enable multi file upload

This commit is contained in:
shamsmosowi
2022-10-11 19:14:31 +02:00
parent 433ee68c2c
commit 293df99c0a
5 changed files with 109 additions and 111 deletions

View File

@@ -23,6 +23,7 @@ import { DATE_TIME_FORMAT } from "@src/constants/dates";
import { fieldSx, getFieldId } from "@src/components/SideDrawer/utils";
import { projectScope, confirmDialogAtom } from "@src/atoms/projectScope";
import { FileValue } from "@src/types/table";
import { arrayUnion } from "firebase/firestore";
export default function File_({
column,
@@ -37,25 +38,22 @@ export default function File_({
const { uploaderState, upload, deleteUpload } = useUploader();
// Store a preview image locally while uploading
const [localFile, setLocalFile] = useState<string>("");
const [localFiles, setLocalFiles] = useState<string[]>([]);
const onDrop = useCallback(
(acceptedFiles: File[]) => {
const file = acceptedFiles[0];
if (_rowy_ref && file) {
if (acceptedFiles.length > 0) {
upload({
docRef: _rowy_ref! as any,
fieldName: column.key,
files: [file],
previousValue: value ?? [],
onComplete: (newValue) => {
onChange(newValue);
files: acceptedFiles,
onComplete: (newUploads) => {
onChange(arrayUnion(newUploads));
onSubmit();
setLocalFile("");
setLocalFiles([]);
},
});
setLocalFile(file.name);
setLocalFiles(acceptedFiles.map((file) => file.name));
}
},
[_rowy_ref, value]
@@ -71,7 +69,7 @@ export default function File_({
const { getRootProps, getInputProps, isDragActive } = useDropzone({
onDrop,
multiple: false,
multiple: true,
});
return (
@@ -138,15 +136,18 @@ export default function File_({
</Grid>
))}
{localFile && (
<Grid item>
<Chip
icon={<FileIcon />}
label={localFile}
deleteIcon={<CircularProgressOptical size={20} color="inherit" />}
/>
</Grid>
)}
{localFiles &&
localFiles.map((fileName) => (
<Grid item>
<Chip
icon={<FileIcon />}
label={fileName}
deleteIcon={
<CircularProgressOptical size={20} color="inherit" />
}
/>
</Grid>
))}
</Grid>
</>
);

View File

@@ -1,4 +1,4 @@
import { useCallback } from "react";
import { useCallback, useState } from "react";
import { IHeavyCellProps } from "@src/components/fields/types";
import { useSetAtom } from "jotai";
import { findIndex } from "lodash-es";
@@ -17,6 +17,7 @@ import useUploader from "@src/hooks/useFirebaseStorageUploader";
import { FileIcon } from ".";
import { DATE_TIME_FORMAT } from "@src/constants/dates";
import { FileValue } from "@src/types/table";
import { arrayUnion } from "firebase/firestore";
export default function File_({
column,
@@ -28,28 +29,26 @@ export default function File_({
}: IHeavyCellProps) {
const confirm = useSetAtom(confirmDialogAtom, projectScope);
const updateField = useSetAtom(updateFieldAtom, tableScope);
const [localFiles, setLocalFiles] = useState<string[]>([]);
const { uploaderState, upload, deleteUpload } = useUploader();
const { progress, isLoading } = uploaderState;
const onDrop = useCallback(
(acceptedFiles: File[]) => {
const file = acceptedFiles[0];
if (file) {
if (acceptedFiles.length > 0) {
upload({
docRef: docRef! as any,
fieldName: column.key,
files: [file],
previousValue: value,
onComplete: (newValue) => {
files: acceptedFiles,
onComplete: (newUploads) => {
updateField({
path: docRef.path,
fieldName: column.key,
value: newValue,
value: arrayUnion(newUploads),
});
setLocalFiles([]);
},
});
setLocalFiles(acceptedFiles.map((file) => file.name));
}
},
[value]
@@ -65,7 +64,7 @@ export default function File_({
const { getRootProps, getInputProps, isDragActive } = useDropzone({
onDrop,
multiple: false,
multiple: true,
});
const dropzoneProps = getRootProps();
@@ -135,6 +134,18 @@ export default function File_({
</Tooltip>
</Grid>
))}
{localFiles &&
localFiles.map((fileName) => (
<Grid item>
<Chip
icon={<FileIcon />}
label={fileName}
deleteIcon={
<CircularProgressOptical size={20} color="inherit" />
}
/>
</Grid>
))}
</ChipList>
{!isLoading ? (

View File

@@ -26,6 +26,7 @@ import CircularProgressOptical from "@src/components/CircularProgressOptical";
import { projectScope, confirmDialogAtom } from "@src/atoms/projectScope";
import { IMAGE_MIME_TYPES } from ".";
import { fieldSx, getFieldId } from "@src/components/SideDrawer/utils";
import { arrayUnion } from "firebase/firestore";
const imgSx = {
position: "relative",
@@ -93,25 +94,21 @@ export default function Image_({
const { progress } = uploaderState;
// Store a preview image locally while uploading
const [localImage, setLocalImage] = useState<string>("");
const [localImages, setLocalImages] = useState<string[]>([]);
const onDrop = useCallback(
(acceptedFiles: File[]) => {
const imageFile = acceptedFiles[0];
if (_rowy_ref && imageFile) {
if (_rowy_ref && acceptedFiles.length > 0) {
upload({
docRef: _rowy_ref! as any,
fieldName: column.key,
files: [imageFile],
previousValue: value ?? [],
onComplete: (newValue) => {
onChange(newValue);
onSubmit();
setLocalImage("");
files: acceptedFiles,
onComplete: (newUploads) => {
onChange(arrayUnion(newUploads));
setLocalImages([]);
},
});
setLocalImage(URL.createObjectURL(imageFile));
setLocalImages(acceptedFiles.map((file) => URL.createObjectURL(file)));
}
},
[_rowy_ref, value]
@@ -127,7 +124,7 @@ export default function Image_({
const { getRootProps, getInputProps, isDragActive } = useDropzone({
onDrop,
multiple: false,
multiple: true,
accept: IMAGE_MIME_TYPES,
});
@@ -237,29 +234,30 @@ export default function Image_({
</Grid>
))}
{localImage && (
<Grid item>
<ButtonBase
sx={imgSx}
style={{ backgroundImage: `url("${localImage}")` }}
className="img"
>
<Grid
container
justifyContent="center"
alignItems="center"
sx={overlaySx}
{localImages &&
localImages.map((image, i) => (
<Grid item>
<ButtonBase
sx={imgSx}
style={{ backgroundImage: `url("${image}")` }}
className="img"
>
<CircularProgressOptical
color="inherit"
size={48}
variant={progress === 0 ? "indeterminate" : "determinate"}
value={progress}
/>
</Grid>
</ButtonBase>
</Grid>
)}
<Grid
container
justifyContent="center"
alignItems="center"
sx={overlaySx}
>
<CircularProgressOptical
color="inherit"
size={48}
variant={progress === 0 ? "indeterminate" : "determinate"}
value={progress}
/>
</Grid>
</ButtonBase>
</Grid>
))}
</Grid>
</>
);

View File

@@ -32,6 +32,7 @@ import useUploader from "@src/hooks/useFirebaseStorageUploader";
import { IMAGE_MIME_TYPES } from "./index";
import { DEFAULT_ROW_HEIGHT } from "@src/components/Table";
import { FileValue } from "@src/types/table";
import { arrayUnion } from "firebase/firestore";
// MULTIPLE
const imgSx = (rowHeight: number) => ({
@@ -99,28 +100,25 @@ export default function Image_({
const { progress, isLoading } = uploaderState;
// Store a preview image locally while uploading
const [localImage, setLocalImage] = useState<string>("");
const [localImages, setLocalImages] = useState<string[]>([]);
const onDrop = useCallback(
(acceptedFiles: File[]) => {
const imageFile = acceptedFiles[0];
if (imageFile) {
if (acceptedFiles.length > 0) {
upload({
docRef: docRef! as any,
fieldName: column.key,
files: [imageFile],
previousValue: value,
onComplete: (newValue) => {
files: acceptedFiles,
onComplete: (newUploads) => {
updateField({
path: docRef.path,
fieldName: column.key,
value: newValue,
value: arrayUnion(newUploads),
});
setLocalImage("");
setLocalImages([]);
},
});
setLocalImage(URL.createObjectURL(imageFile));
setLocalImages(acceptedFiles.map((file) => URL.createObjectURL(file)));
}
},
[value]
@@ -136,7 +134,7 @@ export default function Image_({
const { getRootProps, getInputProps, isDragActive } = useDropzone({
onDrop,
multiple: false,
multiple: true,
accept: IMAGE_MIME_TYPES,
});
@@ -250,20 +248,21 @@ export default function Image_({
</Grid>
))}
{localImage && (
<Grid item>
<Box
sx={[
imgSx(rowHeight),
{
boxShadow: (theme) =>
`0 0 0 1px ${theme.palette.divider} inset`,
},
]}
style={{ backgroundImage: `url("${localImage}")` }}
/>
</Grid>
)}
{localImages &&
localImages.map((url) => (
<Grid item>
<Box
sx={[
imgSx(rowHeight),
{
boxShadow: (theme) =>
`0 0 0 1px ${theme.palette.divider} inset`,
},
]}
style={{ backgroundImage: `url("${url}")` }}
/>
</Grid>
))}
</Grid>
</div>

View File

@@ -33,8 +33,7 @@ export type UploadProps = {
docRef: DocumentReference;
fieldName: string;
files: File[];
previousValue?: FileValue[];
onComplete?: (values: FileValue[]) => void;
onComplete?: (value: FileValue) => void;
};
// TODO: GENERALIZE INTO ATOM
@@ -46,13 +45,7 @@ const useFirebaseStorageUploader = () => {
...initialState,
});
const upload = ({
docRef,
fieldName,
files,
previousValue,
onComplete,
}: UploadProps) => {
const upload = ({ docRef, fieldName, files, onComplete }: UploadProps) => {
uploaderDispatch({ isLoading: true });
files.forEach((file) => {
@@ -139,24 +132,20 @@ const useFirebaseStorageUploader = () => {
// Upload completed successfully, now we can get the download URL
getDownloadURL(uploadTask.snapshot.ref).then(
(downloadURL: string) => {
const newValue: FileValue[] = Array.isArray(previousValue)
? [...previousValue]
: [];
newValue.push({
ref: uploadTask.snapshot.ref.fullPath,
downloadURL,
name: file.name,
type: file.type,
lastModifiedTS: file.lastModified,
});
// STore in the document if docRef provided
// if (docRef && docRef.update)docRef.update({ [fieldName]: newValue });
// Also call callback if it exists
// IMPORTANT: SideDrawer form may not update its local values after this
// function updates the doc, so you MUST update it manually
// using this callback
if (onComplete) onComplete(newValue);
const obj = {
ref: uploadTask.snapshot.ref.fullPath,
downloadURL,
name: file.name,
type: file.type,
lastModifiedTS: file.lastModified,
};
if (onComplete) onComplete(obj);
}
);
}