diff --git a/app/dashboard/page.test.tsx b/app/dashboard/page.test.tsx index 9bce6a0..c11e8a1 100644 --- a/app/dashboard/page.test.tsx +++ b/app/dashboard/page.test.tsx @@ -12,53 +12,61 @@ vi.mock('next/navigation', () => ({ // Mock ResizeObserver global.ResizeObserver = class ResizeObserver { - observe() {} - unobserve() {} - disconnect() {} + observe(): void { + /* noop */ + } + unobserve(): void { + /* noop */ + } + disconnect(): void { + /* noop */ + } }; // Mock fetch global.fetch = vi.fn(); -const createTestQueryClient = () => new QueryClient({ - defaultOptions: { - queries: { - retry: false, +const createTestQueryClient = () => + new QueryClient({ + defaultOptions: { + queries: { + retry: false, + }, }, - }, -}); + }); describe('Dashboard', () => { beforeEach(() => { vi.clearAllMocks(); - + // Mock Auth Response - (global.fetch as any).mockImplementation((url: string) => { + vi.mocked(global.fetch).mockImplementation((url: string | URL | Request) => { if (url === '/api/auth') { return Promise.resolve({ json: () => Promise.resolve({ authenticated: true, token: 'test-token' }), - }); + } as Response); } if (url === '/api/habits') { return Promise.resolve({ ok: true, - json: () => Promise.resolve({ - habits: [ - { - id: 1, - name: 'Test Habit', - type: 'neutral', - totalLogs: 5, - logsLastWeek: 2, - logsLastMonth: 5, - createdAt: new Date().toISOString(), - lastLoggedAt: new Date().toISOString(), - } - ] - }), - }); + json: () => + Promise.resolve({ + habits: [ + { + id: 1, + name: 'Test Habit', + type: 'neutral', + totalLogs: 5, + logsLastWeek: 2, + logsLastMonth: 5, + createdAt: new Date().toISOString(), + lastLoggedAt: new Date().toISOString(), + }, + ], + }), + } as Response); } - return Promise.resolve({ ok: true, json: () => Promise.resolve({}) }); + return Promise.resolve({ ok: true, json: () => Promise.resolve({}) } as Response); }); }); @@ -66,7 +74,7 @@ describe('Dashboard', () => { render( - + , ); await waitFor(() => { @@ -78,7 +86,7 @@ describe('Dashboard', () => { render( - + , ); await waitFor(() => { @@ -99,7 +107,7 @@ describe('Dashboard', () => { render( - + , ); await waitFor(() => { diff --git a/app/dashboard/page.tsx b/app/dashboard/page.tsx index af42ef5..fbcddf6 100644 --- a/app/dashboard/page.tsx +++ b/app/dashboard/page.tsx @@ -77,12 +77,12 @@ interface HabitResponse { export default function Dashboard() { const router = useRouter(); const queryClient = useQueryClient(); - + // State const [showNewHabitDialog, setShowNewHabitDialog] = useState(false); const [newHabitName, setNewHabitName] = useState(''); const [newHabitType, setNewHabitType] = useState<'positive' | 'neutral' | 'negative'>('neutral'); - + const [editingHabit, setEditingHabit] = useState(null); const [editHabitName, setEditHabitName] = useState(''); const [editHabitType, setEditHabitType] = useState<'positive' | 'neutral' | 'negative'>('neutral'); @@ -109,7 +109,9 @@ export default function Dashboard() { const interval = setInterval(() => { setCurrentTime(Date.now()); }, 60000); - return () => clearInterval(interval); + return () => { + clearInterval(interval); + }; }, []); // Fetch habits @@ -140,9 +142,9 @@ export default function Dashboard() { }); // Undo log mutation - const undoLogMutation = useMutation({ + const undoLogMutation = useMutation({ mutationFn: async (habitId: number): Promise => { - const res = await fetch(`/api/habits/${habitId}/log`, { + const res = await fetch(`/api/habits/${String(habitId)}/log`, { method: 'DELETE', }); if (!res.ok) throw new Error('Failed to undo log'); @@ -172,9 +174,13 @@ export default function Dashboard() { }); // Update habit mutation - const updateHabitMutation = useMutation({ + const updateHabitMutation = useMutation< + HabitResponse, + Error, + { id: number; name: string; type: string } + >({ mutationFn: async ({ id, name, type }): Promise => { - const res = await fetch(`/api/habits/${id}`, { + const res = await fetch(`/api/habits/${String(id)}`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name, type }), @@ -189,9 +195,9 @@ export default function Dashboard() { }); // Delete habit mutation - const deleteHabitMutation = useMutation({ + const deleteHabitMutation = useMutation({ mutationFn: async (id: number): Promise => { - const res = await fetch(`/api/habits/${id}`, { + const res = await fetch(`/api/habits/${String(id)}`, { method: 'DELETE', }); if (!res.ok) throw new Error('Failed to delete habit'); @@ -450,8 +456,10 @@ export default function Dashboard() { variant="ghost" size="icon" className="h-8 w-8 opacity-0 transition-opacity group-hover:opacity-100 hover:bg-black/20" - onClick={(e) => openEditDialog(e, habit)} - data-testid={`edit-habit-${habit.id}`} + onClick={(e) => { + openEditDialog(e, habit); + }} + data-testid={`edit-habit-${String(habit.id)}`} > @@ -463,34 +471,34 @@ export default function Dashboard() { {/* Last logged */}
- - + + {habit.lastLoggedAt - ? formatDistanceToNow(new Date(habit.lastLoggedAt), { addSuffix: true }) - : 'Never logged'} - + ? formatDistanceToNow(new Date(habit.lastLoggedAt), { addSuffix: true }) + : 'Never logged'} +
{habit.lastLoggedAt && ( - - - - - - -

Undo last log

-
-
-
+ + + + + + +

Undo last log

+
+
+
)}
@@ -553,9 +561,14 @@ export default function Dashboard() { )} - + {/* Edit Habit Dialog */} - !open && setEditingHabit(null)}> + { + if (!open) setEditingHabit(null); + }} + > Edit Habit @@ -569,7 +582,9 @@ export default function Dashboard() { setEditHabitName(e.target.value)} + onChange={(e) => { + setEditHabitName(e.target.value); + }} className="border-zinc-800 bg-zinc-900" /> @@ -608,47 +623,56 @@ export default function Dashboard() { -
+
{showDeleteConfirm ? ( -
- - -
+
+ + +
) : ( )} -
-
- - -
+
+
+ + +