new features

This commit is contained in:
Daniil
2026-02-27 23:34:17 +03:00
parent 42ce5fa0fe
commit 71b974903a
191 changed files with 11300 additions and 373 deletions
+89
View File
@@ -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 (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)
})
}