mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2025-11-14 00:32:35 +10:00
🚀 release v3.0.0
This commit is contained in:
83
client/components/build/LeftSidebar/sections/PhotoUpload.tsx
Normal file
83
client/components/build/LeftSidebar/sections/PhotoUpload.tsx
Normal file
@ -0,0 +1,83 @@
|
||||
import { Avatar, IconButton, Skeleton, Tooltip } from '@mui/material';
|
||||
import { Photo, Resume } from '@reactive-resume/schema';
|
||||
import get from 'lodash/get';
|
||||
import isEmpty from 'lodash/isEmpty';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import React, { useRef } from 'react';
|
||||
import toast from 'react-hot-toast';
|
||||
import { useMutation } from 'react-query';
|
||||
|
||||
import { ServerError } from '@/services/axios';
|
||||
import { deletePhoto, DeletePhotoParams, uploadPhoto, UploadPhotoParams } from '@/services/resume';
|
||||
import { useAppDispatch, useAppSelector } from '@/store/hooks';
|
||||
import { setResumeState } from '@/store/resume/resumeSlice';
|
||||
|
||||
const FILE_UPLOAD_MAX_SIZE = 2000000; // 2 MB
|
||||
|
||||
const PhotoUpload: React.FC = () => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const fileInputRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
const id: number = useAppSelector((state) => get(state.resume, 'id'));
|
||||
const photo: Photo = useAppSelector((state) => get(state.resume, 'basics.photo'));
|
||||
|
||||
const { mutateAsync: uploadMutation, isLoading } = useMutation<Resume, ServerError, UploadPhotoParams>(uploadPhoto);
|
||||
|
||||
const { mutateAsync: deleteMutation } = useMutation<Resume, ServerError, DeletePhotoParams>(deletePhoto);
|
||||
|
||||
const handleClick = async () => {
|
||||
if (fileInputRef.current) {
|
||||
if (!isEmpty(photo.url)) {
|
||||
try {
|
||||
await deleteMutation({ id });
|
||||
} finally {
|
||||
dispatch(setResumeState({ path: 'basics.photo.url', value: '' }));
|
||||
}
|
||||
} else {
|
||||
fileInputRef.current.click();
|
||||
}
|
||||
|
||||
fileInputRef.current.value = '';
|
||||
}
|
||||
};
|
||||
|
||||
const handleChange = async (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
if (event.target.files && event.target.files[0]) {
|
||||
const file = event.target.files[0];
|
||||
|
||||
if (file.size > FILE_UPLOAD_MAX_SIZE) {
|
||||
toast.error(t('common.toast.error.upload-photo-size'));
|
||||
return;
|
||||
}
|
||||
|
||||
const resume = await uploadMutation({ id, file });
|
||||
|
||||
dispatch(setResumeState({ path: 'basics.photo.url', value: get(resume, 'basics.photo.url', '') }));
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<IconButton onClick={handleClick}>
|
||||
{isLoading ? (
|
||||
<Skeleton variant="circular" width={96} height={96} />
|
||||
) : (
|
||||
<Tooltip
|
||||
title={
|
||||
isEmpty(photo.url)
|
||||
? t<string>('builder.leftSidebar.sections.basics.photo-upload.tooltip.upload')
|
||||
: t<string>('builder.leftSidebar.sections.basics.photo-upload.tooltip.remove')
|
||||
}
|
||||
>
|
||||
<Avatar sx={{ width: 96, height: 96 }} src={photo.url} />
|
||||
</Tooltip>
|
||||
)}
|
||||
|
||||
<input hidden type="file" ref={fileInputRef} onChange={handleChange} accept="image/*" />
|
||||
</IconButton>
|
||||
);
|
||||
};
|
||||
|
||||
export default PhotoUpload;
|
||||
Reference in New Issue
Block a user