From f47f72d81388a74d6d65e8a3951fc267447b4fbd Mon Sep 17 00:00:00 2001 From: wmcparla <183443443+wmcparla@users.noreply.github.com> Date: Fri, 13 Nov 2026 14:17:53 -0500 Subject: [PATCH] fix: offer the way back to the month from a day opened in the month grid #125 --- src/screens/CalendarScreen.tsx | 46 +++++++++++++++---- .../calendar-back-to-month-wiring.test.ts | 27 +++++++++++ 2 files changed, 63 insertions(+), 10 deletions(-) create mode 100644 src/screens/__tests__/calendar-back-to-month-wiring.test.ts diff --git a/src/screens/CalendarScreen.tsx b/src/screens/CalendarScreen.tsx index 711ae9dd..9ee026d5 100644 --- a/src/screens/CalendarScreen.tsx +++ b/src/screens/CalendarScreen.tsx @@ -13,8 +13,10 @@ import { import { SafeAreaView } from 'react-native-safe-area-context'; import { useFocusEffect } from '@react-navigation/native'; import { monthButtonAccessibilityLabel } from '../lib/calendar-a11y'; +import { useBackWhileFocused } from '../lib/use-back-while-focused'; import { TASK_CHIP_ID_PREFIX, multiDayCount } from '../lib/calendar-time-grid'; import { + ArrowLeft, ChevronDown, ChevronLeft, ChevronRight, @@ -518,9 +520,14 @@ export default function CalendarScreen() { jumpTo(displayNow()); }, [jumpTo]); + // Set when a day is opened from the month grid: the header then offers the + // way back to the month in the menu's place, as the webmail does on a phone. + const [returnToMonth, setReturnToMonth] = React.useState(false); + // Switching views keeps the period on screen in view. const changeViewMode = React.useCallback( (mode: ViewMode) => { + setReturnToMonth(false); if (mode === viewMode) return; const date = visibleDate ?? focus.date; setViewMode(mode); @@ -549,6 +556,7 @@ export default function CalendarScreen() { return; } setSelectedDate(date); + setReturnToMonth(false); setVisibleDate(null); setFocus((prev) => ({ date, nonce: prev.nonce + 1 })); setWindowState((prev) => @@ -618,12 +626,18 @@ export default function CalendarScreen() { // A day in the month grid or a day header in the week grids opens that // day, as in Google Calendar. const openDay = React.useCallback((date: Date) => { + setReturnToMonth(viewMode === 'month'); setSelectedDate(date); setViewMode('day'); setVisibleDate(null); setFocus((prev) => ({ date, nonce: prev.nonce + 1 })); setWindowState(freshScrollWindowState('day', date)); - }, []); + }, [viewMode]); + + // Back to the month of the day on screen; Android's back does the same. + const showBackToMonth = returnToMonth && viewMode === 'day'; + const backToMonth = React.useCallback(() => changeViewMode('month'), [changeViewMode]); + useBackWhileFocused(showBackToMonth, backToMonth); const openCreate = React.useCallback((date?: Date) => { setModalEvent(null); @@ -1023,15 +1037,27 @@ export default function CalendarScreen() { return ( - setSidebarVisible(true)} - hitSlop={8} - style={styles.headerBtn} - accessibilityRole="button" - accessibilityLabel={t('calendar.nav_open_menu', 'Open menu')} - > - - + {showBackToMonth ? ( + + + + ) : ( + setSidebarVisible(true)} + hitSlop={8} + style={styles.headerBtn} + accessibilityRole="button" + accessibilityLabel={t('calendar.nav_open_menu', 'Open menu')} + > + + + )} { + it('remembers that the day was opened from the month grid', () => { + expect(src).toMatch(/const openDay = React\.useCallback\(\(date: Date\) => \{\s+setReturnToMonth\(viewMode === 'month'\);/); + }); + + it('forgets it when the view is changed another way', () => { + expect(src).toMatch(/\(mode: ViewMode\) => \{\s+setReturnToMonth\(false\);\s+if \(mode === viewMode\) return;/); + expect(src).toMatch(/setSelectedDate\(date\);\s+setReturnToMonth\(false\);/); + }); + + it('shows the back button in the menu\'s place and handles Android back, only in Day view', () => { + expect(src).toMatch(/const showBackToMonth = returnToMonth && viewMode === 'day';/); + expect(src).toMatch(/useBackWhileFocused\(showBackToMonth, backToMonth\);/); + expect(src).toMatch(/\{showBackToMonth \? \(\s+