90 lines
2.5 KiB
TypeScript
90 lines
2.5 KiB
TypeScript
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 (0–100)
|
||
* @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)
|
||
})
|
||
}
|