fix: state and rendering

This commit is contained in:
Juan Di Toro 2024-03-12 15:32:00 +01:00
parent b0809c65f3
commit 94406b7f13
2 changed files with 125 additions and 100 deletions

View File

@ -54,7 +54,17 @@ export const DashboardLayout = ({ children }: React.PropsWithChildren<{}>) => {
<p>Privacy</p> <p>Privacy</p>
<p>Ownership</p> <p>Ownership</p>
</span> </span>
<UploadFileModal /> <Dialog>
<DialogTrigger asChild>
<Button size={"lg"} className="w-[calc(100%-3rem)] font-semibold">
<CloudUploadIcon className="w-6 h-6 -ml-3 mr-4" />
Upload Files
</Button>
</DialogTrigger>
<DialogContent>
<UploadFileForm />
</DialogContent>
</Dialog>
</header> </header>
{children} {children}
@ -89,97 +99,92 @@ export const DashboardLayout = ({ children }: React.PropsWithChildren<{}>) => {
) )
} }
const UploadFileModal = () => { const UploadFileForm = () => {
const { getRootProps, getInputProps, files, upload, removeFile, cancelAll } = const {
useUppy({ getRootProps,
uploader: "tus", getInputProps,
endpoint: import.meta.env.VITE_PUBLIC_TUS_ENDPOINT getFiles,
}) upload,
state,
removeFile,
cancelAll
} = useUppy({
uploader: "tus",
endpoint: import.meta.env.VITE_PUBLIC_TUS_ENDPOINT
})
const isUploading = console.log({ state, files: getFiles() })
files.length > 0
? files.map((file) => file.progress?.uploadStarted != null).includes(true) const isUploading = state === "uploading"
: false const isCompleted = state === "completed"
const isCompleted = const hasStarted = state !== "idle" && state !== "initializing"
files.length > 0
? files
.map((file) => file.progress?.uploadComplete)
.reduce((acc, cur) => acc && cur, true)
: false
const hasStarted = isUploading || isCompleted
return ( return (
<Dialog> <>
<DialogTrigger asChild> <DialogHeader className="mb-6">
<Button size={"lg"} className="w-[calc(100%-3rem)] font-semibold"> <DialogTitle>Upload Files</DialogTitle>
<CloudUploadIcon className="w-6 h-6 -ml-3 mr-4" /> </DialogHeader>
Upload Files {!hasStarted ? (
</Button> <div
</DialogTrigger> {...getRootProps()}
<DialogContent> className="border border-border rounded text-primary-2 bg-primary-dark h-48 flex flex-col items-center justify-center"
<DialogHeader className="mb-6"> >
<DialogTitle>Upload Files</DialogTitle> <input
</DialogHeader> hidden
{!hasStarted ? ( aria-hidden
<div name="uppyFiles[]"
{...getRootProps()} key={new Date().toISOString()}
className="border border-border rounded text-primary-2 bg-primary-dark h-48 flex flex-col items-center justify-center" multiple
> {...getInputProps()}
<input />
hidden <CloudUploadIcon className="w-24 h-24 stroke stroke-primary-dark" />
aria-hidden <p>Drag & Drop Files or Browse</p>
name="uppyFiles[]"
key={new Date().toISOString()}
multiple
{...getInputProps()}
/>
<CloudUploadIcon className="w-24 h-24 stroke stroke-primary-dark" />
<p>Drag & Drop Files or Browse</p>
</div>
) : null}
<div className="w-full space-y-3 max-h-48 overflow-y-auto">
{files.map((file) => (
<UploadFileItem
key={file.id}
file={file}
onRemove={(id) => {
removeFile(id)
}}
/>
))}
</div> </div>
) : null}
{hasStarted ? ( <div className="w-full space-y-3 max-h-48 overflow-y-auto">
<div className="flex flex-col items-center gap-y-2 w-full text-primary-1"> {getFiles().map((file) => (
<CloudCheckIcon className="w-32 h-32" /> <UploadFileItem
{isCompleted key={file.id}
? "Upload completed" file={file}
: `${files.length} being uploaded`} onRemove={(id) => {
</div> removeFile(id)
) : null} }}
/>
))}
</div>
{hasStarted ? ( {hasStarted ? (
<DialogClose asChild onClick={cancelAll}> <div className="flex flex-col items-center gap-y-2 w-full text-primary-1">
<Button size={"lg"} className="mt-6"> <CloudCheckIcon className="w-32 h-32" />
Cancel {isCompleted
</Button> ? "Upload completed"
</DialogClose> : `${getFiles().length} files being uploaded`}
) : ( </div>
<Button size={"lg"} className="mt-6" onClick={upload}> ) : null}
Upload
{isUploading ? (
<DialogClose asChild onClick={cancelAll}>
<Button size={"lg"} className="mt-6">
Cancel
</Button> </Button>
)} </DialogClose>
) : null}
{hasStarted && isCompleted ? ( {isCompleted ? (
<DialogClose asChild> <DialogClose asChild>
<Button size={"lg"} className="mt-6"> <Button size={"lg"} className="mt-6">
Close Close
</Button> </Button>
</DialogClose> </DialogClose>
) : null} ) : null}
</DialogContent>
</Dialog> {!hasStarted && !isCompleted && !isUploading ? (
<Button size={"lg"} className="mt-6" onClick={upload}>
Upload
</Button>
) : null}
</>
) )
} }

