This commit is contained in:
hosseintaromi 2025-12-19 23:54:34 +03:30
parent 30f1e4768a
commit 2fe019ec66
3 changed files with 108 additions and 108 deletions

View File

@ -67,7 +67,6 @@ export const API_ROUTES = {
// Files APIs
GET_FILES: "files",
UPLOAD_FILE: "files",
UPLOAD_USER_FILE: "api/v1/users/files",
GET_FILE: (id: string) => `files/${id}`,
UPDATE_FILE: (id: string) => `files/${id}`,
DELETE_FILE: (id: string) => `files/${id}`,

View File

@ -21,13 +21,20 @@ interface UploadResponse {
export const useFileUpload = () => {
return useMutation({
mutationFn: async (file: File): Promise<{ id: string; url: string; mimeType?: string }> => {
const contentType =
file.type && file.type.startsWith("video") ? "video/mp4" : "image/png";
const formData = new FormData();
formData.append("file", file);
formData.append("name", "uploaded-file");
console.log("Uploading file:", file.name);
const response = await httpPostRequest<UploadResponse>(
APIUrlGenerator(API_ROUTES.UPLOAD_USER_FILE, undefined, undefined, false),
file,
{ headers: { "Content-Type": contentType, Accept: "application/json" } }
APIUrlGenerator(API_ROUTES.UPLOAD_FILE),
formData,
{
headers: {
"Content-Type": "multipart/form-data",
},
}
);
console.log("Upload response:", response);

View File

@ -40,122 +40,116 @@ const productSchema = yup.object({
});
const toPublicUrl = (img: any): ProductImage => {
const rawUrl: string = img?.url || img?.file_url || img?.fileUrl || '';
const serveKey: string | undefined = img?.serve_key || img?.serveKey;
const url = serveKey
? `${API_GATE_WAY}/${API_ROUTES.DOWNLOAD_FILE(serveKey)}`
: rawUrl?.startsWith('http')
? rawUrl
: rawUrl
? `${API_GATE_WAY}${rawUrl.startsWith('/') ? '' : '/'}${rawUrl}`
: '';
return {
id: (img?.id ?? img?.file_id ?? img?.FileID ?? img).toString(),
url,
alt: img?.alt || img?.original_name || '',
order: img?.order ?? 0,
type: img?.mime_type || img?.type || img?.file_type,
mime_type: img?.mime_type || img?.file_type,
size: img?.size,
};
const rawUrl: string = img?.url || img?.file_url || img?.fileUrl || '';
const serveKey: string | undefined = img?.serve_key || img?.serveKey;
const url = serveKey
? `${API_GATE_WAY}/${API_ROUTES.DOWNLOAD_FILE(serveKey)}`
: rawUrl?.startsWith('http')
? rawUrl
: rawUrl
? `${API_GATE_WAY}${rawUrl.startsWith('/') ? '' : '/'}${rawUrl}`
: '';
return {
id: (img?.id ?? img?.file_id ?? img?.FileID ?? img).toString(),
url,
alt: img?.alt || img?.original_name || '',
order: img?.order ?? 0,
type: img?.mime_type || img?.type || img?.file_type,
mime_type: img?.mime_type || img?.file_type,
size: img?.size,
};
};
const IMAGE_MAX_SIZE = 2 * 1024 * 1024;
const VIDEO_MAX_SIZE = 50 * 1024 * 1024;
const VIDEO_MAX_SIZE = 25 * 1024 * 1024;
const isImageFile = (file: File) => file.type?.startsWith('image/');
const isVideoFile = (file: File) => file.type?.startsWith('video/');
const ensureSquareImage = (file: File) =>
new Promise<void>((resolve, reject) => {
const url = URL.createObjectURL(file);
const img = new Image();
img.onload = () => {
URL.revokeObjectURL(url);
if (img.width === img.height) {
resolve();
} else {
reject(new Error('ابعاد تصویر Explorer باید ۱ در ۱ باشد'));
}
};
img.onerror = () => {
URL.revokeObjectURL(url);
reject(new Error('امکان بررسی ابعاد تصویر وجود ندارد'));
};
img.src = url;
});
new Promise<void>((resolve, reject) => {
const url = URL.createObjectURL(file);
const img = new Image();
img.onload = () => {
URL.revokeObjectURL(url);
if (img.width === img.height) {
resolve();
} else {
reject(new Error('ابعاد تصویر Explorer باید ۱ در ۱ باشد'));
}
};
img.onerror = () => {
URL.revokeObjectURL(url);
reject(new Error('امکان بررسی ابعاد تصویر وجود ندارد'));
};
img.src = url;
});
const validateMediaFile = async (file: File, options?: { requireSquare?: boolean }) => {
if (isImageFile(file)) {
if (file.size > IMAGE_MAX_SIZE) {
throw new Error('حجم تصویر نباید بیشتر از ۲ مگابایت باشد');
}
if (options?.requireSquare) {
await ensureSquareImage(file);
}
} else if (isVideoFile(file)) {
if (file.size > VIDEO_MAX_SIZE) {
throw new Error('حجم ویدیو نباید بیشتر از ۲۵ مگابایت باشد');
}
} else {
throw new Error('فقط تصاویر یا ویدیو مجاز است');
if (isImageFile(file)) {
if (file.size > IMAGE_MAX_SIZE) {
throw new Error('حجم تصویر نباید بیشتر از ۲ مگابایت باشد');
}
if (options?.requireSquare) {
await ensureSquareImage(file);
}
} else if (isVideoFile(file)) {
if (file.size > VIDEO_MAX_SIZE) {
throw new Error('حجم ویدیو نباید بیشتر از ۲۵ مگابایت باشد');
}
} else {
throw new Error('فقط تصاویر یا ویدیو مجاز است');
}
};
const validateExplorerFile = async (file: File) => {
if (isImageFile(file)) {
if (file.size > IMAGE_MAX_SIZE) {
throw new Error('حجم تصویر نباید بیشتر از ۲ مگابایت باشد');
}
await ensureSquareImage(file);
return;
}
if (isVideoFile(file)) {
if (file.size > VIDEO_MAX_SIZE) {
throw new Error('حجم ویدیو نباید بیشتر از ۵۰ مگابایت باشد');
}
return;
}
throw new Error('فقط تصاویر یا ویدیو مجاز است');
if (isImageFile(file)) {
await ensureSquareImage(file);
return;
}
if (isVideoFile(file)) {
return;
}
throw new Error('فقط تصاویر یا ویدیو مجاز است');
};
const mapExplorerFiles = (entries: any[]): ProductImage[] => {
if (!entries || !Array.isArray(entries)) {
return [];
if (!entries || !Array.isArray(entries)) {
return [];
}
return entries.map((entry, index) => {
if (entry?.file) {
const media = toPublicUrl(entry.file);
return { ...media, order: index };
}
return entries.map((entry, index) => {
if (entry?.file) {
const media = toPublicUrl(entry.file);
return { ...media, order: index };
}
if (entry?.file_id) {
const normalized = toPublicUrl({
...entry,
id: entry.file_id,
url: entry.file_url || entry.url,
file_url: entry.file_url || entry.url,
mime_type: entry.mime_type || entry.file_type,
type: entry.file_type || entry.type,
original_name: entry.name || entry.original_name,
});
return { ...normalized, order: index };
}
if (entry?.FileID) {
const normalized = toPublicUrl({
...entry,
id: entry.FileID,
url: entry.file_url || entry.url,
file_url: entry.file_url || entry.url,
});
return { ...normalized, order: index };
}
if (typeof entry === 'number' || typeof entry === 'string') {
const normalized = toPublicUrl(entry);
return { ...normalized, order: index };
}
const normalized = toPublicUrl(entry);
return { ...normalized, order: index };
});
if (entry?.file_id) {
const normalized = toPublicUrl({
...entry,
id: entry.file_id,
url: entry.file_url || entry.url,
file_url: entry.file_url || entry.url,
mime_type: entry.mime_type || entry.file_type,
type: entry.file_type || entry.type,
original_name: entry.name || entry.original_name,
});
return { ...normalized, order: index };
}
if (entry?.FileID) {
const normalized = toPublicUrl({
...entry,
id: entry.FileID,
url: entry.file_url || entry.url,
file_url: entry.file_url || entry.url,
});
return { ...normalized, order: index };
}
if (typeof entry === 'number' || typeof entry === 'string') {
const normalized = toPublicUrl(entry);
return { ...normalized, order: index };
}
const normalized = toPublicUrl(entry);
return { ...normalized, order: index };
});
};
const ProductFormPage = () => {
@ -612,11 +606,11 @@ const ProductFormPage = () => {
onUpload={handleFileUpload}
onRemove={handleFileRemove}
acceptedTypes={['image/*', 'video/*']}
maxFileSize={50 * 1024 * 1024}
maxFileSize={25 * 1024 * 1024}
maxFiles={10}
mode="multi"
label=""
description="تصاویر یا ویدیوهای محصول را آپلود کنید (حداکثر ۲ مگ برای تصویر و ۵۰ مگ برای ویدیو)"
description="تصاویر یا ویدیوهای محصول را آپلود کنید (حداکثر ۲ مگ برای تصویر و ۲۵ مگ برای ویدیو)"
onUploadStart={() => setIsUploading(true)}
onUploadComplete={() => setIsUploading(false)}
/>
@ -673,11 +667,11 @@ const ProductFormPage = () => {
onUpload={handleExplorerUpload}
onRemove={handleExplorerRemove}
acceptedTypes={['image/*', 'video/*']}
maxFileSize={50 * 1024 * 1024}
maxFileSize={0}
maxFiles={5}
mode="multi"
label=""
description="فایل‌های Explorer را آپلود کنید (تصویر: ۲ مگ، ویدیو: ۵۰ مگ، تصاویر باید مربعی باشند)"
description="فایل‌های Explorer را آپلود کنید (تصاویر باید مربعی باشند)"
onUploadStart={() => setIsExplorerUploading(true)}
onUploadComplete={() => setIsExplorerUploading(false)}
/>