187 lines
5.0 KiB
TypeScript
187 lines
5.0 KiB
TypeScript
import { useCallback, useEffect, useState } from 'react'
|
|
import {
|
|
Button,
|
|
FormControl,
|
|
FormErrorMessage,
|
|
Modal,
|
|
ModalBody,
|
|
ModalCloseButton,
|
|
ModalContent,
|
|
ModalFooter,
|
|
ModalHeader,
|
|
ModalOverlay,
|
|
} from '@chakra-ui/react'
|
|
import { useSWRConfig } from 'swr'
|
|
import {
|
|
Field,
|
|
FieldAttributes,
|
|
FieldProps,
|
|
Form,
|
|
Formik,
|
|
FormikHelpers,
|
|
} from 'formik'
|
|
import * as Yup from 'yup'
|
|
import cx from 'classnames'
|
|
import UserAPI, { User } from '@/client/idp/user'
|
|
import EditPictureUpload from './edit-picture-upload'
|
|
|
|
export type AccountEditPictureProps = {
|
|
open: boolean
|
|
user: User
|
|
onClose?: () => void
|
|
}
|
|
|
|
type FormValues = {
|
|
picture: any
|
|
}
|
|
|
|
const AccountEditPicture = ({
|
|
open,
|
|
user,
|
|
onClose,
|
|
}: AccountEditPictureProps) => {
|
|
const { mutate } = useSWRConfig()
|
|
const [isModalOpen, setIsModalOpen] = useState(false)
|
|
const [deletionInProgress, setDeletionInProgress] = useState(false)
|
|
const formSchema = Yup.object().shape({
|
|
picture: Yup.mixed()
|
|
.required()
|
|
.test(
|
|
'fileSize',
|
|
'Image is too big, should be less than 3 MB',
|
|
(value: any) => value === null || (value && value.size <= 3000000),
|
|
)
|
|
.test(
|
|
'fileType',
|
|
'Unsupported file format',
|
|
(value: any) =>
|
|
value === null ||
|
|
(value &&
|
|
['image/jpg', 'image/jpeg', 'image/gif', 'image/png'].includes(
|
|
value.type,
|
|
)),
|
|
),
|
|
})
|
|
|
|
useEffect(() => {
|
|
setIsModalOpen(open)
|
|
}, [open])
|
|
|
|
const handleSubmit = useCallback(
|
|
async (
|
|
{ picture }: FormValues,
|
|
{ setSubmitting }: FormikHelpers<FormValues>,
|
|
) => {
|
|
setSubmitting(true)
|
|
try {
|
|
const result = await UserAPI.updatePicture(picture)
|
|
mutate(`/user`, result)
|
|
setSubmitting(false)
|
|
onClose?.()
|
|
} finally {
|
|
setSubmitting(false)
|
|
}
|
|
},
|
|
[onClose, mutate],
|
|
)
|
|
|
|
const handleDelete = useCallback(async () => {
|
|
try {
|
|
setDeletionInProgress(true)
|
|
const result = await UserAPI.deletePicture()
|
|
mutate(`/user`, result)
|
|
onClose?.()
|
|
} finally {
|
|
setDeletionInProgress(false)
|
|
}
|
|
}, [onClose, mutate])
|
|
|
|
return (
|
|
<Modal
|
|
isOpen={isModalOpen}
|
|
onClose={() => onClose?.()}
|
|
closeOnOverlayClick={false}
|
|
>
|
|
<ModalOverlay />
|
|
<ModalContent>
|
|
<ModalHeader>Edit Picture</ModalHeader>
|
|
<ModalCloseButton />
|
|
<Formik
|
|
enableReinitialize={true}
|
|
initialValues={{
|
|
picture: user.picture,
|
|
}}
|
|
validationSchema={formSchema}
|
|
validateOnBlur={false}
|
|
onSubmit={handleSubmit}
|
|
>
|
|
{({ errors, touched, isSubmitting, setFieldValue, values }) => (
|
|
<Form>
|
|
<ModalBody>
|
|
<div
|
|
className={cx('flex', 'flex-col', 'items-center', 'gap-1')}
|
|
>
|
|
<Field name="picture">
|
|
{({ field }: FieldAttributes<FieldProps>) => (
|
|
<FormControl
|
|
isInvalid={
|
|
errors.picture && touched.picture ? true : false
|
|
}
|
|
>
|
|
<EditPictureUpload
|
|
{...field}
|
|
initialValue={user.picture}
|
|
disabled={isSubmitting}
|
|
onChange={(e) =>
|
|
setFieldValue('picture', e.target.files[0])
|
|
}
|
|
/>
|
|
<FormErrorMessage>{errors.picture}</FormErrorMessage>
|
|
</FormControl>
|
|
)}
|
|
</Field>
|
|
</div>
|
|
</ModalBody>
|
|
<ModalFooter>
|
|
<div
|
|
className={cx('flex', 'flex-row', 'items-center', 'gap-1')}
|
|
>
|
|
<Button
|
|
type="button"
|
|
variant="outline"
|
|
colorScheme="blue"
|
|
disabled={isSubmitting}
|
|
onClick={() => onClose?.()}
|
|
>
|
|
Cancel
|
|
</Button>
|
|
<Button
|
|
variant="outline"
|
|
colorScheme="red"
|
|
isLoading={deletionInProgress}
|
|
disabled={!user.picture}
|
|
onClick={handleDelete}
|
|
>
|
|
Delete
|
|
</Button>
|
|
<Button
|
|
type="submit"
|
|
variant="solid"
|
|
colorScheme="blue"
|
|
disabled={isSubmitting || values.picture === user.picture}
|
|
isLoading={isSubmitting}
|
|
>
|
|
Save
|
|
</Button>
|
|
</div>
|
|
</ModalFooter>
|
|
</Form>
|
|
)}
|
|
</Formik>
|
|
</ModalContent>
|
|
</Modal>
|
|
)
|
|
}
|
|
|
|
export default AccountEditPicture
|