Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 36 additions & 10 deletions src/screens/CalendarScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -549,6 +556,7 @@ export default function CalendarScreen() {
return;
}
setSelectedDate(date);
setReturnToMonth(false);
setVisibleDate(null);
setFocus((prev) => ({ date, nonce: prev.nonce + 1 }));
setWindowState((prev) =>
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -1023,15 +1037,27 @@ export default function CalendarScreen() {
return (
<SafeAreaView style={styles.container} edges={['top', 'left', 'right']}>
<View style={styles.header}>
<Pressable
onPress={() => setSidebarVisible(true)}
hitSlop={8}
style={styles.headerBtn}
accessibilityRole="button"
accessibilityLabel={t('calendar.nav_open_menu', 'Open menu')}
>
<Menu size={20} color={c.text} />
</Pressable>
{showBackToMonth ? (
<Pressable
onPress={backToMonth}
hitSlop={8}
style={styles.headerBtn}
accessibilityRole="button"
accessibilityLabel={t('calendar.back_to_month', 'Back to month')}
>
<ArrowLeft size={22} color={c.text} />
</Pressable>
) : (
<Pressable
onPress={() => setSidebarVisible(true)}
hitSlop={8}
style={styles.headerBtn}
accessibilityRole="button"
accessibilityLabel={t('calendar.nav_open_menu', 'Open menu')}
>
<Menu size={20} color={c.text} />
</Pressable>
)}
<Pressable
onPress={toggleMonthPanel}
style={styles.titleBtn}
Expand Down
27 changes: 27 additions & 0 deletions src/screens/__tests__/calendar-back-to-month-wiring.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { describe, expect, it } from 'vitest';
import fs from 'node:fs';
import path from 'node:path';

// #125: a day opened from the month grid offers the way back to the month,
// in the header and on Android's back. No React Native renderer in the test
// env, so this checks the wiring.

const src = fs.readFileSync(path.resolve(__dirname, '..', 'CalendarScreen.tsx'), 'utf8');

describe('calendar back to month wiring', () => {
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+<Pressable\s+onPress=\{backToMonth\}/);
expect(src).toMatch(/accessibilityLabel=\{t\('calendar\.back_to_month', 'Back to month'\)\}/);
});
});
Loading