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>Ownership</p>
</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>
{children}
@ -89,97 +99,92 @@ export const DashboardLayout = ({ children }: React.PropsWithChildren<{}>) => {
)
}
const UploadFileModal = () => {
const { getRootProps, getInputProps, files, upload, removeFile, cancelAll } =
useUppy({
uploader: "tus",
endpoint: import.meta.env.VITE_PUBLIC_TUS_ENDPOINT
})
const UploadFileForm = () => {
const {
getRootProps,
getInputProps,
getFiles,
upload,
state,
removeFile,
cancelAll
} = useUppy({
uploader: "tus",
endpoint: import.meta.env.VITE_PUBLIC_TUS_ENDPOINT
})
const isUploading =
files.length > 0
? files.map((file) => file.progress?.uploadStarted != null).includes(true)
: false
const isCompleted =
files.length > 0
? files
.map((file) => file.progress?.uploadComplete)
.reduce((acc, cur) => acc && cur, true)
: false
const hasStarted = isUploading || isCompleted
console.log({ state, files: getFiles() })
const isUploading = state === "uploading"
const isCompleted = state === "completed"
const hasStarted = state !== "idle" && state !== "initializing"
return (
<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>
<DialogHeader className="mb-6">
<DialogTitle>Upload Files</DialogTitle>
</DialogHeader>
{!hasStarted ? (
<div
{...getRootProps()}
className="border border-border rounded text-primary-2 bg-primary-dark h-48 flex flex-col items-center justify-center"
>
<input
hidden
aria-hidden
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)
}}
/>
))}
<>
<DialogHeader className="mb-6">
<DialogTitle>Upload Files</DialogTitle>
</DialogHeader>
{!hasStarted ? (
<div
{...getRootProps()}
className="border border-border rounded text-primary-2 bg-primary-dark h-48 flex flex-col items-center justify-center"
>
<input
hidden
aria-hidden
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}
{hasStarted ? (
<div className="flex flex-col items-center gap-y-2 w-full text-primary-1">
<CloudCheckIcon className="w-32 h-32" />
{isCompleted
? "Upload completed"
: `${files.length} being uploaded`}
</div>
) : null}
<div className="w-full space-y-3 max-h-48 overflow-y-auto">
{getFiles().map((file) => (
<UploadFileItem
key={file.id}
file={file}
onRemove={(id) => {
removeFile(id)
}}
/>
))}
</div>
{hasStarted ? (
<DialogClose asChild onClick={cancelAll}>
<Button size={"lg"} className="mt-6">
Cancel
</Button>
</DialogClose>
) : (
<Button size={"lg"} className="mt-6" onClick={upload}>
Upload
{hasStarted ? (
<div className="flex flex-col items-center gap-y-2 w-full text-primary-1">
<CloudCheckIcon className="w-32 h-32" />
{isCompleted
? "Upload completed"
: `${getFiles().length} files being uploaded`}
</div>
) : null}
{isUploading ? (
<DialogClose asChild onClick={cancelAll}>
<Button size={"lg"} className="mt-6">
Cancel
</Button>
)}
</DialogClose>
) : null}
{hasStarted && isCompleted ? (
<DialogClose asChild>
<Button size={"lg"} className="mt-6">
Close
</Button>
</DialogClose>
) : null}
</DialogContent>
</Dialog>
{isCompleted ? (
<DialogClose asChild>
<Button size={"lg"} className="mt-6">
Close
</Button>
</DialogClose>
) : null}
{!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),
[]
)
const [state, setState] = useState<State>()
const [uppyState, setUppyState] = useState<State>()
const [state, setState] = useState<
"completed" | "idle" | "initializing" | "error" | "uploading"
>("initializing")
const [inputProps, setInputProps] = useState<
| {
@ -71,7 +74,7 @@ export function useUppy({
[targetRef, uppyInstance]
)
const cancelAll = useCallback(
() => uppyInstance.current?.cancelAll(),
() => uppyInstance.current?.cancelAll({ reason: "user" }),
// eslint-disable-next-line react-hooks/exhaustive-deps
[targetRef, uppyInstance]
)
@ -116,36 +119,53 @@ export function useUppy({
uppy.on("complete", (result) => {
if (result.failed.length === 0) {
console.log("Upload successful üòÄ")
setState("completed")
} else {
console.warn("Upload failed üòû")
setState("error")
}
console.log("successful files:", result.successful)
console.log("failed files:", result.failed)
})
const setStateCb = () => {
setState(uppy.getState())
const setStateCb = (event: (typeof LISTENING_EVENTS)[number]) => {
switch (event) {
case "upload":
setState("uploading")
break
case "upload-error":
setState("error")
break
default:
break
}
setUppyState(uppy.getState())
}
for (const event of LISTENING_EVENTS) {
uppy.on(event, setStateCb)
uppy.on(event, function cb() {
setStateCb(event)
})
}
setState("idle")
return () => {
for (const event of ["complete", ...LISTENING_EVENTS]) {
uppyInstance.current?.off(
event as "complete" & keyof typeof LISTENING_EVENTS,
//@ts-expect-error -- huh? typescript wtf
setStateCb
)
}
uppyInstance.current?.close()
uppyInstance.current = undefined
// for (const event of ["complete", ...LISTENING_EVENTS]) {
// uppyInstance.current?.off(
// event as "complete" & keyof typeof LISTENING_EVENTS,
// //@ts-expect-error -- huh? typescript wtf
// setStateCb
// )
// }
// uppyInstance.current?.cancelAll({ reason: "unmount" })
// uppyInstance.current?.logout()
// uppyInstance.current?.close()
// uppyInstance.current = undefined
}
}, [targetRef, endpoint, uploader])
return {
files: uppyInstance.current?.getFiles() ?? [],
getFiles: () => uppyInstance.current?.getFiles() ?? [],
error: uppyInstance.current?.getState,
state,
upload: () =>
@ -154,6 +174,6 @@ export function useUppy({
getInputProps: () => inputProps,
getRootProps,
removeFile,
cancelAll,
cancelAll
}
}