diff --git a/src/components/anniversary/AnniversaryList.tsx b/src/components/anniversary/AnniversaryList.tsx index 74803d8..0bf8a78 100644 --- a/src/components/anniversary/AnniversaryList.tsx +++ b/src/components/anniversary/AnniversaryList.tsx @@ -27,7 +27,10 @@ interface BuiltInHolidayEvent { export function AnniversaryList({ events, onEventClick, onAddClick }: AnniversaryListProps) { const anniversaries = events.filter((e) => e.type === 'anniversary'); - const showHolidays = useAppStore((state) => state.settings?.showHolidays ?? true); + const settings = useAppStore((state) => state.settings); + const showHolidays = settings?.showHolidays ?? true; + const holidayDisplayCount = settings?.holidayDisplayCount ?? 3; + const showStatutoryOnly = settings?.showStatutoryOnly ?? false; const scrollContainerRef = useRef(null); const [bottomPadding, setBottomPadding] = useState(0); @@ -108,17 +111,29 @@ export function AnniversaryList({ events, onEventClick, onAddClick }: Anniversar const nextYear = getHolidaysForYear(year + 1); // 合并今年和明年的节假日,按日期排序 - const allHolidays = [...holidays, ...nextYear].sort( + let allHolidays = [...holidays, ...nextYear].sort( (a, b) => a.date.getTime() - b.date.getTime() ); - // 只取未来90天内的节假日,显示最近3个 + // 应用过滤规则 + // 1. 如果 enabledHolidays 有内容,只显示选中的节假日 + const enabledHolidays = settings?.enabledHolidays; + if (enabledHolidays && enabledHolidays.length > 0) { + allHolidays = allHolidays.filter((h) => enabledHolidays.includes(h.id)); + } + + // 2. 如果开启了仅显示法定节假日 + if (showStatutoryOnly) { + allHolidays = allHolidays.filter((h) => h.isStatutory); + } + + // 只取未来90天内的节假日 const cutoffDate = new Date(now); cutoffDate.setDate(cutoffDate.getDate() + 90); return allHolidays .filter((h) => h.date >= now && h.date <= cutoffDate) - .slice(0, 3) + .slice(0, holidayDisplayCount) .map((h): BuiltInHolidayEvent => ({ id: `builtin-${h.id}`, title: h.name, @@ -129,7 +144,7 @@ export function AnniversaryList({ events, onEventClick, onAddClick }: Anniversar type: 'anniversary', is_builtin: true, })); - }, [showHolidays]); + }, [showHolidays, holidayDisplayCount, showStatutoryOnly, settings]); // 合并用户纪念日和内置节假日 const allAnniversaries = useMemo(() => { diff --git a/src/pages/SettingsPage.tsx b/src/pages/SettingsPage.tsx index 0cc9922..d892515 100644 --- a/src/pages/SettingsPage.tsx +++ b/src/pages/SettingsPage.tsx @@ -1,4 +1,4 @@ -import { useEffect, useState } from 'react'; +import { useEffect, useState, useMemo } from 'react'; import { Container, Title, @@ -9,13 +9,18 @@ import { Group, Button, Loader, + Select, + Divider, + Checkbox, + ScrollArea, } from '@mantine/core'; -import { IconArrowLeft, IconSettings, IconBell, IconRefresh, IconBellCheck } from '@tabler/icons-react'; +import { IconArrowLeft, IconSettings, IconBell, IconRefresh, IconBellCheck, IconChevronDown } from '@tabler/icons-react'; import { useNavigate } from 'react-router-dom'; import { useAppStore } from '../stores'; import { requestNotificationPermission, getNotificationPermission, isNotificationSupported } from '../services/notification'; import { syncRemindersToSW, triggerSWCheck } from '../services/swSync'; import { notifications } from '@mantine/notifications'; +import { getBuiltInHolidays } from '../constants/holidays'; export function SettingsPage() { const navigate = useNavigate(); @@ -23,6 +28,88 @@ export function SettingsPage() { const updateSettings = useAppStore((state) => state.updateSettings); const [permissionStatus, setPermissionStatus] = useState<'granted' | 'denied' | 'default'>('default'); const [isRequesting, setIsRequesting] = useState(false); + const [holidayFilterExpanded, setHolidayFilterExpanded] = useState(false); + + // 获取所有节假日列表 + const allHolidays = useMemo(() => getBuiltInHolidays(), []); + + // 法定节假日 + const statutoryHolidays = useMemo( + () => allHolidays.filter((h) => h.isStatutory), + [allHolidays] + ); + + // 非法定节假日 + const nonStatutoryHolidays = useMemo( + () => allHolidays.filter((h) => !h.isStatutory), + [allHolidays] + ); + + // 处理节假日开关 + const handleHolidayToggle = (checked: boolean) => { + updateSettings({ showHolidays: checked }); + if (!checked) { + // 关闭时也可以收起筛选面板 + setHolidayFilterExpanded(false); + } + }; + + // 处理显示数量变化 + const handleDisplayCountChange = (value: string | null) => { + updateSettings({ holidayDisplayCount: value ? parseInt(value, 10) : 3 }); + }; + + // 处理仅显示法定节假日变化 + const handleStatutoryOnlyChange = (checked: boolean) => { + updateSettings({ showStatutoryOnly: checked }); + }; + + // 处理特定节假日选择 + const handleHolidaySelection = (holidayId: string, checked: boolean) => { + const currentEnabled = settings.enabledHolidays || []; + let newEnabled: string[]; + + if (checked) { + newEnabled = [...currentEnabled, holidayId]; + } else { + newEnabled = currentEnabled.filter((id) => id !== holidayId); + } + + updateSettings({ enabledHolidays: newEnabled }); + }; + + // 检查节假日是否被选中 + const isHolidaySelected = (holidayId: string) => { + const enabled = settings.enabledHolidays || []; + return enabled.includes(holidayId); + }; + + // 全选/取消全选 + const handleSelectAll = (checked: boolean) => { + if (checked) { + updateSettings({ enabledHolidays: allHolidays.map((h) => h.id) }); + } else { + updateSettings({ enabledHolidays: [] }); + } + }; + + // 选择所有法定节假日 + const handleSelectStatutory = (checked: boolean) => { + if (checked) { + const statutoryIds = statutoryHolidays.map((h) => h.id); + const currentEnabled = settings.enabledHolidays || []; + // 合并现有选择和法定节假日 + const newEnabled = [...new Set([...currentEnabled, ...statutoryIds])]; + updateSettings({ enabledHolidays: newEnabled }); + } else { + // 移除所有法定节假日 + const statutoryIds = new Set(statutoryHolidays.map((h) => h.id)); + const newEnabled = (settings.enabledHolidays || []).filter( + (id) => !statutoryIds.has(id) + ); + updateSettings({ enabledHolidays: newEnabled }); + } + }; // 页面加载时检查登录状态 useEffect(() => { @@ -170,18 +257,145 @@ export function SettingsPage() { 显示节假日 - 在纪念日列表中显示即将到来的节假日(最近3个) + 在纪念日列表中显示即将到来的节假日 updateSettings({ showHolidays: e.currentTarget.checked })} + onChange={(e) => handleHolidayToggle(e.currentTarget.checked)} size="sm" color="#1a1a1a" /> + {/* 节假日显示数量 */} + {settings.showHolidays && ( + + + 显示数量 + +