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:
Davide Scaini
2026-04-27 15:37:09 +02:00
parent 87baf33815
commit 5e36806392
2 changed files with 33 additions and 14 deletions
+16 -2
View File
@@ -70,6 +70,7 @@ export { PAGE_SIZE };
export type ActivityFilter = {
sport: string; // '' = all sports
dateFrom: string; // '' = no lower bound; ISO-like 'YYYY-MM-DDTHHMMSSZ' for comparison
dateTo: string; // '' = no upper bound
sort: 'date' | 'distance' | 'elevation';
};
@@ -95,9 +96,10 @@ export function useFilteredActivities(filter: ActivityFilter, limit = PAGE_SIZE)
FROM activities
WHERE (? = '' OR json_extract(detail_json, '$.sport') = ?)
AND (? = '' OR json_extract(detail_json, '$.started_at') >= ?)
AND (? = '' OR json_extract(detail_json, '$.started_at') < ?)
ORDER BY ${order}
LIMIT ?
`, [filter.sport, filter.sport, filter.dateFrom, filter.dateFrom, limit]);
`, [filter.sport, filter.sport, filter.dateFrom, filter.dateFrom, filter.dateTo, filter.dateTo, limit]);
}
export function useFilteredCount(filter: ActivityFilter): number {
@@ -106,10 +108,22 @@ export function useFilteredCount(filter: ActivityFilter): number {
SELECT COUNT(*) as n FROM activities
WHERE (? = '' OR json_extract(detail_json, '$.sport') = ?)
AND (? = '' OR json_extract(detail_json, '$.started_at') >= ?)
`, [filter.sport, filter.sport, filter.dateFrom, filter.dateFrom]);
AND (? = '' OR json_extract(detail_json, '$.started_at') < ?)
`, [filter.sport, filter.sport, filter.dateFrom, filter.dateFrom, filter.dateTo, filter.dateTo]);
return row?.n ?? 0;
}
export function useActivityYears(): string[] {
const db = useSQLiteContext();
const rows = db.getAllSync<{ year: string }>(
`SELECT DISTINCT substr(json_extract(detail_json, '$.started_at'), 1, 4) AS year
FROM activities
WHERE json_extract(detail_json, '$.started_at') IS NOT NULL
ORDER BY year DESC`,
);
return rows.map(r => r.year).filter(Boolean);
}
export function useActivity(id: string): ActivityRow | null {
const db = useSQLiteContext();
return db.getFirstSync<ActivityRow>(