View File

@ -36,7 +36,10 @@ export function useUppy({
(element: HTMLElement | null) => _setTargetRef(element), (element: HTMLElement | null) => _setTargetRef(element),
[] []
) )
const [state, setState] = useState<State>() const [uppyState, setUppyState] = useState<State>()
const [state, setState] = useState<
"completed" | "idle" | "initializing" | "error" | "uploading"
>("initializing")
const [inputProps, setInputProps] = useState< const [inputProps, setInputProps] = useState<
| { | {
@ -71,7 +74,7 @@ export function useUppy({
[targetRef, uppyInstance] [targetRef, uppyInstance]
) )
const cancelAll = useCallback( const cancelAll = useCallback(
() => uppyInstance.current?.cancelAll(), () => uppyInstance.current?.cancelAll({ reason: "user" }),
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
[targetRef, uppyInstance] [targetRef, uppyInstance]
) )
@ -116,36 +119,53 @@ export function useUppy({
uppy.on("complete", (result) => { uppy.on("complete", (result) => {
if (result.failed.length === 0) { if (result.failed.length === 0) {
console.log("Upload successful üòÄ") console.log("Upload successful üòÄ")
setState("completed")
} else { } else {
console.warn("Upload failed üòû") console.warn("Upload failed üòû")
setState("error")
} }
console.log("successful files:", result.successful) console.log("successful files:", result.successful)
console.log("failed files:", result.failed) console.log("failed files:", result.failed)
}) })
const setStateCb = () => { const setStateCb = (event: (typeof LISTENING_EVENTS)[number]) => {
setState(uppy.getState()) switch (event) {
case "upload":
setState("uploading")
break
case "upload-error":
setState("error")
break
default:
break
}
setUppyState(uppy.getState())
} }
for (const event of LISTENING_EVENTS) { for (const event of LISTENING_EVENTS) {
uppy.on(event, setStateCb) uppy.on(event, function cb() {
setStateCb(event)
})
} }
setState("idle")
return () => { return () => {
for (const event of ["complete", ...LISTENING_EVENTS]) { // for (const event of ["complete", ...LISTENING_EVENTS]) {
uppyInstance.current?.off( // uppyInstance.current?.off(
event as "complete" & keyof typeof LISTENING_EVENTS, // event as "complete" & keyof typeof LISTENING_EVENTS,
//@ts-expect-error -- huh? typescript wtf // //@ts-expect-error -- huh? typescript wtf
setStateCb // setStateCb
) // )
} // }
uppyInstance.current?.close() // uppyInstance.current?.cancelAll({ reason: "unmount" })
uppyInstance.current = undefined // uppyInstance.current?.logout()
// uppyInstance.current?.close()
// uppyInstance.current = undefined
} }
}, [targetRef, endpoint, uploader]) }, [targetRef, endpoint, uploader])
return { return {
files: uppyInstance.current?.getFiles() ?? [], getFiles: () => uppyInstance.current?.getFiles() ?? [],
error: uppyInstance.current?.getState, error: uppyInstance.current?.getState,
state, state,
upload: () => upload: () =>
@ -154,6 +174,6 @@ export function useUppy({
getInputProps: () => inputProps, getInputProps: () => inputProps,
getRootProps, getRootProps,
removeFile, removeFile,
cancelAll, cancelAll
} }
} }