From 60eadcc4af027c4b48a38fa9a8aae712579ac490 Mon Sep 17 00:00:00 2001 From: hamid zarghami Date: Sat, 14 Mar 2026 16:11:04 +0330 Subject: [PATCH] connect to uploader --- src/components/UploadBoxDraggble.tsx | 35 ++++++----- .../components/sidebar/ToolInstructions.tsx | 45 +++++++------- .../sidebar/instructions/VideoInput.tsx | 58 ++++++++++--------- 3 files changed, 72 insertions(+), 66 deletions(-) diff --git a/src/components/UploadBoxDraggble.tsx b/src/components/UploadBoxDraggble.tsx index 97afd50..ba2210b 100644 --- a/src/components/UploadBoxDraggble.tsx +++ b/src/components/UploadBoxDraggble.tsx @@ -16,22 +16,26 @@ type Props = { const UploadBoxDraggble: FC = (props: Props) => { - const [files, setFiles] = useState([]) - const [perviews, setPerviews] = useState(props.preview ? props.preview : []) - const [isFill, setIsFill] = useState(false) - const [cover, setCover] = useState(props.coverUrl ? props.coverUrl : '') + const [files, setFiles] = useState([]); + const [perviews, setPerviews] = useState(props.preview ?? []); + const [cover, setCover] = useState(props.coverUrl ?? ""); const onDrop = useCallback((acceptedFiles: File[]) => { + // وقتی parent با preview و onChangePreview مدیریت می‌کند، فقط onChange بزن تا فقط یک ردیف (perviews) نمایش داده شود + if (props.preview !== undefined && props.onChangePreview) { + props.onChange(acceptedFiles); + return; + } if (props.isMultiple) { - const array = [...files, ...acceptedFiles] - setFiles(array) - props.onChange(array) + const array = [...files, ...acceptedFiles]; + setFiles(array); + props.onChange(array); } else { - setFiles([acceptedFiles[0]]) - props.onChange([acceptedFiles[0]]) + setFiles([acceptedFiles[0]]); + props.onChange([acceptedFiles[0]]); } // eslint-disable-next-line react-hooks/exhaustive-deps - }, [files]) + }, [files]); const { getRootProps, getInputProps } = useDropzone({ onDrop }) const handleDelete = (index: number) => { @@ -51,15 +55,10 @@ const UploadBoxDraggble: FC = (props: Props) => { } useEffect(() => { - - if (props.preview && props.preview.length > 0 && !isFill) { - setPerviews(props.preview) - console.log('preview', props.preview); - - setIsFill(true) + if (props.preview) { + setPerviews(props.preview); } - - }, [props.preview, isFill]) + }, [props.preview]); useEffect(() => { setCover(props.coverUrl ? props.coverUrl : '') diff --git a/src/pages/editor/components/sidebar/ToolInstructions.tsx b/src/pages/editor/components/sidebar/ToolInstructions.tsx index 0b4939b..3c91d01 100644 --- a/src/pages/editor/components/sidebar/ToolInstructions.tsx +++ b/src/pages/editor/components/sidebar/ToolInstructions.tsx @@ -1,4 +1,5 @@ import { useEditorStore, type ToolType } from "@/pages/editor/store/editorStore"; +import { useSingleUpload } from "@/pages/uploader/hooks/useUploaderData"; import { ImageUpload, VideoInput, @@ -18,31 +19,33 @@ type ToolInstructionsProps = { const ToolInstructions = ({ tool }: ToolInstructionsProps) => { const { addObject, setSelectedObjectId, setTool } = useEditorStore(); + const { mutateAsync: uploadFile } = useSingleUpload(); - const handleImageUpload = (e: React.ChangeEvent) => { + const handleImageUpload = async (e: React.ChangeEvent) => { const file = e.target.files?.[0]; - if (file) { - const reader = new FileReader(); - reader.onload = (event) => { - const imageUrl = event.target?.result as string; - const img = new Image(); - img.onload = () => { - const newImage = { - id: `image-${Date.now()}`, - type: "image" as ToolType, - x: 100, - y: 100, - width: img.width, - height: img.height, - imageUrl, - }; - addObject(newImage); - setSelectedObjectId(newImage.id); - setTool("select"); + if (!file) return; + try { + const result = await uploadFile(file); + const imageUrl = result?.data?.url; + if (!imageUrl) return; + const img = new Image(); + img.onload = () => { + const newImage = { + id: `image-${Date.now()}`, + type: "image" as ToolType, + x: 100, + y: 100, + width: img.width, + height: img.height, + imageUrl, }; - img.src = imageUrl; + addObject(newImage); + setSelectedObjectId(newImage.id); + setTool("select"); }; - reader.readAsDataURL(file); + img.src = imageUrl; + } catch { + // TODO: show error toast } }; diff --git a/src/pages/editor/components/sidebar/instructions/VideoInput.tsx b/src/pages/editor/components/sidebar/instructions/VideoInput.tsx index 66b63e8..0869411 100644 --- a/src/pages/editor/components/sidebar/instructions/VideoInput.tsx +++ b/src/pages/editor/components/sidebar/instructions/VideoInput.tsx @@ -1,34 +1,42 @@ import { type FC, useCallback, useMemo } from "react"; import { useEditorStore, type ToolType } from "@/pages/editor/store/editorStore"; +import { useSingleUpload } from "@/pages/uploader/hooks/useUploaderData"; import { CloseCircle } from "iconsax-react"; import { useDropzone } from "react-dropzone"; import VideoUploadZone from "@/components/VideoUploadZone"; const VideoInput: FC = () => { - const { objects, addObject, setSelectedObjectId, setTool, deleteObject } = useEditorStore(); + const { objects, addObject, setSelectedObjectId, setTool, deleteObject } = + useEditorStore(); + const { mutateAsync: uploadFile } = useSingleUpload(); - const onDrop = useCallback((acceptedFiles: File[]) => { - acceptedFiles.forEach((file) => { - const videoUrl = URL.createObjectURL(file); - const videoId = `video-${Date.now()}-${Math.random()}`; - - - - const newVideo = { - id: videoId, - type: "video" as ToolType, - x: 100, - y: 100, - width: 400, - height: 300, - videoUrl, - }; - - addObject(newVideo); - setSelectedObjectId(newVideo.id); - setTool("select"); - }); - }, [addObject, setSelectedObjectId, setTool]); + const onDrop = useCallback( + async (acceptedFiles: File[]) => { + for (const file of acceptedFiles) { + try { + const result = await uploadFile(file); + const videoUrl = result?.data?.url; + if (!videoUrl) continue; + const videoId = `video-${Date.now()}-${Math.random()}`; + const newVideo = { + id: videoId, + type: "video" as ToolType, + x: 100, + y: 100, + width: 400, + height: 300, + videoUrl, + }; + addObject(newVideo); + setSelectedObjectId(newVideo.id); + setTool("select"); + } catch { + // TODO: show error toast + } + } + }, + [addObject, setSelectedObjectId, setTool, uploadFile] + ); const { getRootProps, getInputProps } = useDropzone({ onDrop, @@ -43,10 +51,6 @@ const VideoInput: FC = () => { }, [objects]); const handleDeleteVideo = (videoId: string) => { - const videoObject = videoObjects.find((v) => v.id === videoId); - if (videoObject?.videoUrl) { - URL.revokeObjectURL(videoObject.videoUrl); - } deleteObject(videoId); };