feat(mobile): replace 'This year' with dynamic per-year pills in filter tab
Date row now shows All time | 7d | 30d | 6mo | 2026 | 2025 | ... derived from actual activity data. Year pills use a bounded [Jan 1, Jan 1+1) range via a new dateTo field on ActivityFilter; rolling-window presets keep an open upper bound.
This commit is contained in:
@@ -1,10 +1,9 @@
|
||||
import { useState } from 'react';
|
||||
import { FlatList, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native';
|
||||
import { PAGE_SIZE, useFilteredActivities, useFilteredCount, type ActivityFilter } from '@/db/queries';
|
||||
import { PAGE_SIZE, useActivityYears, useFilteredActivities, useFilteredCount, type ActivityFilter } from '@/db/queries';
|
||||
import { ActivityCard } from '@/components/ActivityCard';
|
||||
import { useTheme } from '@/ThemeContext';
|
||||
|
||||
type DatePreset = 'all' | '7d' | '30d' | '6mo' | 'year';
|
||||
type SortKey = 'date' | 'distance' | 'elevation';
|
||||
|
||||
const SPORTS = [
|
||||
@@ -16,12 +15,11 @@ const SPORTS = [
|
||||
{ value: 'walking', label: '🚶 Walking' },
|
||||
];
|
||||
|
||||
const DATE_PRESETS: { value: DatePreset; label: string }[] = [
|
||||
const DATE_PRESETS = [
|
||||
{ value: 'all', label: 'All time' },
|
||||
{ value: '7d', label: '7 days' },
|
||||
{ value: '30d', label: '30 days' },
|
||||
{ value: '6mo', label: '6 months' },
|
||||
{ value: 'year', label: 'This year' },
|
||||
];
|
||||
|
||||
const SORTS: { value: SortKey; label: string }[] = [
|
||||
@@ -30,26 +28,33 @@ const SORTS: { value: SortKey; label: string }[] = [
|
||||
{ value: 'elevation', label: 'Elevation' },
|
||||
];
|
||||
|
||||
function computeDateFrom(preset: DatePreset): string {
|
||||
if (preset === 'all') return '';
|
||||
function computeDateRange(preset: string): { dateFrom: string; dateTo: string } {
|
||||
if (preset === 'all') return { dateFrom: '', dateTo: '' };
|
||||
if (/^\d{4}$/.test(preset)) {
|
||||
const y = parseInt(preset, 10);
|
||||
return { dateFrom: `${y}-01-01T000000Z`, dateTo: `${y + 1}-01-01T000000Z` };
|
||||
}
|
||||
const pad = (n: number) => String(n).padStart(2, '0');
|
||||
const now = new Date();
|
||||
let d: Date;
|
||||
if (preset === '7d') d = new Date(now.getTime() - 7 * 86_400_000);
|
||||
else if (preset === '30d') d = new Date(now.getTime() - 30 * 86_400_000);
|
||||
else if (preset === '6mo') { d = new Date(now); d.setMonth(d.getMonth() - 6); }
|
||||
else d = new Date(now.getFullYear(), 0, 1);
|
||||
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T000000Z`;
|
||||
else { d = new Date(now); d.setMonth(d.getMonth() - 6); }
|
||||
return { dateFrom: `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T000000Z`, dateTo: '' };
|
||||
}
|
||||
|
||||
export default function SearchScreen() {
|
||||
const theme = useTheme();
|
||||
const [sport, setSport] = useState('');
|
||||
const [datePre, setDatePre] = useState<DatePreset>('all');
|
||||
const [datePre, setDatePre] = useState('all');
|
||||
const [sort, setSort] = useState<SortKey>('date');
|
||||
const [limit, setLimit] = useState(PAGE_SIZE);
|
||||
|
||||
const filter: ActivityFilter = { sport, dateFrom: computeDateFrom(datePre), sort };
|
||||
const years = useActivityYears();
|
||||
const dateOptions = [...DATE_PRESETS, ...years.map(y => ({ value: y, label: y }))];
|
||||
|
||||
const { dateFrom, dateTo } = computeDateRange(datePre);
|
||||
const filter: ActivityFilter = { sport, dateFrom, dateTo, sort };
|
||||
const activities = useFilteredActivities(filter, limit);
|
||||
const total = useFilteredCount(filter);
|
||||
const hasMore = activities.length < total;
|
||||
@@ -71,7 +76,7 @@ export default function SearchScreen() {
|
||||
|
||||
<ScrollView horizontal showsHorizontalScrollIndicator={false}
|
||||
style={styles.pillScroll} contentContainerStyle={styles.pillRow}>
|
||||
{DATE_PRESETS.map(d => (
|
||||
{dateOptions.map(d => (
|
||||
<Pill key={d.value} label={d.label} active={datePre === d.value} accent={theme.accent}
|
||||
onPress={() => { setDatePre(d.value); setLimit(PAGE_SIZE); }} />
|
||||
))}
|
||||
|
||||
Reference in New Issue
Block a user