Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

make offer count work #52

Merged
merged 2 commits into from
Dec 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/App.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import JobApplicationList from './components/JobApplicationList';
import CssBaseline from '@mui/material/CssBaseline';
import { createTheme, ThemeProvider } from '@mui/material/styles';
import PrimarySearchAppBar from './components/PrimarySearchAppBar';
import AppHeader from './components/AppHeader';
import { Route, Routes } from "react-router-dom"

const theme = createTheme();
Expand All @@ -11,7 +11,7 @@ function App() {
return (
<ThemeProvider theme={theme}>
<CssBaseline />
<PrimarySearchAppBar/>
<AppHeader/>
<div className="App">
</div>
</ThemeProvider>
Expand Down
8 changes: 4 additions & 4 deletions src/App.test.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import { render, screen } from '@testing-library/react';
import { MemoryRouter } from 'react-router-dom';
import App from './App';
import PrimarySearchAppBar from './components/PrimarySearchAppBar';
import AppHeader from './components/AppHeader';
import JobApplicationList from './components/JobApplicationList';


jest.mock('./components/PrimarySearchAppBar')
jest.mock('./components/AppHeader')
jest.mock('./components/JobApplicationList')

it('Should render Job Application list on default route', async () => {
PrimarySearchAppBar.mockImplementation(() => <div>PrimarySearchAppBarMock</div>)
AppHeader.mockImplementation(() => <div>AppHeaderMock</div>)
JobApplicationList.mockImplementation(() => <div>JobApplicationListrMock</div>)
render(<MemoryRouter>
<App />
</MemoryRouter>);
expect(screen.getByText("PrimarySearchAppBarMock")).toBeInTheDocument();
expect(screen.getByText("AppHeaderMock")).toBeInTheDocument();
});
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,20 @@ import IconButton from '@mui/material/IconButton';
import Badge from '@mui/material/Badge';
import EmojiEventsIcon from '@mui/icons-material/EmojiEvents';
import AddCircleIcon from '@mui/icons-material/AddCircle';
import MailIcon from '@mui/icons-material/Mail';
import NotificationsIcon from '@mui/icons-material/Notifications';
import EventAvailableIcon from '@mui/icons-material/EventAvailable';
import AccountCircle from '@mui/icons-material/AccountCircle';
import MoreIcon from '@mui/icons-material/MoreVert';
import { useQuery } from '@apollo/client';
import { GET_PROFILE } from '../graphql/query';
import { GET_PROFILE, GET_ALL_OFFERS, GET_ALL_INTERVIEWS } from '../graphql/query';
import SearchBar from './SearchBar';
import JobApplicationDialog from './JobApplicationDialog';
import ProfileDialog from './ProfileDialog';
import JobApplicationList from './JobApplicationList';
import MobileMenu from './MobileMenu';
import dayjs from 'dayjs';

export default function PrimarySearchAppBar() {
export default function AppHeader() {
const [mobileMoreAnchorEl, setMobileMoreAnchorEl] = useState(null);
const [jobApplicationOpen, setJobApplicationOpen] = useState(false);
const [profileOpen, setProfileOpen] = useState(false);
Expand All @@ -33,6 +34,31 @@ export default function PrimarySearchAppBar() {
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',
});

const offerCount = offersData?.allOffer?.length || 0;

const filteredInterviews = interviewsData?.allInterview?.filter((interview) => {
const interviewDate = dayjs(interview.interviewDate);
if (!interviewDate.isValid()) {
console.warn('Invalid dayjs object for interviewDate:', interview.interviewDate);
return false;
}

return (
(interviewDate.isSame(dayjs(), 'day') || interviewDate.isAfter(dayjs(), 'day')) &&
['open', 'pending'].includes(interview.status)
);
}) || [];

const interviewCount = filteredInterviews?.length || 0;

const handleProfileMenuOpen = () => {
setProfileOpen(true);
setProfile(data.profileById);
Expand Down Expand Up @@ -88,13 +114,13 @@ export default function PrimarySearchAppBar() {
<IconButton size="large" aria-label="New" color="inherit" onClick={handleJobApplicationOpen}>
<AddCircleIcon />
</IconButton>
<IconButton size="large" aria-label="show 4 new mails" color="inherit">
<Badge badgeContent={4} color="error">
<MailIcon />
<IconButton size="large" color="inherit">
<Badge badgeContent={interviewsLoading ? '...' : interviewCount} color="error">
<EventAvailableIcon />
</Badge>
</IconButton>
<IconButton size="large" aria-label="show 17 new notifications" color="inherit">
<Badge badgeContent={17} color="error">
<IconButton size="large" color="inherit">
<Badge badgeContent={offersLoading ? '...' : offerCount} color="error">
<NotificationsIcon />
</Badge>
</IconButton>
Expand Down Expand Up @@ -129,6 +155,8 @@ export default function PrimarySearchAppBar() {
handleMobileMenuClose={handleMobileMenuClose}
handleProfileMenuOpen={handleProfileMenuOpen}
handleJobApplicationOpen={handleJobApplicationOpen}
interviewCount={interviewCount}
offerCount={offerCount}
/>
</AppBar>
<JobApplicationList searchTerm={searchTerm} />
Expand Down
18 changes: 9 additions & 9 deletions src/components/MobileMenu.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ import Menu from '@mui/material/Menu';
import MenuItem from '@mui/material/MenuItem';
import Badge from '@mui/material/Badge';
import AddCircleIcon from '@mui/icons-material/AddCircle';
import MailIcon from '@mui/icons-material/Mail';
import EventAvailableIcon from '@mui/icons-material/EventAvailable';
import NotificationsIcon from '@mui/icons-material/Notifications';
import AccountCircle from '@mui/icons-material/AccountCircle';

export default function MobileMenu({ mobileMoreAnchorEl, isMobileMenuOpen, handleMobileMenuClose, handleProfileMenuOpen, handleJobApplicationOpen }) {
export default function MobileMenu({ mobileMoreAnchorEl, isMobileMenuOpen, handleMobileMenuClose, handleProfileMenuOpen, handleJobApplicationOpen, interviewCount, offerCount }) {
const mobileMenuId = 'primary-search-account-menu-mobile';
return (
<Menu
Expand All @@ -33,20 +33,20 @@ export default function MobileMenu({ mobileMoreAnchorEl, isMobileMenuOpen, handl
<p>New</p>
</MenuItem>
<MenuItem>
<IconButton size="large" aria-label="show 4 new mails" color="inherit">
<Badge badgeContent={4} color="error">
<MailIcon />
<IconButton size="large" color="inherit">
<Badge badgeContent={interviewCount} color="error">
<EventAvailableIcon />
</Badge>
</IconButton>
<p>Offers</p>
<p>Interviews</p>
</MenuItem>
<MenuItem>
<IconButton size="large" aria-label="show 17 new notifications" color="inherit">
<Badge badgeContent={17} color="error">
<IconButton size="large" color="inherit">
<Badge badgeContent={offerCount} color="error">
<NotificationsIcon />
</Badge>
</IconButton>
<p>Interviews</p>
<p>Offers</p>
</MenuItem>
<MenuItem onClick={handleProfileMenuOpen}>
<IconButton size="large" aria-label="account of current user" aria-controls="primary-search-account-menu" aria-haspopup="true" color="inherit">
Expand Down
17 changes: 13 additions & 4 deletions src/components/forms/InterviewsForm.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import ConfirmDialog from '../common/ConfirmDialog';
import SnackbarComponent from '../common/SnackbarComponent';
import useSnackbar from '../hooks/useSnackbar';
import { ADD_INTERVIEW, UPDATE_INTERVIEW, DELETE_INTERVIEW } from '../../graphql/mutation';
import { GET_INTERVIEWS_BY_JOB_APPLICATION_ID } from '../../graphql/query';
import { GET_INTERVIEWS_BY_JOB_APPLICATION_ID, GET_ALL_INTERVIEWS } from '../../graphql/query';
import dayjs from 'dayjs';
import { Grid } from '@mui/material';

Expand All @@ -30,15 +30,24 @@ export default function InterviewsForm({ jobApplicationId }) {
});

const [addInterview] = useMutation(ADD_INTERVIEW, {
refetchQueries: [{ query: GET_INTERVIEWS_BY_JOB_APPLICATION_ID, variables: { jobApplicationId } }],
refetchQueries: [
{ query: GET_INTERVIEWS_BY_JOB_APPLICATION_ID, variables: { jobApplicationId } },
{ query: GET_ALL_INTERVIEWS }
],
});

const [updateInterview] = useMutation(UPDATE_INTERVIEW, {
refetchQueries: [{ query: GET_INTERVIEWS_BY_JOB_APPLICATION_ID, variables: { jobApplicationId } }],
refetchQueries: [
{ query: GET_INTERVIEWS_BY_JOB_APPLICATION_ID, variables: { jobApplicationId } },
{ query: GET_ALL_INTERVIEWS }
],
});

const [deleteInterview] = useMutation(DELETE_INTERVIEW, {
refetchQueries: [{ query: GET_INTERVIEWS_BY_JOB_APPLICATION_ID, variables: { jobApplicationId } }],
refetchQueries: [
{ query: GET_INTERVIEWS_BY_JOB_APPLICATION_ID, variables: { jobApplicationId } },
{ query: GET_ALL_INTERVIEWS }
],
onError: (err) => {
console.error('Error deleting interview:', err.message);
showSnackbar('Error deleting interview', 'error');
Expand Down
8 changes: 6 additions & 2 deletions src/components/forms/OfferForm.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
import { DesktopDatePicker } from '@mui/x-date-pickers/DesktopDatePicker';
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
import { ADD_OFFER, UPDATE_OFFER, DELETE_OFFER } from '../../graphql/mutation';
import { GET_OFFER } from '../../graphql/query';
import { GET_OFFER, GET_ALL_OFFERS } from '../../graphql/query';
import dayjs from 'dayjs';
import { Grid } from '@mui/material';

Expand Down Expand Up @@ -43,7 +43,10 @@ export default function OfferForm({ jobApplicationId, handleClose }) {
});

const [deleteOffer, { loading: deleteOfferLoading }] = useMutation(DELETE_OFFER, {
refetchQueries: [{ query: GET_OFFER, variables: { jobApplicationId } }],
refetchQueries: [
{ query: GET_OFFER, variables: { jobApplicationId } },
{ query: GET_ALL_OFFERS },
],
});

useEffect(() => {
Expand Down Expand Up @@ -100,6 +103,7 @@ export default function OfferForm({ jobApplicationId, handleClose }) {
description: offerData.description,
offerDate: offerData.offerDate,
},
refetchQueries: [{ query: GET_ALL_OFFERS }],
});
showSnackbar('Offer added successfully!', 'success');
}
Expand Down
13 changes: 13 additions & 0 deletions src/graphql/query.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,19 @@ export const GET_OFFER = gql`
`
;

export const GET_ALL_OFFERS = gql`
query GetOffers {
allOffer {
id
jobApplicationId
offerDate
salaryOffered
description
}
}
`
;

export const GET_ALL_INTERVIEWS = gql`
query GetAllInterviews {
allInterview {
Expand Down
Loading