mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-04 01:18:34 +00:00
- waveform now has a loading state - audio library now has loading new items state - fix so that the "New" state works on both inference created audio items and uploaded audio items - fix so that uploaded audio items takes the file name as its title Co-authored-by: wil <wil@storyteller.ai>
221 lines
6.3 KiB
TypeScript
221 lines
6.3 KiB
TypeScript
import { useContext, useEffect, useState } from "react";
|
|
import { v4 as uuidv4 } from "uuid";
|
|
import {
|
|
faCirclePlus,
|
|
faFileArrowUp,
|
|
faFileAudio,
|
|
faSpinnerThird,
|
|
} from "@fortawesome/pro-solid-svg-icons";
|
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
|
import { FileUploader } from "react-drag-drop-files";
|
|
|
|
import { TransitionDialogue } from "../TransitionDialogue"
|
|
|
|
import { Button } from "../Button";
|
|
import { H2, P } from "../Typography";
|
|
import { WaveformPlayer } from "../WaveformPlayer";
|
|
|
|
import { AuthenticationContext } from "~/contexts/Authentication";
|
|
import { UploadMedia, UploadMediaResponse } from "./utilities";
|
|
|
|
// import { ListDropdown } from "../ListDropdown";
|
|
// const visiblityOptions = [
|
|
// {
|
|
// name: "private",
|
|
// value: "private",
|
|
// },
|
|
// {
|
|
// name: "public",
|
|
// value: "public",
|
|
// },
|
|
// ];
|
|
const FILE_TYPES = ["MP3", "WAV", "FLAC", "OGG"];
|
|
|
|
type ComponentState = {
|
|
isOpen: boolean;
|
|
file: File | undefined;
|
|
audioUrl: string;
|
|
uploadState: "init" | "staged" | "uploading" | "uploaded" | "error";
|
|
// visibility: string;
|
|
fileToken: string|undefined;
|
|
}
|
|
const initialValues:ComponentState = {
|
|
isOpen: false,
|
|
file: undefined,
|
|
audioUrl: "",
|
|
uploadState: "init",
|
|
// visibility: "private",
|
|
fileToken: undefined,
|
|
}
|
|
|
|
const getFileName = (file:File)=>{
|
|
return file.name.split(".")[0] || "";
|
|
}
|
|
|
|
export const UploadAudioButtonDiagloue = ({
|
|
onUploaded,
|
|
}:{
|
|
onUploaded: (fileToken:string)=>void;
|
|
}) => {
|
|
const { authState } = useContext(AuthenticationContext);
|
|
const [{isOpen, file, audioUrl, uploadState, fileToken}, setState] = useState<ComponentState>(initialValues);
|
|
|
|
const closeModal = () => setState(initialValues);
|
|
const openModal = () => setState((curr)=>({...curr, isOpen:true}));
|
|
// const selectVisibility = (value:string) => {
|
|
// setState((curr)=>({...curr, visibility:value}))
|
|
// };
|
|
const handleFileChange = (file: File) => {
|
|
setState((curr) => ({
|
|
...curr,
|
|
file: file,
|
|
audioUrl: URL.createObjectURL(file),
|
|
uploadState: "staged",
|
|
}));
|
|
};
|
|
const handleClear = ()=>{
|
|
setState({
|
|
...initialValues,
|
|
isOpen: true,
|
|
});
|
|
}
|
|
const submitUpload = ()=>{
|
|
if(file && authState && authState.sessionToken){
|
|
setState((curr)=>({
|
|
...curr,
|
|
uploadState: "uploading"
|
|
}))
|
|
UploadMedia({
|
|
uuid_idempotency_token: uuidv4(),
|
|
file: file,
|
|
source: "file",
|
|
title: getFileName(file),
|
|
}, authState.sessionToken)
|
|
.then((res: UploadMediaResponse) => {
|
|
// console.log(res);
|
|
if ("media_file_token" in res) {
|
|
setState((curr)=>({
|
|
...curr,
|
|
uploadState: "uploaded",
|
|
fileToken: res.media_file_token,
|
|
}));
|
|
}else{
|
|
setState((curr)=>({
|
|
...curr,
|
|
uploadState: "error"
|
|
}));
|
|
}
|
|
});
|
|
}
|
|
};
|
|
useEffect(()=>{
|
|
if(fileToken){
|
|
onUploaded(fileToken);
|
|
}
|
|
},[fileToken])
|
|
return(
|
|
<>
|
|
<Button
|
|
className="grow py-3 text-sm font-medium"
|
|
variant="action"
|
|
icon={faCirclePlus}
|
|
type="button"
|
|
onClick={openModal}
|
|
>
|
|
Upload Audio
|
|
</Button>
|
|
<TransitionDialogue
|
|
isOpen={isOpen}
|
|
onClose={closeModal}
|
|
title={<H2>Upload Audio</H2>}
|
|
>
|
|
<div className="w-full flex flex-col gap-3">
|
|
<FileUploader
|
|
handleChange={handleFileChange}
|
|
name="file"
|
|
types={FILE_TYPES}
|
|
maxSize={50}
|
|
children={<DragAndDropZone file={file}/>}
|
|
/>
|
|
{file && (
|
|
<div className="flex items-center gap-3 rounded-lg bg-brand-secondary p-3">
|
|
<div className="grow">
|
|
<WaveformPlayer audio={audioUrl} hasPlayButton/>
|
|
</div>
|
|
</div>
|
|
)}
|
|
{/* <ListDropdown list={visiblityOptions} onSelect={selectVisibility}/> */}
|
|
<div className="flex justify-end gap-3">
|
|
<Button variant="secondary" onClick={closeModal}>
|
|
{uploadState === "uploaded" ? "Close" : "Cancel"}
|
|
</Button>
|
|
{uploadState !== "uploaded" &&
|
|
<Button
|
|
onClick={submitUpload}
|
|
disabled={uploadState!=="staged"}
|
|
>
|
|
Upload
|
|
{uploadState === "uploading" && (
|
|
<FontAwesomeIcon icon={faSpinnerThird} spin />
|
|
)}
|
|
</Button>
|
|
}
|
|
{uploadState === "uploaded" &&
|
|
<Button onClick={handleClear}>
|
|
Upload Another
|
|
</Button>
|
|
}
|
|
</div>
|
|
</div>
|
|
</TransitionDialogue>
|
|
</>
|
|
);
|
|
}
|
|
|
|
const DragAndDropZone = ({
|
|
file,
|
|
}: {
|
|
file: File | undefined;
|
|
}) => {
|
|
const fileSize =
|
|
file && file.size >= 1024 * 1024
|
|
? (file.size / 1024 / 1024).toFixed(2) + " MB"
|
|
: file
|
|
? `${Math.floor(file.size / 1024)} KB`
|
|
: null;
|
|
|
|
const fileName = file && getFileName(file).toUpperCase();
|
|
|
|
if (!file) {
|
|
return (
|
|
<div className="flex cursor-pointer items-center gap-3.5 rounded-lg border-2 border-dashed border-ui-controls-button/50 bg-brand-secondary p-3">
|
|
<FontAwesomeIcon icon={faFileArrowUp} className="text-4xl" />
|
|
<div className="flex flex-col gap-0">
|
|
<P className="font-medium">
|
|
<u>Upload a file</u> or drop it here
|
|
</P>
|
|
<P className="flex items-center gap-2 text-sm font-normal opacity-50">
|
|
{FILE_TYPES.join(", ").toString()} supported
|
|
</P>
|
|
</div>
|
|
</div>
|
|
);
|
|
} else {
|
|
return (
|
|
<div className="flex cursor-pointer items-center gap-3.5 rounded-lg border-2 border-dashed border-ui-controls-button/50 bg-brand-secondary p-3 justify-between">
|
|
<FontAwesomeIcon icon={faFileAudio} className="text-4xl" />
|
|
<div className="grow flex flex-col gap-0">
|
|
<P className="font-medium">
|
|
{file.name.slice(0, file.name.lastIndexOf("."))}
|
|
</P>
|
|
<P className="flex items-center gap-2 text-sm font-normal">
|
|
<span className="opacity-50">
|
|
{`${fileName} file size: ${fileSize} `}
|
|
</span>
|
|
<u className="transition-all hover:text-white/80">Change File</u>
|
|
</P>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
}; |