Skip to content

Commit

Permalink
offer list (#53)
Browse files Browse the repository at this point in the history
  • Loading branch information
januschung authored Dec 19, 2024
1 parent bd05c57 commit 6536cc7
Show file tree
Hide file tree
Showing 9 changed files with 251 additions and 28 deletions.
41 changes: 27 additions & 14 deletions src/components/AppHeader.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,31 @@ import { useQuery } from '@apollo/client';
import { GET_PROFILE, GET_ALL_OFFERS, GET_ALL_INTERVIEWS } from '../graphql/query';
import SearchBar from './SearchBar';
import JobApplicationDialog from './JobApplicationDialog';
import OfferListDialog from './OfferListDialog';
import useJobApplicationDialog from './hooks/useJobApplicationDialog';
import useOfferListDialog from './hooks/useOfferList';
import ProfileDialog from './ProfileDialog';
import JobApplicationList from './JobApplicationList';
import MobileMenu from './MobileMenu';
import dayjs from 'dayjs';

export default function AppHeader() {
const [mobileMoreAnchorEl, setMobileMoreAnchorEl] = useState(null);
const [jobApplicationOpen, setJobApplicationOpen] = useState(false);
const [profileOpen, setProfileOpen] = useState(false);
const [profile, setProfile] = useState('');
const [searchTerm, setSearchTerm] = useState('');
const { data: offersData, loading: offersLoading, error: offersError, refetch } = useQuery(GET_ALL_OFFERS, {
fetchPolicy: 'network-only',
});
const { open, handleOpen, handleClose } = useJobApplicationDialog(refetch);

const {
offerListingDialogOpen,
handleOfferListDialogOpen,
handleOfferListDialogClose,
} = useOfferListDialog(refetch);


const isMobileMenuOpen = Boolean(mobileMoreAnchorEl);

const id = 1;
Expand All @@ -34,10 +48,6 @@ export default function AppHeader() {
variables: { id },
});

const { data: offersData, loading: offersLoading, error: offersError } = useQuery(GET_ALL_OFFERS, {
fetchPolicy: 'network-only',
});

const { data: interviewsData, loading: interviewsLoading, error: interviewsError } = useQuery(GET_ALL_INTERVIEWS, {
fetchPolicy: 'network-only',
});
Expand Down Expand Up @@ -66,8 +76,6 @@ export default function AppHeader() {

const handleProfileClose = () => setProfileOpen(false);
const handleMobileMenuClose = () => setMobileMoreAnchorEl(null);
const handleJobApplicationOpen = () => setJobApplicationOpen(true);
const handleJobApplicationClose = () => setJobApplicationOpen(false);

const handleSearch = (text) => {
setSearchTerm(text);
Expand All @@ -77,9 +85,9 @@ export default function AppHeader() {
<Box sx={{ flexGrow: 1 }}>
<JobApplicationDialog
jobApplication={{ status: 'open' }}
open={jobApplicationOpen}
handleClose={handleJobApplicationClose}
setOpen={setJobApplicationOpen}
open={open}
handleClose={handleClose}
setOpen={handleOpen}
isNew
/>
<ProfileDialog
Expand All @@ -88,6 +96,11 @@ export default function AppHeader() {
handleClose={handleProfileClose}
setOpen={setProfileOpen}
/>
<OfferListDialog
open={offerListingDialogOpen}
handleClose={handleOfferListDialogClose}
setOpen={handleOfferListDialogOpen}
/>
<AppBar position="static">
<Toolbar>
<EmojiEventsIcon sx={{ color: '#FFD700', mr: 2 }} />
Expand All @@ -111,15 +124,15 @@ export default function AppHeader() {
<SearchBar onSearch={handleSearch} />
<Box sx={{ flexGrow: 1 }} />
<Box sx={{ display: { xs: 'none', md: 'flex' } }}>
<IconButton size="large" aria-label="New" color="inherit" onClick={handleJobApplicationOpen}>
<IconButton size="large" aria-label="New" color="inherit" onClick={handleOpen}>
<AddCircleIcon />
</IconButton>
<IconButton size="large" color="inherit">
<IconButton size="large" color="inherit" onClick={() => refetch()}>
<Badge badgeContent={interviewsLoading ? '...' : interviewCount} color="error">
<EventAvailableIcon />
</Badge>
</IconButton>
<IconButton size="large" color="inherit">
<IconButton size="large" color="inherit" onClick={handleOfferListDialogOpen}>
<Badge badgeContent={offersLoading ? '...' : offerCount} color="error">
<NotificationsIcon />
</Badge>
Expand Down Expand Up @@ -154,7 +167,7 @@ export default function AppHeader() {
isMobileMenuOpen={isMobileMenuOpen}
handleMobileMenuClose={handleMobileMenuClose}
handleProfileMenuOpen={handleProfileMenuOpen}
handleJobApplicationOpen={handleJobApplicationOpen}
handleJobApplicationOpen={handleOpen}
interviewCount={interviewCount}
offerCount={offerCount}
/>
Expand Down
4 changes: 2 additions & 2 deletions src/components/JobApplicationDialog.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,13 @@ export default function JobApplicationDialog({ jobApplication, handleClose, open
)}
{activeTab === 1 && (
<InterviewsForm
jobApplicationId={parseInt(jobApplication.id)}
jobApplicationId={parseInt(jobApplication.id || 0)}
/>
)}

{activeTab === 2 && (
<OfferForm
jobApplicationId={parseInt(jobApplication.id)}
jobApplicationId={parseInt(jobApplication?.id || 0)}
handleClose={handleClose}
/>
)}
Expand Down
17 changes: 9 additions & 8 deletions src/components/JobApplicationList.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,20 @@ import SnackbarComponent from './common/SnackbarComponent';
import useJobApplications from './hooks/useJobApplications';
import useSnackbar from './hooks/useSnackbar';
import useConfirmDialog from './hooks/useConfirmDialog';
import useJobApplicationDialog from './hooks/useJobApplicationDialog';
import { DELETE_JOB_APPLICATION } from '../graphql/mutation';
import { GET_JOB_APPLICATIONS } from '../graphql/query';

export default function JobApplicationList({ searchTerm }) {
const [open, setOpen] = useState(false);
const [jobApplication, setJobApplication] = useState(null);
// const [open, setOpen] = useState(false);
// const [jobApplication, setJobApplication] = useState(null);
const [jobApplicationToDelete, setJobApplicationToDelete] = useState(null);
const [localData, setLocalData] = useState([]);

const { data, loading, error } = useJobApplications();
const { snackbarOpen, snackbarMessage, showSnackbar, handleSnackbarClose } = useSnackbar();
const { confirmOpen, openConfirmDialog, cancel } = useConfirmDialog();

const { open, jobApplication, handleOpen, handleClose } = useJobApplicationDialog();

const [deleteJobApplication] = useMutation(DELETE_JOB_APPLICATION, {
refetchQueries: [{ query: GET_JOB_APPLICATIONS }],
Expand All @@ -48,12 +49,12 @@ export default function JobApplicationList({ searchTerm }) {
}
}, [data]);

const handleOpen = (jobApplication) => {
setJobApplication(jobApplication);
setOpen(true);
};
// const handleOpen = (jobApplication) => {
// setJobApplication(jobApplication);
// setOpen(true);
// };

const handleClose = () => setOpen(false);
// const handleClose = () => setOpen(false);

const confirmDeleteJobApplication = () => {
if (jobApplicationToDelete) {
Expand Down
139 changes: 139 additions & 0 deletions src/components/OfferListDialog.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
import React, { useState, useEffect } from 'react';
import { useQuery } from '@apollo/client';
import CancelIcon from '@mui/icons-material/Cancel';
import Button from '@mui/material/Button';
import Dialog from '@mui/material/Dialog';
import DialogActions from '@mui/material/DialogActions';
import DialogContent from '@mui/material/DialogContent';
import CircularProgress from '@mui/material/CircularProgress';
import Box from '@mui/material/Box';
import Table from '@mui/material/Table';
import TableBody from '@mui/material/TableBody';
import TableCell from '@mui/material/TableCell';
import TableContainer from '@mui/material/TableContainer';
import TableHead from '@mui/material/TableHead';
import TableRow from '@mui/material/TableRow';
import Typography from '@mui/material/Typography';
import Paper from '@mui/material/Paper';
import { GET_ALL_OFFERS } from '../graphql/query';
import useJobApplicationDialog from './hooks/useJobApplicationDialog';
import JobApplicationDialog from './JobApplicationDialog';
import DialogTitleBar from './DialogTitleBar';

export default function OfferListDialog({ handleClose, open }) {
const [offers, setOffers] = useState([]);
const { loading, error, data, refetch } = useQuery(GET_ALL_OFFERS, {
fetchPolicy: 'network-only',
onCompleted: (data) => setOffers(data.allOffer),
});
const {
open: jobDialogOpen,
jobApplication,
handleOpen: handleJobDialogOpen,
handleClose: handleJobDialogClose
} = useJobApplicationDialog(() => {
refetch().then(({ data }) => setOffers(data.allOffer));
});

useEffect(() => {
if (open) {
refetch()
.then(({ data }) => {
if (data) setOffers(data.allOffer);
})
.catch((err) => console.error('Refetch error:', err));
}
}, [open, refetch]);

return (
<Dialog
open={open}
onClose={handleClose}
aria-labelledby="modal-title"
aria-describedby="modal-description"
fullWidth
maxWidth="md"
slotProps={{
backdrop: {
sx: {
backdropFilter: 'blur(8px)',
},
},
}}
>
<DialogTitleBar title="Offer List" />

<DialogContent dividers>
{loading && (
<Box display="flex" justifyContent="center" alignItems="center" height="200px">
<CircularProgress />
</Box>
)}

{error && (
<Typography variant="body1" color="error" align="center">
Something went wrong. Please try again later.
</Typography>
)}

{!loading && !error && offers.length === 0 && (
<Box textAlign="center" p={4}>
<Typography variant="h6" color="textSecondary">
No offers available yet!
</Typography>
<Button color="primary" variant="contained" onClick={handleClose}>
Add an Offer
</Button>
</Box>
)}

{!loading && !error && offers.length > 0 && (
<TableContainer component={Paper}>
<Table>
<TableHead>
<TableRow>
<TableCell align="left">Company</TableCell>
<TableCell align="left">Offer Date</TableCell>
<TableCell align="left">Salary Offered</TableCell>
<TableCell align="left">Note</TableCell>
<TableCell align="center">Job Application</TableCell>
</TableRow>
</TableHead>
<TableBody>
{offers.map((offer, index) => (
<TableRow key={index}>
<TableCell align="left">{offer.jobApplication.companyName}</TableCell>
<TableCell align="left">{offer.offerDate}</TableCell>
<TableCell align="left">{offer.salaryOffered}</TableCell>
<TableCell align="left">{offer.description}</TableCell>
<TableCell align="center">
<Button
size="small"
color="info"
variant="outlined"
onClick={() => handleJobDialogOpen(offer.jobApplication)}
>
Job Details
</Button>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
)}
</DialogContent>

<DialogActions>
<Button color="info" variant="outlined" startIcon={<CancelIcon />} onClick={handleClose}>
Cancel
</Button>
</DialogActions>
<JobApplicationDialog
jobApplication={jobApplication}
open={jobDialogOpen}
handleClose={handleJobDialogClose}
/>
</Dialog>
);
}
4 changes: 2 additions & 2 deletions src/components/forms/ApplicationForm.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { ADD_JOB_APPLICATION, UPDATE_JOB_APPLICATION } from '../../graphql/mutat
import { GET_JOB_APPLICATIONS } from '../../graphql/query';
import dayjs from 'dayjs';

export default function ApplicationForm({ jobApplication, isNew, setOpen, handleClose }) {
export default function ApplicationForm({ jobApplication, isNew, handleClose }) {
const [formData, setFormData] = useState({
companyName: '',
jobTitle: '',
Expand Down Expand Up @@ -70,7 +70,7 @@ export default function ApplicationForm({ jobApplication, isNew, setOpen, handle
...(jobApplication && { id: jobApplication.id }),
};
mutationFn({ variables });
setOpen(false);
handleClose()
};

return (
Expand Down
10 changes: 8 additions & 2 deletions src/components/forms/OfferForm.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,17 @@ export default function OfferForm({ jobApplicationId, handleClose }) {
});

const [addOffer, { loading: addOfferLoading }] = useMutation(ADD_OFFER, {
refetchQueries: [{ query: GET_OFFER, variables: { jobApplicationId } }],
refetchQueries: [
{ query: GET_OFFER, variables: { jobApplicationId } },
{ query: GET_ALL_OFFERS },
],
});

const [updateOffer, { loading: updateOfferLoading }] = useMutation(UPDATE_OFFER, {
refetchQueries: [{ query: GET_OFFER, variables: { jobApplicationId } }],
refetchQueries: [
{ query: GET_OFFER, variables: { jobApplicationId } },
{ query: GET_ALL_OFFERS },
],
});

const [deleteOffer, { loading: deleteOfferLoading }] = useMutation(DELETE_OFFER, {
Expand Down
31 changes: 31 additions & 0 deletions src/components/hooks/useJobApplicationDialog.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { useState } from 'react';

const useJobApplicationDialog = (refetch) => {
const [open, setOpen] = useState(false);
const [jobApplication, setJobApplication] = useState(null);

const handleOpen = (jobApplication) => {
if (refetch) {
refetch();
}
setJobApplication(jobApplication);
setOpen(true);
};

const handleClose = () => {
if (refetch) {
refetch();
}
setOpen(false);
setJobApplication(null);
};

return {
open,
jobApplication,
handleOpen,
handleClose,
};
};

export default useJobApplicationDialog;
23 changes: 23 additions & 0 deletions src/components/hooks/useOfferList.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { useState } from 'react';

export default function useOfferListDialog(refetch) {
const [offerListingDialogOpen, setOfferListDialogOpen] = useState(false);
const handleOfferListDialogOpen = () => {
setOfferListDialogOpen(true);
if (refetch) {
refetch();
}
}
const handleOfferListDialogClose = () => {
setOfferListDialogOpen(false);
if (refetch) {
refetch();
}
}

return {
offerListingDialogOpen,
handleOfferListDialogOpen,
handleOfferListDialogClose,
};
}
Loading

0 comments on commit 6536cc7

Please sign in to comment.