mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2025-11-16 01:32:02 +10:00
🚀 release: v3.0.0
This commit is contained in:
216
apps/client/components/build/Center/Header.tsx
Normal file
216
apps/client/components/build/Center/Header.tsx
Normal file
@ -0,0 +1,216 @@
|
||||
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('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('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;
|
||||
Reference in New Issue
Block a user