Skip to content

Commit 882aae1

Browse files
Merge pull request #113 from uwblueprint/colin/absence-conflict
(Merge #105 first) Show warning on Absence Conflict
2 parents 161a93e + e42138d commit 882aae1

File tree

2 files changed

+54
-12
lines changed

2 files changed

+54
-12
lines changed

src/components/AbsenceDetails.tsx

Lines changed: 39 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import {
22
Box,
33
Button,
44
Flex,
5+
Icon,
56
IconButton,
67
Modal,
78
ModalBody,
@@ -10,6 +11,11 @@ import {
1011
ModalFooter,
1112
ModalHeader,
1213
ModalOverlay,
14+
Popover,
15+
PopoverArrow,
16+
PopoverBody,
17+
PopoverContent,
18+
PopoverTrigger,
1319
Text,
1420
VStack,
1521
useTheme,
@@ -19,12 +25,13 @@ import { useUserData } from '@hooks/useUserData';
1925
import { EventDetails, Role } from '@utils/types';
2026
import { Buildings, Calendar } from 'iconsax-react';
2127
import { useState } from 'react';
28+
import { BiSolidErrorCircle } from 'react-icons/bi';
2229
import { FiEdit2, FiMapPin, FiTrash2, FiUser } from 'react-icons/fi';
2330
import { IoEyeOutline } from 'react-icons/io5';
31+
import AbsenceClaimThanks from './AbsenceClaimThanks';
2432
import AbsenceStatusTag from './AbsenceStatusTag';
2533
import EditAbsenceForm from './EditAbsenceForm';
2634
import LessonPlanView from './LessonPlanView';
27-
import AbsenceClaimThanks from './AbsenceClaimThanks';
2835

2936
interface AbsenceDetailsProps {
3037
isOpen: boolean;
@@ -33,6 +40,7 @@ interface AbsenceDetailsProps {
3340
onDelete?: (absenceId: number) => void;
3441
isAdminMode: boolean;
3542
fetchAbsences: () => Promise<void>;
43+
hasConflictingEvent: boolean;
3644
}
3745

3846
const AbsenceDetails: React.FC<AbsenceDetailsProps> = ({
@@ -42,6 +50,7 @@ const AbsenceDetails: React.FC<AbsenceDetailsProps> = ({
4250
onDelete,
4351
isAdminMode,
4452
fetchAbsences,
53+
hasConflictingEvent,
4554
}) => {
4655
const theme = useTheme();
4756
const userData = useUserData();
@@ -217,16 +226,34 @@ const AbsenceDetails: React.FC<AbsenceDetailsProps> = ({
217226
>
218227
<ModalHeader p="0">
219228
<Flex justify="space-between" align="center" position="relative">
220-
<AbsenceStatusTag
221-
isUserAbsentTeacher={isUserAbsentTeacher}
222-
isUserSubstituteTeacher={isUserSubstituteTeacher}
223-
isAdminMode={isAdminMode}
224-
substituteTeacherFullName={
225-
event.substituteTeacherFullName
226-
? event.substituteTeacherFullName
227-
: undefined
228-
}
229-
/>
229+
<Flex gap="8px" align="center">
230+
<AbsenceStatusTag
231+
isUserAbsentTeacher={isUserAbsentTeacher}
232+
isUserSubstituteTeacher={isUserSubstituteTeacher}
233+
isAdminMode={isAdminMode}
234+
/>
235+
{hasConflictingEvent &&
236+
!event.substituteTeacherFullName &&
237+
!isUserAbsentTeacher && (
238+
<Popover placement="top" trigger="hover">
239+
<PopoverTrigger>
240+
<Box display="flex" alignItems="center" height="100%">
241+
<Icon
242+
as={BiSolidErrorCircle}
243+
color={theme.colors.errorRed['200']}
244+
boxSize={6}
245+
/>
246+
</Box>
247+
</PopoverTrigger>
248+
<PopoverContent bg="white" width="fit-content">
249+
<PopoverArrow />
250+
<PopoverBody textStyle="caption" maxW="190px">
251+
You have already filled an absence on this date.
252+
</PopoverBody>
253+
</PopoverContent>
254+
</Popover>
255+
)}
256+
</Flex>
230257
<Flex position="absolute" right="0">
231258
{isAdminMode && (
232259
<IconButton
@@ -422,6 +449,7 @@ const AbsenceDetails: React.FC<AbsenceDetailsProps> = ({
422449
fontSize="16px"
423450
fontWeight="500"
424451
onClick={handleClaimAbsenceClick}
452+
disabled={hasConflictingEvent}
425453
>
426454
Fill this Absence
427455
</Button>

src/pages/calendar.tsx

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,19 @@ const Calendar: React.FC = () => {
225225
updateMonthYearTitle();
226226
}, [updateMonthYearTitle]);
227227

228+
const formatDateForClaimedDays = (date: Date) => {
229+
const year = date.getFullYear();
230+
const month = (date.getMonth() + 1).toString().padStart(2, '0');
231+
const day = date.getDate().toString().padStart(2, '0');
232+
return `${year}-${month}-${day}`;
233+
};
234+
235+
const hasConflictingEvent = (event: EventDetails | null) => {
236+
if (!event?.start) return false;
237+
const dateString = formatDateForClaimedDays(new Date(event.start));
238+
return claimedDays.has(dateString);
239+
};
240+
228241
const handleAbsenceClick = (clickInfo: EventClickArg) => {
229242
setSelectedEvent({
230243
title: clickInfo.event.title,
@@ -316,7 +329,7 @@ const Calendar: React.FC = () => {
316329
}
317330

318331
const dayCellContent = (args) => {
319-
const eventDateString = `${args.date.getFullYear()}-${(args.date.getMonth() + 1).toString().padStart(2, '0')}-${args.date.getDate().toString().padStart(2, '0')}`;
332+
const eventDateString = formatDateForClaimedDays(args.date);
320333

321334
const isToday = (() => {
322335
const today = new Date();
@@ -461,6 +474,7 @@ const Calendar: React.FC = () => {
461474
fetchAbsences={fetchAbsences}
462475
onDelete={handleDeleteAbsence}
463476
isAdminMode={isAdminMode}
477+
hasConflictingEvent={hasConflictingEvent(selectedEvent)}
464478
/>
465479

466480
<Modal isOpen={isInputFormOpen} onClose={onInputFormClose} isCentered>

0 commit comments

Comments
 (0)