Skip to content

Commit

Permalink
fix(calendar): prevent click on occurrence dialog close from flopping (
Browse files Browse the repository at this point in the history
…#136)

* fix(calendar): prevent click on occurrence dialog close from flopping

* feat(habit): use nextui disclosure for edit dialog
  • Loading branch information
domhhv authored Dec 27, 2024
1 parent 030b6fa commit 6dda919
Show file tree
Hide file tree
Showing 6 changed files with 44 additions and 98 deletions.
56 changes: 1 addition & 55 deletions src/components/calendar/AddOccurrenceDialog.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ describe(AddOccurrenceDialog.name, () => {
const date = new Date(2021, 1, 1, 12);

const props = {
open: true,
isOpen: true,
onClose: mockOnClose,
date,
};
Expand Down Expand Up @@ -56,60 +56,6 @@ describe(AddOccurrenceDialog.name, () => {
expect(getByText('Add habit entry for 2021-01-01')).toBeInTheDocument();
});

it('should not render if date is null', () => {
(useHabitsStore as unknown as jest.Mock).mockReturnValue({ habits: [] });
(useNotesStore as unknown as jest.Mock).mockReturnValue({
addNote: jest.fn(),
addingNote: false,
});
(useUser as jest.Mock).mockReturnValue({ id: '1' });
(format as jest.Mock).mockReturnValue('2021-01-01');
(useOccurrencesStore as unknown as jest.Mock).mockReturnValue({
addOccurrence: jest.fn(),
addingOccurrence: false,
});
const { container } = render(
<AddOccurrenceDialog {...props} date={null} />
);
expect(container.firstChild).toBeNull();
});

it('should not render if open is false', () => {
(useHabitsStore as unknown as jest.Mock).mockReturnValue({ habits: [] });
(useNotesStore as unknown as jest.Mock).mockReturnValue({
addNote: jest.fn(),
addingNote: false,
});
(useUser as jest.Mock).mockReturnValue({ id: '1' });
(format as jest.Mock).mockReturnValue('2021-01-01');
(useOccurrencesStore as unknown as jest.Mock).mockReturnValue({
addOccurrence: jest.fn(),
addingOccurrence: false,
});
const { container } = render(
<AddOccurrenceDialog {...props} open={false} />
);
expect(container.firstChild).toBeNull();
});

it('should not render if date is null', () => {
(useHabitsStore as unknown as jest.Mock).mockReturnValue({ habits: [] });
(useNotesStore as unknown as jest.Mock).mockReturnValue({
addNote: jest.fn(),
addingNote: false,
});
(useUser as jest.Mock).mockReturnValue({ id: '1' });
(format as jest.Mock).mockReturnValue('2021-01-01');
(useOccurrencesStore as unknown as jest.Mock).mockReturnValue({
addOccurrence: jest.fn(),
addingOccurrence: false,
});
const { container } = render(
<AddOccurrenceDialog {...props} date={null} />
);
expect(container.firstChild).toBeNull();
});

it('if no habits are available, should show a message', () => {
(useHabitsStore as unknown as jest.Mock).mockReturnValue({ habits: [] });
(useNotesStore as unknown as jest.Mock).mockReturnValue({
Expand Down
22 changes: 11 additions & 11 deletions src/components/calendar/AddOccurrenceDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@ import React, { type MouseEventHandler } from 'react';
import { Link } from 'react-router-dom';

type AddOccurrenceDialogProps = {
open: boolean;
isOpen: boolean;
onClose: () => void;
date: Date | null;
};

const AddOccurrenceDialog = ({
open,
isOpen,
onClose,
date,
}: AddOccurrenceDialogProps) => {
Expand All @@ -44,10 +44,6 @@ const AddOccurrenceDialog = ({
return Object.groupBy(habits, (habit) => habit.trait?.name || 'Unknown');
}, [habits]);

if (!date || !open) {
return null;
}

const hasHabits = habits.length > 0;

const handleSubmit: MouseEventHandler<HTMLButtonElement> = async (event) => {
Expand All @@ -58,9 +54,11 @@ const AddOccurrenceDialog = ({
}

const newOccurrence = await addOccurrence({
day: date.toISOString().split('T')[0],
timestamp: +date,
habitId: +selectedHabitId,
day: date!.toISOString().split('T')[0],
timestamp: +date!,
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
habitId: +selectedHabitId.currentKey,
userId: user?.id as string,
time: null, // TODO: Add time picker
});
Expand All @@ -85,13 +83,15 @@ const AddOccurrenceDialog = ({
return (
<Modal
role="add-occurrence-modal"
isOpen={open}
isOpen={isOpen}
onClose={handleClose}
isDismissable={false}
placement="center"
onClick={(e) => e.stopPropagation()}
>
<ModalContent>
<ModalHeader>
Add habit entry for {format(date, 'iii, LLL d, y')}
{date && `Add habit entry for ${format(date || '', 'iii, LLL d, y')}`}
</ModalHeader>
<ModalBody>
<Select
Expand Down
28 changes: 19 additions & 9 deletions src/components/calendar/Calendar.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { generateCalendarRange } from '@helpers';
import { useDocumentTitle } from '@hooks';
import { CalendarDate, GregorianCalendar } from '@internationalized/date';
import { useDisclosure } from '@nextui-org/react';
import { useOccurrencesStore } from '@stores';
import { capitalizeFirstLetter } from '@utils';
import clsx from 'clsx';
import React from 'react';
import { type AriaButtonProps, useCalendar, useLocale } from 'react-aria';
import { useCalendarState } from 'react-stately';
Expand All @@ -29,7 +31,11 @@ const Calendar = () => {
});
const { calendarProps, prevButtonProps, nextButtonProps, title } =
useCalendar({}, state);
const [dayModalDialogOpen, setDayModalDialogOpen] = React.useState(false);
const {
isOpen: isAddOccurrenceDialogOpen,
onOpen: openAddOccurrenceDialog,
onClose: closeDayOccurrenceDialog,
} = useDisclosure();
const [activeDate, setActiveDate] = React.useState<Date | null>(null);

React.useEffect(() => {
Expand Down Expand Up @@ -86,21 +92,25 @@ const Calendar = () => {
monthIndex: number,
fullYear: number
) => {
setDayModalDialogOpen(true);
openAddOccurrenceDialog();
setActiveDate(new Date(fullYear, monthIndex - 1, dateNumber, 12));
};

const handleDayModalDialogClose = () => {
setActiveDate(null);
setDayModalDialogOpen(false);
window.setTimeout(() => {
closeDayOccurrenceDialog();
setActiveDate(null);
}, 0);
};

const calendarContainerClassName = clsx(
'flex h-full w-full max-w-full flex-1 flex-col gap-2 p-0 pb-8 lg:gap-4 lg:px-16 lg:py-4',
isAddOccurrenceDialogOpen && 'pointer-events-none'
);

return (
<>
<div
{...calendarProps}
className="flex h-full w-full max-w-full flex-1 flex-col gap-2 p-0 pb-8 lg:gap-4 lg:px-16 lg:py-4"
>
<div {...calendarProps} className={calendarContainerClassName}>
<CalendarHeader
activeMonthLabel={capitalizeFirstLetter(activeMonthLabel)}
activeYear={activeYear}
Expand All @@ -119,7 +129,7 @@ const Calendar = () => {
</div>

<AddOccurrenceDialog
open={dayModalDialogOpen}
isOpen={isAddOccurrenceDialogOpen}
onClose={handleDayModalDialogClose}
date={activeDate}
/>
Expand Down
6 changes: 0 additions & 6 deletions src/components/habit/edit-habit/EditHabitDialog.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ describe(EditHabitDialog.name, () => {
});

const props: EditHabitDialogProps = {
open: true,
onClose: jest.fn(),
habit: {
id: 7,
Expand Down Expand Up @@ -72,11 +71,6 @@ describe(EditHabitDialog.name, () => {
expect(queryByRole('dialog')).toBeNull();
});

it('should not render if open is false', () => {
const { queryByRole } = render(<EditHabitDialog {...props} open={false} />);
expect(queryByRole('dialog')).toBeNull();
});

it('should call onClose when closed', async () => {
const onClose = jest.fn();
const { getByLabelText } = render(
Expand Down
24 changes: 12 additions & 12 deletions src/components/habit/edit-habit/EditHabitDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,24 +11,20 @@ import {
Select,
SelectItem,
Textarea,
useDisclosure,
} from '@nextui-org/react';
import { useHabitsStore, useTraitsStore } from '@stores';
import { useUser } from '@supabase/auth-helpers-react';
import { toEventLike } from '@utils';
import React from 'react';

export type EditHabitDialogProps = {
open: boolean;
habit: Habit | null;
onClose?: () => void;
};

const EditHabitDialog = ({
open = false,
habit,
onClose,
}: EditHabitDialogProps) => {
const [isOpen, setIsOpen] = React.useState(false);
const EditHabitDialog = ({ habit, onClose }: EditHabitDialogProps) => {
const { isOpen, onOpen, onClose: onDisclosureClose } = useDisclosure();
const [name, handleNameChange] = useTextField();
const [description, handleDescriptionChange] = useTextField();
const [traitId, setTraitId] = React.useState('');
Expand All @@ -37,8 +33,12 @@ const EditHabitDialog = ({
const user = useUser();

React.useEffect(() => {
setIsOpen(open);
}, [open]);
if (habit) {
onOpen();
} else {
onClose?.();
}
}, [habit, onOpen, onClose]);

React.useEffect(() => {
if (habit) {
Expand All @@ -48,12 +48,12 @@ const EditHabitDialog = ({
}
}, [habit, handleNameChange, handleDescriptionChange]);

if (!isOpen || !habit) {
if (!habit) {
return null;
}

const handleClose = () => {
setIsOpen(false);
onDisclosureClose();
onClose?.();
};

Expand All @@ -75,7 +75,7 @@ const EditHabitDialog = ({

return (
<Modal
isOpen={open}
isOpen={isOpen}
onClose={handleClose}
role="edit-habit-modal"
data-visible={isOpen.toString()}
Expand Down
6 changes: 1 addition & 5 deletions src/components/habit/habits-page/HabitsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -187,11 +187,7 @@ const HabitsPage = () => {
))}
</TableBody>
</Table>
<EditHabitDialog
open={!!habitToEdit}
onClose={handleEditEnd}
habit={habitToEdit}
/>
<EditHabitDialog onClose={handleEditEnd} habit={habitToEdit} />
<AddHabitDialogButton />
<ConfirmDialog
open={!!habitToRemove}
Expand Down

0 comments on commit 6dda919

Please sign in to comment.