Files
dpage-editor/src/pages/editor/components/sidebar/instructions/AudioInput.tsx
T
hamid zarghami 22d15f9a13
deploy to danak / build_and_deploy (push) Has been cancelled
progressbar uploading
2026-07-01 16:27:21 +03:30

128 lines
5.1 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { type FC, useCallback, useMemo, useState } from "react";
import { useEditorStore, type ToolType } from "@/pages/editor/store/editorStore";
import { useSingleUpload } from "@/pages/uploader/hooks/useUploaderData";
import { CloseCircle, Music } from "iconsax-react";
import { useDropzone } from "react-dropzone";
import AudioUploadZone from "@/components/AudioUploadZone";
import Input from "@/components/Input";
const getAudioNameFromFile = (file: File) =>
file.name.replace(/\.[^/.]+$/, "");
export const AUDIO_ACCEPT = {
"audio/*": [".mp3", ".wav", ".ogg", ".m4a", ".aac", ".flac", ".webm"],
} as const;
const AudioInput: FC = () => {
const { objects, addObject, setSelectedObjectId, setTool, deleteObject, updateObject } =
useEditorStore();
const { mutateAsync: uploadFile } = useSingleUpload();
const [isUploading, setIsUploading] = useState(false);
const [audioName, setAudioName] = useState("");
const onDrop = useCallback(
async (acceptedFiles: File[]) => {
if (acceptedFiles.length === 0) return;
setIsUploading(true);
try {
for (const file of acceptedFiles) {
try {
const result = await uploadFile({ file });
const audioUrl = result?.data?.url;
if (!audioUrl) continue;
const audioId = `audio-${Date.now()}-${Math.random()}`;
const newAudio = {
id: audioId,
type: "audio" as ToolType,
x: 100,
y: 100,
width: 320,
height: 56,
audioUrl,
audioName: audioName.trim() || getAudioNameFromFile(file),
};
addObject(newAudio);
setSelectedObjectId(newAudio.id);
setTool("select");
} catch {
// TODO: show error toast
}
}
setAudioName("");
} finally {
setIsUploading(false);
}
},
[addObject, audioName, setSelectedObjectId, setTool, uploadFile]
);
const { getRootProps, getInputProps } = useDropzone({
onDrop,
accept: AUDIO_ACCEPT,
multiple: true,
disabled: isUploading,
});
const audioObjects = useMemo(() => {
return objects.filter((obj) => obj.type === "audio");
}, [objects]);
const handleDeleteAudio = (audioId: string) => {
deleteObject(audioId);
};
return (
<div className="space-y-4">
<div className="text-base font-bold">صدا</div>
<Input
label="نام فایل صوتی"
value={audioName}
onChange={(e) => setAudioName(e.target.value)}
placeholder="مثلاً موسیقی پس‌زمینه"
/>
<AudioUploadZone
getRootProps={getRootProps}
getInputProps={getInputProps}
isLoading={isUploading}
/>
{audioObjects.length > 0 && (
<div className="space-y-2">
<div className="text-xs font-bold">فایلهای صوتی آپلود شده</div>
<div className="flex flex-col gap-2">
{audioObjects.map((audioObject) => (
<div
key={audioObject.id}
className="relative flex items-center gap-2 rounded-lg border border-border bg-gray-50 px-3 py-2"
>
<Music size={20} color="#8C90A3" variant="Bold" />
<input
className="flex-1 h-7 rounded-lg border border-border bg-white px-2 text-xs text-black outline-none"
value={audioObject.audioName || ""}
onChange={(e) =>
updateObject(audioObject.id, {
audioName: e.target.value,
})
}
placeholder="نام فایل صوتی"
/>
<button
onClick={() => handleDeleteAudio(audioObject.id)}
className="absolute -right-1 -top-2 shadow-md bg-white size-5 rounded-full flex justify-center items-center hover:bg-gray-100 transition-colors"
>
<CloseCircle size={16} color="red" />
</button>
</div>
))}
</div>
</div>
)}
</div>
);
};
export default AudioInput;