# Proposed Implementation Plan ## Phase 1: Settings Update * **`frontend/src/hooks/useSettings.ts`**: Add `sessionsPerPage` to the settings state and define a default value (e.g., 10). * **`frontend/src/components/stats/SettingsPopover.tsx`**: * Update the props and local state to include `sessionsPerPage`. * Add a dropdown in the settings UI for selecting "Results per page" (e.g., 5, 10, 25, 50). * **`frontend/src/components/stats/StatsPage.tsx`**: Update the `onSave` handler to persist the new `sessionsPerPage` setting. ## Phase 2: Pagination UI and Logic * **`frontend/src/components/stats/Pagination.tsx` (New Component)**: Implement a "Google-style" pagination component with `Previous`, page numbers, and `Next` buttons. * **`frontend/src/components/stats/SessionList.tsx`**: * Integrate `useSettings` to fetch the selected page size. * Implement local pagination logic (managing `currentPage`). * Slice the session data to show only the current page's items. * Render the new `Pagination` component at the bottom of the list. ## Phase 3: Verification * Verify that changing "Results per page" in Settings correctly updates the list. * Confirm pagination navigation (Prev/Next/Numbers) works as expected and handles edge cases (e.g., first/last page). I will use multiple sub-agents to execute these tasks in parallel. --- The user wants to implement client-side pagination for "Sleep Sessions". Plan: 1. Update `useSettings` to include `sessionsPerPage`. 2. Update `SettingsPopover` to allow users to change `sessionsPerPage`. 3. Update `StatsPage`'s `onSave` in `SettingsPopover` to include the new setting. 4. Create a new `Pagination` component. 5. Update `SessionList` to use pagination logic and the new component. 6. Verify with Playwright and screenshots. I'll start by using `todowrite` to track progress. Then I will launch sub-agents. Sub-agents: 1. `explore` (or `general`) for Phase 1 (Settings). 2. `general` for Phase 2 (Pagination component and SessionList logic). 3. `general` for Phase 3 (Playwright verification). Wait, the user said "use as many sub-agents as possible". I'll split it. Task 1: Update settings (useSettings, SettingsPopover, StatsPage). Task 2: Implement Pagination component and integrate it into SessionList. Task 3: Write Playwright tests to verify functionality and take screenshots. Let's start with `todowrite`. ## TODOS ```json { "todos": [ { "content": "Update useSettings to include sessionsPerPage", "priority": "high", "status": "pending" }, { "content": "Update SettingsPopover to allow changing sessionsPerPage", "priority": "high", "status": "pending" }, { "content": "Update StatsPage to persist sessionsPerPage in onSave", "priority": "high", "status": "pending" }, { "content": "Create Pagination component in frontend/src/components/stats/Pagination.tsx", "priority": "high", "status": "pending" }, { "content": "Update SessionList to implement client-side pagination logic and use Pagination component", "priority": "high", "status": "pending" }, { "content": "Write Playwright tests to verify pagination and take screenshots", "priority": "medium", "status": "pending" } ] } ``` ## Current progress (git diff) ``` diff --git a/frontend/src/components/stats/SessionList.tsx b/frontend/src/components/stats/SessionList.tsx index 374e41c..2bd6ea7 100644 --- a/frontend/src/components/stats/SessionList.tsx +++ b/frontend/src/components/stats/SessionList.tsx @@ -1,15 +1,29 @@ import React, { useState } from 'react'; import { useSessions } from '../../hooks/useSleepSession'; +import { useSettings } from '../../hooks/useSettings'; +import { Pagination } from './Pagination'; import { Edit2, Check, X, Trash2 } from 'lucide-react'; import type { SleepSessionRead } from '../../types'; import { formatDateTime, toLocalDatetimeInputValue, getDurationMinutes, formatMinutes } from '../../utils/time'; export function SessionList() { const { sessions, isLoading, updateSession, deleteSession, isDeleting } = useSessions(); + const { settings } = useSettings(); + const sessionsPerPage = settings.sessionsPerPage; + + const [currentPage, setCurrentPage] = useState(1); const [editingId, setEditingId] = useState(null); const [editStart, setEditStart] = useState(''); const [editEnd, setEditEnd] = useState(''); + const totalPages = Math.ceil(sessions.length / sessionsPerPage); + const clampedPage = Math.max(1, Math.min(currentPage, totalPages || 1)); + + const paginatedSessions = sessions.slice( + (clampedPage - 1) * sessionsPerPage, + clampedPage * sessionsPerPage + ); + if (isLoading) return
Loading sessions...
; if (!sessions.length) return
No sessions recorded.
; @@ -55,7 +69,7 @@ export function SessionList() {

Sleep Sessions

- {sessions.map((s) => ( + {paginatedSessions.map((s) => (
{editingId === s.id ? (
@@ -140,6 +154,13 @@ export function SessionList() {
))}
+ {sessions.length > sessionsPerPage && ( + + )}
); } diff --git a/frontend/src/components/stats/SettingsPopover.tsx b/frontend/src/components/stats/SettingsPopover.tsx index 005a302..8031392 100644 --- a/frontend/src/components/stats/SettingsPopover.tsx +++ b/frontend/src/components/stats/SettingsPopover.tsx @@ -6,15 +6,17 @@ interface SettingsPopoverProps { dayEnd: string; wakeupRef: string; bedtimeRef: string; - onSave: (settings: { dayStart: string; dayEnd: string; wakeupRef: string; bedtimeRef: string }) => void; + sessionsPerPage: number; + onSave: (settings: { dayStart: string; dayEnd: string; wakeupRef: string; bedtimeRef: string; sessionsPerPage: number }) => void; } -export function SettingsPopover({ dayStart, dayEnd, wakeupRef, bedtimeRef, onSave }: SettingsPopoverProps) { +export function SettingsPopover({ dayStart, dayEnd, wakeupRef, bedtimeRef, sessionsPerPage, onSave }: SettingsPopoverProps) { const [isOpen, setIsOpen] = useState(false); const [localDayStart, setLocalDayStart] = useState(dayStart); const [localDayEnd, setLocalDayEnd] = useState(dayEnd); const [localWakeupRef, setLocalWakeupRef] = useState(wakeupRef); const [localBedtimeRef, setLocalBedtimeRef] = useState(bedtimeRef); + const [localSessionsPerPage, setLocalSessionsPerPage] = useState(sessionsPerPage); const popoverRef = useRef(null); useEffect(() => { @@ -22,7 +24,8 @@ export function SettingsPopover({ dayStart, dayEnd, wakeupRef, bedtimeRef, onSav setLocalDayEnd(dayEnd); setLocalWakeupRef(wakeupRef); setLocalBedtimeRef(bedtimeRef); - }, [dayStart, dayEnd, wakeupRef, bedtimeRef]); + setLocalSessionsPerPage(sessionsPerPage); + }, [dayStart, dayEnd, wakeupRef, bedtimeRef, sessionsPerPage]); useEffect(() => { const handleClickOutside = (e: MouseEvent) => { @@ -42,6 +45,7 @@ export function SettingsPopover({ dayStart, dayEnd, wakeupRef, bedtimeRef, onSav dayEnd: localDayEnd, wakeupRef: localWakeupRef, bedtimeRef: localBedtimeRef, + sessionsPerPage: localSessionsPerPage, }); setIsOpen(false); }; @@ -65,44 +69,58 @@ export function SettingsPopover({ dayStart, dayEnd, wakeupRef, bedtimeRef, onSav
- - setLocalDayStart(e.target.value)} - className="w-full p-2 border rounded-md text-sm" -/> + + setLocalDayStart(e.target.value)} + className="w-full p-2 border rounded-md text-sm" + />
- - setLocalDayEnd(e.target.value)} - className="w-full p-2 border rounded-md text-sm" -/> + + setLocalDayEnd(e.target.value)} + className="w-full p-2 border rounded-md text-sm" + />
- - setLocalWakeupRef(e.target.value)} - className="w-full p-2 border rounded-md text-sm" -/> + + setLocalWakeupRef(e.target.value)} + className="w-full p-2 border rounded-md text-sm" + />
- - setLocalBedtimeRef(e.target.value)} - className="w-full p-2 border rounded-md text-sm" -/> + + setLocalBedtimeRef(e.target.value)} + className="w-full p-2 border rounded-md text-sm" + /> +
+
+ +
diff --git a/frontend/src/components/stats/StatsPage.tsx b/frontend/src/components/stats/StatsPage.tsx index 2516d55..e3518c8 100644 --- a/frontend/src/components/stats/StatsPage.tsx +++ b/frontend/src/components/stats/StatsPage.tsx @@ -27,18 +27,20 @@ const StatsPage: React.FC = () => {

Statistics

Overview of sleep patterns and trends

- { - update('dayStart', s.dayStart); - update('dayEnd', s.dayEnd); - update('wakeupRef', s.wakeupRef); - update('bedtimeRef', s.bedtimeRef); - }} - /> + { + update('dayStart', s.dayStart); + update('dayEnd', s.dayEnd); + update('wakeupRef', s.wakeupRef); + update('bedtimeRef', s.bedtimeRef); + update('sessionsPerPage', s.sessionsPerPage); + }} + />
diff --git a/frontend/src/hooks/useSettings.ts b/frontend/src/hooks/useSettings.ts index c587fb3..d95899b 100644 --- a/frontend/src/hooks/useSettings.ts +++ b/frontend/src/hooks/useSettings.ts @@ -8,6 +8,7 @@ interface Settings { wakeupRef: string; bedtimeRef: string; statsInterval: number; + sessionsPerPage: number; } const DEFAULT_SETTINGS: Settings = { @@ -16,6 +17,7 @@ const DEFAULT_SETTINGS: Settings = { wakeupRef: '04:00', bedtimeRef: '19:00', statsInterval: 7, + sessionsPerPage: 10, }; export function useSettings() { ``` ## Last command The last command you ran was this: ``` npx playwright test frontend/tests/e2e/pagination.spec.ts --reporter=list ``` so please run this again and see the output, as this might help us know where to pick things up.