217 lines
6.5 KiB
TypeScript
217 lines
6.5 KiB
TypeScript
import {
|
|
ChevronLeft as ChevronLeftIcon,
|
|
ChevronRight as ChevronRightIcon,
|
|
CopyAll,
|
|
Delete,
|
|
DriveFileRenameOutline,
|
|
Home as HomeIcon,
|
|
KeyboardArrowDown as KeyboardArrowDownIcon,
|
|
Link as LinkIcon,
|
|
} from '@mui/icons-material';
|
|
import {
|
|
AppBar,
|
|
IconButton,
|
|
ListItemIcon,
|
|
ListItemText,
|
|
Menu,
|
|
MenuItem,
|
|
Toolbar,
|
|
Tooltip,
|
|
useMediaQuery,
|
|
useTheme,
|
|
} from '@mui/material';
|
|
import { Resume } from '@reactive-resume/schema';
|
|
import clsx from 'clsx';
|
|
import get from 'lodash/get';
|
|
import { useRouter } from 'next/router';
|
|
import { useTranslation } from 'next-i18next';
|
|
import { useEffect, useMemo, useState } from 'react';
|
|
import toast from 'react-hot-toast';
|
|
import { useMutation } from 'react-query';
|
|
|
|
import { RESUMES_QUERY } from '@/constants/index';
|
|
import { ServerError } from '@/services/axios';
|
|
import queryClient from '@/services/react-query';
|
|
import { deleteResume, DeleteResumeParams, duplicateResume, DuplicateResumeParams } from '@/services/resume';
|
|
import { setSidebarState, toggleSidebar } from '@/store/build/buildSlice';
|
|
import { useAppDispatch, useAppSelector } from '@/store/hooks';
|
|
import { setModalState } from '@/store/modal/modalSlice';
|
|
import getResumeUrl from '@/utils/getResumeUrl';
|
|
|
|
import styles from './Header.module.scss';
|
|
|
|
const Header = () => {
|
|
const theme = useTheme();
|
|
|
|
const router = useRouter();
|
|
|
|
const { t } = useTranslation();
|
|
|
|
const dispatch = useAppDispatch();
|
|
|
|
const isDesktop = useMediaQuery(theme.breakpoints.up('lg'));
|
|
|
|
const [anchorEl, setAnchorEl] = useState<HTMLButtonElement | null>(null);
|
|
|
|
const { mutateAsync: duplicateMutation } = useMutation<Resume, ServerError, DuplicateResumeParams>(duplicateResume);
|
|
|
|
const { mutateAsync: deleteMutation } = useMutation<void, ServerError, DeleteResumeParams>(deleteResume);
|
|
|
|
const resume = useAppSelector((state) => state.resume);
|
|
const { left, right } = useAppSelector((state) => state.build.sidebar);
|
|
|
|
const name = useMemo(() => get(resume, 'name'), [resume]);
|
|
|
|
useEffect(() => {
|
|
if (isDesktop) {
|
|
dispatch(setSidebarState({ sidebar: 'left', state: { open: true } }));
|
|
dispatch(setSidebarState({ sidebar: 'right', state: { open: true } }));
|
|
} else {
|
|
dispatch(setSidebarState({ sidebar: 'left', state: { open: false } }));
|
|
dispatch(setSidebarState({ sidebar: 'right', state: { open: false } }));
|
|
}
|
|
}, [isDesktop, dispatch]);
|
|
|
|
const toggleLeftSidebar = () => dispatch(toggleSidebar({ sidebar: 'left' }));
|
|
|
|
const toggleRightSidebar = () => dispatch(toggleSidebar({ sidebar: 'right' }));
|
|
|
|
const goBack = () => router.push('/dashboard');
|
|
|
|
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
|
|
setAnchorEl(event.currentTarget);
|
|
};
|
|
|
|
const handleClose = () => {
|
|
setAnchorEl(null);
|
|
};
|
|
|
|
const handleRename = () => {
|
|
handleClose();
|
|
|
|
dispatch(
|
|
setModalState({
|
|
modal: 'dashboard.rename-resume',
|
|
state: {
|
|
open: true,
|
|
payload: {
|
|
item: resume,
|
|
onComplete: (newResume: Resume) => {
|
|
queryClient.invalidateQueries(RESUMES_QUERY);
|
|
|
|
router.push(`/${resume.user.username}/${newResume.slug}/build`);
|
|
},
|
|
},
|
|
},
|
|
})
|
|
);
|
|
};
|
|
|
|
const handleDuplicate = async () => {
|
|
handleClose();
|
|
|
|
const newResume = await duplicateMutation({ id: resume.id });
|
|
|
|
queryClient.invalidateQueries(RESUMES_QUERY);
|
|
|
|
router.push(`/${resume.user.username}/${newResume.slug}/build`);
|
|
};
|
|
|
|
const handleDelete = async () => {
|
|
handleClose();
|
|
|
|
await deleteMutation({ id: resume.id });
|
|
|
|
queryClient.invalidateQueries(RESUMES_QUERY);
|
|
|
|
goBack();
|
|
};
|
|
|
|
const handleShareLink = async () => {
|
|
handleClose();
|
|
|
|
const url = getResumeUrl(resume, { withHost: true });
|
|
await navigator.clipboard.writeText(url);
|
|
|
|
toast.success(t('common.toast.success.resume-link-copied'));
|
|
};
|
|
|
|
return (
|
|
<AppBar elevation={0} position="fixed">
|
|
<Toolbar
|
|
variant="regular"
|
|
className={clsx({
|
|
[styles.header]: true,
|
|
[styles.pushLeft]: left.open,
|
|
[styles.pushRight]: right.open,
|
|
})}
|
|
>
|
|
<IconButton onClick={toggleLeftSidebar}>{left.open ? <ChevronLeftIcon /> : <ChevronRightIcon />}</IconButton>
|
|
|
|
<div className={styles.title}>
|
|
<IconButton className="opacity-50 hover:opacity-100" onClick={goBack}>
|
|
<HomeIcon />
|
|
</IconButton>
|
|
|
|
<span className="opacity-50">{'/'}</span>
|
|
|
|
<h1>{name}</h1>
|
|
|
|
<IconButton onClick={handleClick}>
|
|
<KeyboardArrowDownIcon />
|
|
</IconButton>
|
|
|
|
<Menu open={Boolean(anchorEl)} anchorEl={anchorEl} onClose={handleClose}>
|
|
<MenuItem onClick={handleRename}>
|
|
<ListItemIcon>
|
|
<DriveFileRenameOutline className="scale-90" />
|
|
</ListItemIcon>
|
|
<ListItemText>{t('builder.header.menu.rename')}</ListItemText>
|
|
</MenuItem>
|
|
|
|
<MenuItem onClick={handleDuplicate}>
|
|
<ListItemIcon>
|
|
<CopyAll className="scale-90" />
|
|
</ListItemIcon>
|
|
<ListItemText>{t('builder.header.menu.duplicate')}</ListItemText>
|
|
</MenuItem>
|
|
|
|
{resume.public ? (
|
|
<MenuItem onClick={handleShareLink}>
|
|
<ListItemIcon>
|
|
<LinkIcon className="scale-90" />
|
|
</ListItemIcon>
|
|
<ListItemText>{t('builder.header.menu.share-link')}</ListItemText>
|
|
</MenuItem>
|
|
) : (
|
|
<Tooltip arrow placement="right" title={t<string>('builder.header.menu.tooltips.share-link')}>
|
|
<div>
|
|
<MenuItem>
|
|
<ListItemIcon>
|
|
<LinkIcon className="scale-90" />
|
|
</ListItemIcon>
|
|
<ListItemText>{t('builder.header.menu.share-link')}</ListItemText>
|
|
</MenuItem>
|
|
</div>
|
|
</Tooltip>
|
|
)}
|
|
|
|
<Tooltip arrow placement="right" title={t<string>('builder.header.menu.tooltips.delete')}>
|
|
<MenuItem onClick={handleDelete}>
|
|
<ListItemIcon>
|
|
<Delete className="scale-90" />
|
|
</ListItemIcon>
|
|
<ListItemText>{t('builder.header.menu.delete')}</ListItemText>
|
|
</MenuItem>
|
|
</Tooltip>
|
|
</Menu>
|
|
</div>
|
|
|
|
<IconButton onClick={toggleRightSidebar}>{right.open ? <ChevronRightIcon /> : <ChevronLeftIcon />}</IconButton>
|
|
</Toolbar>
|
|
</AppBar>
|
|
);
|
|
};
|
|
|
|
export default Header;
|