From e3815bab374c4e287312f5a754a19195bd868f38 Mon Sep 17 00:00:00 2001 From: Kichiyaki Date: Sun, 14 Mar 2021 10:42:09 +0100 Subject: [PATCH] QuestionsImage: add ImagePreview, add file upload functionality --- .../components/FormDialog/FormDialog.tsx | 149 +++++++++++++++--- .../components/FormDialog/ImagePreview.tsx | 50 ++++++ .../components/FormDialog/helpers.ts | 2 + 3 files changed, 176 insertions(+), 25 deletions(-) create mode 100644 src/features/QuestionsPage/components/FormDialog/ImagePreview.tsx create mode 100644 src/features/QuestionsPage/components/FormDialog/helpers.ts diff --git a/src/features/QuestionsPage/components/FormDialog/FormDialog.tsx b/src/features/QuestionsPage/components/FormDialog/FormDialog.tsx index b4a38e3..7721f3e 100644 --- a/src/features/QuestionsPage/components/FormDialog/FormDialog.tsx +++ b/src/features/QuestionsPage/components/FormDialog/FormDialog.tsx @@ -1,6 +1,8 @@ +import { useEffect } from 'react'; import { useForm, Controller } from 'react-hook-form'; -import { pick } from 'lodash'; +import { pick, get } from 'lodash'; import useQualifications from './FormDialog.useQualifications'; +import { capitalizeFirstLetter } from './helpers'; import { QuestionInput, Question, Maybe, Answer } from 'libs/graphql/types'; import { makeStyles } from '@material-ui/core/styles'; @@ -13,7 +15,9 @@ import { DialogTitle, MenuItem, TextField, + TextFieldProps, } from '@material-ui/core'; +import ImagePreview from './ImagePreview'; const ANSWERS = Object.values(Answer); @@ -23,6 +27,21 @@ export interface FormDialogProps extends Pick { onSubmit: (input: QuestionInput) => Promise | boolean; } +type Images = Pick< + QuestionInput, + | 'deleteImage' + | 'deleteAnswerAImage' + | 'deleteAnswerBImage' + | 'deleteAnswerCImage' + | 'deleteAnswerDImage' +> & { + image?: FileList; + answerAImage?: FileList; + answerBImage?: FileList; + answerCImage?: FileList; + answerDImage?: FileList; +}; + const FormDialog = ({ open, onClose, question, onSubmit }: FormDialogProps) => { const editMode = Boolean(question); const { @@ -31,26 +50,87 @@ const FormDialog = ({ open, onClose, question, onSubmit }: FormDialogProps) => { errors, control, formState: { isSubmitting }, + watch, + setValue, } = useForm({}); + const images: Images = watch([ + 'image', + 'deleteImage', + 'answerAImage', + 'deleteAnswerAImage', + 'answerBImage', + 'deleteAnswerBImage', + 'answerCImage', + 'deleteAnswerCImage', + 'answerDImage', + 'deleteAnswerDImage', + ]); const { qualifications, loading: loadingQualifications, } = useQualifications(); const classes = useStyles(); + useEffect(() => { + [ + 'deleteImage', + 'deleteAnswerAImage', + 'deleteAnswerBImage', + 'deleteAnswerCImage', + 'deleteAnswerDImage', + ].forEach(key => { + register(key); + }); + }, [register]); + const _onSubmit = async (data: QuestionInput) => { - const filtered = editMode - ? pick( - data, - Object.keys(data).filter(key => data[key as keyof QuestionInput]) - ) - : data; - const success = await onSubmit(filtered); + console.log(data); + const success = await onSubmit({ + ...data, + image: data.image?.item(0), + answerAImage: data.answerAImage?.item(0), + answerBImage: data.answerBImage?.item(0), + answerCImage: data.answerCImage?.item(0), + answerDImage: data.answerDImage?.item(0), + }); if (success) { onClose(); } }; + const renderImagePreview = (key: keyof Images) => { + const deleteKey = ('delete' + capitalizeFirstLetter(key)) as keyof Images; + const uploadedImage = images[key] as FileList | undefined; + + if ( + (uploadedImage && uploadedImage.length > 0) || + (question && get(question, key) && !get(images, deleteKey)) + ) { + return ( + { + setValue(key, undefined); + setValue(deleteKey, true); + }} + /> + ); + } + + return null; + }; + + const defaultFileInputProps: TextFieldProps = { + type: 'file', + InputLabelProps: { + shrink: true, + }, + inputProps: { + accept: ['image/*'], + multiple: false, + }, + }; return ( { {editMode ? 'Edycja pytania' : 'Tworzenie pytania'} + {renderImagePreview('image')} + { /> {ANSWERS.map(answer => { const upper = answer.toUpperCase(); + const key = `answer${upper}` as keyof QuestionInput; + const imageKey = `${key}Image` as keyof Images; return ( - +
+ {renderImagePreview(imageKey)} + + +
); })} {!loadingQualifications && ( diff --git a/src/features/QuestionsPage/components/FormDialog/ImagePreview.tsx b/src/features/QuestionsPage/components/FormDialog/ImagePreview.tsx new file mode 100644 index 0000000..4e58490 --- /dev/null +++ b/src/features/QuestionsPage/components/FormDialog/ImagePreview.tsx @@ -0,0 +1,50 @@ +import { useEffect, useState } from 'react'; +import { Tooltip, IconButton, Box } from '@material-ui/core'; +import { Delete as DeleteIcon } from '@material-ui/icons'; + +export interface PreviewImageProps { + file?: File | null; + src?: string | null; + onDelete?: () => void; + disabled?: boolean; +} + +const PreviewImage = ({ file, src, onDelete, disabled }: PreviewImageProps) => { + const [_src, _setSrc] = useState(''); + + useEffect(() => { + if (!file) return _setSrc(src ?? ''); + const reader = new FileReader(); + + reader.onload = function (e) { + _setSrc(typeof e.target?.result === 'string' ? e.target.result : ''); + }; + + reader.readAsDataURL(file); + }, [src, file]); + + return ( + + + + + + + + + + Podgląd zdjęcia + + + ); +}; + +export default PreviewImage; diff --git a/src/features/QuestionsPage/components/FormDialog/helpers.ts b/src/features/QuestionsPage/components/FormDialog/helpers.ts new file mode 100644 index 0000000..bc8b019 --- /dev/null +++ b/src/features/QuestionsPage/components/FormDialog/helpers.ts @@ -0,0 +1,2 @@ +export const capitalizeFirstLetter = (str: string) => + str[0].toUpperCase() + str.slice(1);