new features
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
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)
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user