Skip to content

Commit

Permalink
feat(habits): migrate context to zustand store (#115)
Browse files Browse the repository at this point in the history
* feat(habits): migrate context to zustand store

* Remove Habits context
  • Loading branch information
domhhv authored Oct 24, 2024
1 parent 543cf36 commit e7f94e9
Show file tree
Hide file tree
Showing 21 changed files with 279 additions and 372 deletions.
6 changes: 2 additions & 4 deletions src/components/Providers.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { HabitsProvider, OccurrencesProvider } from '@context';
import { OccurrencesProvider } from '@context';
import { supabaseClient } from '@helpers';
import { NextUIProvider } from '@nextui-org/react';
import { SessionContextProvider } from '@supabase/auth-helpers-react';
Expand All @@ -15,9 +15,7 @@ const LowerProviders = ({ children }: ProviderProps) => {

return (
<NextUIProvider navigate={navigate}>
<HabitsProvider>
<OccurrencesProvider>{children}</OccurrencesProvider>
</HabitsProvider>
<OccurrencesProvider>{children}</OccurrencesProvider>
</NextUIProvider>
);
};
Expand Down
54 changes: 22 additions & 32 deletions src/components/calendar/CalendarHeader.test.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { HabitsProvider, OccurrencesProvider } from '@context';
import { OccurrencesProvider } from '@context';
import { render } from '@testing-library/react';
import React from 'react';

Expand All @@ -25,62 +25,52 @@ describe(CalendarHeader.name, () => {

it.skip('should render month and year', () => {
const { getByText } = render(
<HabitsProvider>
<OccurrencesProvider>
<CalendarHeader {...props} />
</OccurrencesProvider>
</HabitsProvider>
<OccurrencesProvider>
<CalendarHeader {...props} />
</OccurrencesProvider>
);
expect(getByText('January 2022')).toBeInTheDocument();
});

it.skip('should disable previous button', () => {
const { getByRole } = render(
<HabitsProvider>
<OccurrencesProvider>
<CalendarHeader
{...props}
prevButtonProps={{ ...props.prevButtonProps, disabled: true }}
/>
</OccurrencesProvider>
</HabitsProvider>
<OccurrencesProvider>
<CalendarHeader
{...props}
prevButtonProps={{ ...props.prevButtonProps, disabled: true }}
/>
</OccurrencesProvider>
);
expect(getByRole('navigate-back')).toBeDisabled();
});

it.skip('should disable next button', () => {
const { getByRole } = render(
<HabitsProvider>
<OccurrencesProvider>
<CalendarHeader
{...props}
nextButtonProps={{ ...props.nextButtonProps, disabled: true }}
/>
</OccurrencesProvider>
</HabitsProvider>
<OccurrencesProvider>
<CalendarHeader
{...props}
nextButtonProps={{ ...props.nextButtonProps, disabled: true }}
/>
</OccurrencesProvider>
);
expect(getByRole('navigate-forward')).toBeDisabled();
});

it.skip('should call onNavigateBack', () => {
const { getByRole } = render(
<HabitsProvider>
<OccurrencesProvider>
<CalendarHeader {...props} />
</OccurrencesProvider>
</HabitsProvider>
<OccurrencesProvider>
<CalendarHeader {...props} />
</OccurrencesProvider>
);
getByRole('navigate-back').click();
expect(props.onNavigateBack).toHaveBeenCalled();
});

it.skip('should call onNavigateForward', () => {
const { getByRole } = render(
<HabitsProvider>
<OccurrencesProvider>
<CalendarHeader {...props} />
</OccurrencesProvider>
</HabitsProvider>
<OccurrencesProvider>
<CalendarHeader {...props} />
</OccurrencesProvider>
);
getByRole('navigate-forward').click();
expect(props.onNavigateForward).toHaveBeenCalled();
Expand Down
6 changes: 3 additions & 3 deletions src/components/calendar/CalendarHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { useHabits, useOccurrences } from '@context';
import { useOccurrences } from '@context';
import { useScreenSize } from '@hooks';
import { Select, SelectItem, Button } from '@nextui-org/react';
import { ArrowFatLeft, ArrowFatRight } from '@phosphor-icons/react';
import { useTraitsStore } from '@stores';
import { useTraitsStore, useHabitsStore } from '@stores';
import { useUser } from '@supabase/auth-helpers-react';
import React from 'react';

Expand Down Expand Up @@ -51,7 +51,7 @@ const CalendarHeader = ({
onNavigateToYear,
onResetFocusedDate,
}: CalendarHeaderProps) => {
const { habits } = useHabits();
const { habits } = useHabitsStore();
const { traits } = useTraitsStore();
const { filteredBy, filterBy } = useOccurrences();
const user = useUser();
Expand Down
28 changes: 16 additions & 12 deletions src/components/calendar/DayHabitModalDialog.test.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { useHabits, useOccurrences } from '@context';
import { useOccurrences } from '@context';
import { useHabitsStore } from '@stores';
import { useUser } from '@supabase/auth-helpers-react';
import { fireEvent, render, waitFor } from '@testing-library/react';
import { makeTestHabit } from '@tests';
Expand All @@ -9,10 +10,13 @@ import DayHabitModalDialog from './DayHabitModalDialog';

jest.mock('@context', () => ({
useOccurrences: jest.fn(),
useHabits: jest.fn(),
useSnackbar: jest.fn().mockReturnValue({ showSnackbar: jest.fn() }),
}));

jest.mock('@stores', () => ({
useHabitsStore: jest.fn(),
}));

jest.mock('@supabase/auth-helpers-react', () => ({
useUser: jest.fn(),
}));
Expand All @@ -36,7 +40,7 @@ describe(DayHabitModalDialog.name, () => {
});

it('should render', () => {
(useHabits as jest.Mock).mockReturnValue({ habits: [] });
(useHabitsStore as unknown as jest.Mock).mockReturnValue({ habits: [] });
(useUser as jest.Mock).mockReturnValue({ id: '1' });
(format as jest.Mock).mockReturnValue('2021-01-01');
(useOccurrences as jest.Mock).mockReturnValue({
Expand All @@ -48,7 +52,7 @@ describe(DayHabitModalDialog.name, () => {
});

it('should not render if date is null', () => {
(useHabits as jest.Mock).mockReturnValue({ habits: [] });
(useHabitsStore as unknown as jest.Mock).mockReturnValue({ habits: [] });
(useUser as jest.Mock).mockReturnValue({ id: '1' });
(format as jest.Mock).mockReturnValue('2021-01-01');
(useOccurrences as jest.Mock).mockReturnValue({
Expand All @@ -62,7 +66,7 @@ describe(DayHabitModalDialog.name, () => {
});

it('should not render if open is false', () => {
(useHabits as jest.Mock).mockReturnValue({ habits: [] });
(useHabitsStore as unknown as jest.Mock).mockReturnValue({ habits: [] });
(useUser as jest.Mock).mockReturnValue({ id: '1' });
(format as jest.Mock).mockReturnValue('2021-01-01');
(useOccurrences as jest.Mock).mockReturnValue({
Expand All @@ -76,7 +80,7 @@ describe(DayHabitModalDialog.name, () => {
});

it('should not render if date is null', () => {
(useHabits as jest.Mock).mockReturnValue({ habits: [] });
(useHabitsStore as unknown as jest.Mock).mockReturnValue({ habits: [] });
(useUser as jest.Mock).mockReturnValue({ id: '1' });
(format as jest.Mock).mockReturnValue('2021-01-01');
(useOccurrences as jest.Mock).mockReturnValue({
Expand All @@ -90,7 +94,7 @@ describe(DayHabitModalDialog.name, () => {
});

it('if no habits are available, should show a message', () => {
(useHabits as jest.Mock).mockReturnValue({ habits: [] });
(useHabitsStore as unknown as jest.Mock).mockReturnValue({ habits: [] });
(useUser as jest.Mock).mockReturnValue({ id: '1' });
(format as jest.Mock).mockReturnValue('2021-01-01');
(useOccurrences as jest.Mock).mockReturnValue({
Expand All @@ -102,7 +106,7 @@ describe(DayHabitModalDialog.name, () => {
});

it('should render habit options', () => {
(useHabits as jest.Mock).mockReturnValue({
(useHabitsStore as unknown as jest.Mock).mockReturnValue({
habits: [makeTestHabit()],
});
(useUser as jest.Mock).mockReturnValue({ id: '1' });
Expand All @@ -116,7 +120,7 @@ describe(DayHabitModalDialog.name, () => {
});

it.skip('should select habit', async () => {
(useHabits as jest.Mock).mockReturnValue({
(useHabitsStore as unknown as jest.Mock).mockReturnValue({
habits: [makeTestHabit({ id: 42 })],
});
(useUser as jest.Mock).mockReturnValue({ id: '1' });
Expand All @@ -137,7 +141,7 @@ describe(DayHabitModalDialog.name, () => {
});

it('on close, should call onClose', () => {
(useHabits as jest.Mock).mockReturnValue({
(useHabitsStore as unknown as jest.Mock).mockReturnValue({
habits: [makeTestHabit()],
});
(useUser as jest.Mock).mockReturnValue({ id: '1' });
Expand All @@ -152,7 +156,7 @@ describe(DayHabitModalDialog.name, () => {
});

it.skip('on close, should unselect habit', () => {
(useHabits as jest.Mock).mockReturnValue({
(useHabitsStore as unknown as jest.Mock).mockReturnValue({
habits: [makeTestHabit()],
});
(useUser as jest.Mock).mockReturnValue({ id: '1' });
Expand All @@ -174,7 +178,7 @@ describe(DayHabitModalDialog.name, () => {
});

it.skip('on submit, should call addOccurrence with proper arguments', () => {
(useHabits as jest.Mock).mockReturnValue({
(useHabitsStore as unknown as jest.Mock).mockReturnValue({
habits: [makeTestHabit()],
});
(useUser as jest.Mock).mockReturnValue({ id: '1' });
Expand Down
5 changes: 3 additions & 2 deletions src/components/calendar/DayHabitModalDialog.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useOccurrences, useHabits } from '@context';
import { useOccurrences } from '@context';
import {
Button,
Modal,
Expand All @@ -9,6 +9,7 @@ import {
Select,
SelectItem,
} from '@nextui-org/react';
import { useHabitsStore } from '@stores';
import { useUser } from '@supabase/auth-helpers-react';
import { format } from 'date-fns';
import React, { type MouseEventHandler } from 'react';
Expand All @@ -24,7 +25,7 @@ const DayHabitModalDialog = ({
onClose,
date,
}: DayHabitModalDialogProps) => {
const { habits } = useHabits();
const { habits } = useHabitsStore();
const user = useUser();
const { addOccurrence, addingOccurrence } = useOccurrences();
const [selectedHabitIds, setSelectedHabitIds] = React.useState<string[]>([]);
Expand Down
27 changes: 13 additions & 14 deletions src/components/habit/add-habit/AddHabitDialogButton.test.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,19 @@
import { useHabits } from '@context';
import { StorageBuckets, uploadFile } from '@services';
// import { useSnackbarsStore } from '@stores';
import { useSnackbarsStore, useHabitsStore } from '@stores';
import { useUser } from '@supabase/auth-helpers-react';
import { act, fireEvent, render, waitFor } from '@testing-library/react';
import React from 'react';

import AddHabitDialogButton from './AddHabitDialogButton';

jest.mock('@context', () => ({
useHabits: jest.fn().mockReturnValue({ updateHabit: jest.fn() }),
useSnackbar: jest.fn().mockReturnValue({ showSnackbar: jest.fn() }),
useTraits: jest.fn().mockReturnValue({
traits: [{ id: 1, slug: 'trait-slug', name: 'Trait' }],
}),
}));

jest.mock('@stores', () => ({
useSnackbarsStore: jest.fn(),
useHabitsStore: jest.fn(),
useTraitsStore: jest.fn(),
}));

jest.mock('@services', () => ({
Expand All @@ -33,7 +30,7 @@ jest.mock('@supabase/auth-helpers-react', () => ({

describe(AddHabitDialogButton.name, () => {
it.skip('should handle data enter and dialog close', () => {
(useHabits as jest.Mock).mockReturnValue({
(useHabitsStore as unknown as jest.Mock).mockReturnValue({
updateHabit: jest.fn(),
fetchingHabits: false,
});
Expand Down Expand Up @@ -78,7 +75,7 @@ describe(AddHabitDialogButton.name, () => {
});

it.skip('should not set habit icon if empty file uploaded', () => {
(useHabits as jest.Mock).mockReturnValue({
(useHabitsStore as unknown as jest.Mock).mockReturnValue({
updateHabit: jest.fn(),
fetchingHabits: false,
});
Expand All @@ -98,7 +95,9 @@ describe(AddHabitDialogButton.name, () => {

it.skip('should call addHabit on form submit', () => {
const mockAddHabit = jest.fn().mockReturnValue(Promise.resolve({ id: 1 }));
(useHabits as jest.Mock).mockReturnValue({ addHabit: mockAddHabit });
(useHabitsStore as unknown as jest.Mock).mockReturnValue({
addHabit: mockAddHabit,
});
(useUser as jest.Mock).mockReturnValue({
id: '4c6b7c3b-ec2f-45fb-8c3a-df16f7a4b3aa',
});
Expand All @@ -120,20 +119,20 @@ describe(AddHabitDialogButton.name, () => {
.fn()
.mockReturnValue(Promise.resolve({ id: 1234 }));
const mockUpdateHabit = jest.fn().mockReturnValue(Promise.resolve({}));
// const mockShowSnackbar = jest.fn();
const mockShowSnackbar = jest.fn();
(uploadFile as jest.Mock).mockReturnValue(
Promise.resolve({ data: { path: 'icon-path' } })
);
(useHabits as jest.Mock).mockReturnValue({
(useHabitsStore as unknown as jest.Mock).mockReturnValue({
addHabit: mockAddHabit,
updateHabit: mockUpdateHabit,
});
(useUser as jest.Mock).mockReturnValue({
id: 'uuid-42',
});
// (useSnackbarsStore as jest.Mock).mockReturnValue({
// showSnackbar: mockShowSnackbar,
// });
(useSnackbarsStore as unknown as jest.Mock).mockReturnValue({
showSnackbar: mockShowSnackbar,
});

const { getByRole, getByTestId, getByLabelText } = render(
<AddHabitDialogButton />
Expand Down
5 changes: 2 additions & 3 deletions src/components/habit/add-habit/AddHabitDialogButton.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { AddCustomTraitModal, VisuallyHiddenInput } from '@components';
import { useHabits } from '@context';
import { useTextField, useFileField } from '@hooks';
import {
Button,
Expand All @@ -14,14 +13,14 @@ import {
Textarea,
} from '@nextui-org/react';
import { CloudArrowUp, Plus } from '@phosphor-icons/react';
import { useTraitsStore } from '@stores';
import { useHabitsStore, useTraitsStore } from '@stores';
import { useUser } from '@supabase/auth-helpers-react';
import React from 'react';

const AddHabitDialogButton = () => {
const user = useUser();
const { traits } = useTraitsStore();
const { fetchingHabits, addingHabit, addHabit } = useHabits();
const { fetchingHabits, addingHabit, addHabit } = useHabitsStore();
const [open, setOpen] = React.useState(false);
const [name, handleNameChange, clearName] = useTextField();
const [description, handleDescriptionChange, clearDescription] =
Expand Down
Loading

0 comments on commit e7f94e9

Please sign in to comment.