Files
main_frontend/src/shared/api/uploadFile.ts
T
2026-02-27 23:34:17 +03:00

90 lines
2.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import type { components } from "./__generated__/openapi.types"
import { fetchClient } from "."
import { ACCESS_TOKEN_REGEXP, API_URL } from "@shared/lib/constants"
type FileInfoResponse = components["schemas"]["FileInfoResponse"]
type ProgressCallback = (percent: number) => void
/**
* Upload a file to the storage API.
* Handles FormData construction and Content-Type header override
* required for multipart uploads via openapi-fetch.
*
* @param file - File object to upload
* @param folder - Target folder in storage (default: "")
* @returns FileInfoResponse with file_path and file_url
*/
export async function uploadFile(
file: File,
folder = "",
): Promise<FileInfoResponse> {
const formData = new FormData()
formData.append("file", file)
formData.append("folder", folder)
const { data, error } = await fetchClient.POST("/api/files/upload/", {
body: formData as unknown as { file: string; folder: string },
bodySerializer: () => formData as unknown as string,
headers: { "Content-Type": null },
})
if (error || !data) {
throw new Error("File upload failed")
}
return data
}
/**
* Upload a file with real-time progress tracking.
* Uses XMLHttpRequest for access to upload progress events.
*
* @param file - File object to upload
* @param folder - Target folder in storage (default: "")
* @param onProgress - Callback receiving upload percentage (0100)
* @returns FileInfoResponse with file_path and file_url
*/
export function uploadFileWithProgress(
file: File,
folder = "",
onProgress?: ProgressCallback,
): Promise<FileInfoResponse> {
return new Promise((resolve, reject) => {
const formData = new FormData()
formData.append("file", file)
formData.append("folder", folder)
const xhr = new XMLHttpRequest()
xhr.open("POST", `${API_URL}/api/files/upload/`)
const token = document.cookie.replace(ACCESS_TOKEN_REGEXP, "$1")
if (token.length) {
xhr.setRequestHeader("Authorization", `Bearer ${token}`)
}
xhr.upload.onprogress = (e) => {
if (e.lengthComputable && onProgress) {
onProgress(Math.round((e.loaded / e.total) * 100))
}
}
xhr.onload = () => {
if (xhr.status >= 200 && xhr.status < 300) {
try {
resolve(JSON.parse(xhr.responseText) as FileInfoResponse)
} catch {
reject(new Error("Не удалось разобрать ответ сервера"))
}
} else {
reject(new Error("Ошибка загрузки файла"))
}
}
xhr.onerror = () => reject(new Error("Ошибка сети при загрузке"))
xhr.send(formData)
})
}