diff --git a/src/components/Componentes/question-photo.test.tsx b/src/components/Componentes/question-photo.test.tsx index bdc8c96..1be4f97 100644 --- a/src/components/Componentes/question-photo.test.tsx +++ b/src/components/Componentes/question-photo.test.tsx @@ -73,7 +73,7 @@ const mockPhotoQuestion: QuestionField = { tooltip: "", extras: { options: [".jpg", ".jpeg", ".png"], - }, + } as any, options: [], }; diff --git a/src/components/Componentes/question-photo.tsx b/src/components/Componentes/question-photo.tsx index 8292006..ec5d301 100644 --- a/src/components/Componentes/question-photo.tsx +++ b/src/components/Componentes/question-photo.tsx @@ -21,8 +21,9 @@ function base64ToFile(dataUrl: string, filename = "photo.jpg"): File { const parts = dataUrl.split(","); const mimeMatch = parts[0]?.match(/:(.*?);/); const mime = mimeMatch ? mimeMatch[1] : "image/jpeg"; - const base64Data = parts[1] || parts[0]; - const binaryString = atob(base64Data); + const rawBase64 = parts[1] || parts[0]; + const cleanBase64 = rawBase64.replace(/\s+/g, ""); + const binaryString = atob(cleanBase64); const len = binaryString.length; const bytes = new Uint8Array(len); for (let i = 0; i < len; i++) { @@ -201,14 +202,18 @@ export function QuestionPhoto({ }) .catch((err) => { console.error("Flutter photo upload to server error:", err); - handleUploadFailure(); + const reason = + err?.response?.data?.reason || + err?.response?.data?.detail || + err?.message; + handleUploadFailure(reason); pendingDeferredRef.current?.reject(err); pendingDeferredRef.current = null; }); registerPendingUpload?.(question.id, uploadPromise); - } catch (convErr) { + } catch (convErr: any) { console.error("Failed to decode base64 photo:", convErr); - handleUploadFailure(); + handleUploadFailure(convErr?.message); pendingDeferredRef.current?.reject(convErr); pendingDeferredRef.current = null; } @@ -279,12 +284,18 @@ export function QuestionPhoto({ question.ui_config?.source || "gallery"; + const uploadUrl = + typeof window !== "undefined" + ? `${window.location.origin}/api/proxy?__proxyPath=/upload-tmp-media/` + : undefined; + uploadFile({ requestId: String(question.id), mediaType: "image", source: pickerSource as any, picker_type: pickerType as any, - returnAs: "base64", + returnAs: "upload", + uploadUrl, fieldName: "file", allowedExtensions: extensions.length > 0 ? extensions : ["jpg", "jpeg", "png", "webp"], diff --git a/src/hooks/marriage/use-upload-tmp-media.ts b/src/hooks/marriage/use-upload-tmp-media.ts index 880953c..9725ae5 100644 --- a/src/hooks/marriage/use-upload-tmp-media.ts +++ b/src/hooks/marriage/use-upload-tmp-media.ts @@ -5,25 +5,32 @@ import { http } from "@/lib/http"; import type { MutationOptions } from "./options"; import type { UploadTmpMediaResponse } from "./types"; -const CSRF_TOKEN = - "53kqNKySTv3q4K3OolQqLEgaeF9pdPdAEnxrMARaUfvFrIGK57Qje67ifYUDMUQP"; +import { getClientCookie } from "@/lib/cookies"; export async function uploadTmpMedia( - file: File, + file: File | Blob, onProgress?: (progressPercent: number) => void, ) { const formData = new FormData(); - formData.append("file", file); + const filename = (file as File).name || "upload.jpg"; + formData.append("file", file, filename); + + const csrfToken = + getClientCookie("csrftoken") || getClientCookie("XSRF-TOKEN"); + const headers: Record = { + Accept: "application/json", + // Let browser/Axios automatically set multipart/form-data boundary + "Content-Type": undefined, + }; + if (csrfToken) { + headers["X-CSRFToken"] = csrfToken; + } const { data } = await http.post( "/upload-tmp-media/", formData, { - headers: { - Accept: "application/json", - "Content-Type": "multipart/form-data", - "X-CSRFToken": CSRF_TOKEN, - }, + headers: headers as any, onUploadProgress: (progressEvent) => { if (progressEvent.total && onProgress) { const percent = Math.round(