mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-04-09 04:19:27 -07:00
feat(stats): expose 365d trends range in dashboard UI
Add '365d' to the client TrendRange union, the TimeRange hook type, and the DateRangeSelector segmented control so users can select a 365-day window in the trends dashboard.
This commit is contained in:
@@ -53,7 +53,7 @@ export function DateRangeSelector({
|
|||||||
<div className="flex items-center gap-4 text-sm">
|
<div className="flex items-center gap-4 text-sm">
|
||||||
<SegmentedControl
|
<SegmentedControl
|
||||||
label="Range"
|
label="Range"
|
||||||
options={['7d', '30d', '90d', 'all'] as TimeRange[]}
|
options={['7d', '30d', '90d', '365d', 'all'] as TimeRange[]}
|
||||||
value={range}
|
value={range}
|
||||||
onChange={onRangeChange}
|
onChange={onRangeChange}
|
||||||
formatLabel={(r) => (r === 'all' ? 'All' : r)}
|
formatLabel={(r) => (r === 'all' ? 'All' : r)}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { useState, useEffect } from 'react';
|
|||||||
import { getStatsClient } from './useStatsApi';
|
import { getStatsClient } from './useStatsApi';
|
||||||
import type { TrendsDashboardData } from '../types/stats';
|
import type { TrendsDashboardData } from '../types/stats';
|
||||||
|
|
||||||
export type TimeRange = '7d' | '30d' | '90d' | 'all';
|
export type TimeRange = '7d' | '30d' | '90d' | '365d' | 'all';
|
||||||
export type GroupBy = 'day' | 'month';
|
export type GroupBy = 'day' | 'month';
|
||||||
|
|
||||||
export function useTrends(range: TimeRange, groupBy: GroupBy) {
|
export function useTrends(range: TimeRange, groupBy: GroupBy) {
|
||||||
|
|||||||
@@ -115,6 +115,55 @@ test('getTrendsDashboard requests the chart-ready trends endpoint with range and
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('getTrendsDashboard accepts 365d range and builds correct URL', async () => {
|
||||||
|
const originalFetch = globalThis.fetch;
|
||||||
|
let seenUrl = '';
|
||||||
|
globalThis.fetch = (async (input: RequestInfo | URL) => {
|
||||||
|
seenUrl = String(input);
|
||||||
|
return new Response(
|
||||||
|
JSON.stringify({
|
||||||
|
activity: { watchTime: [], cards: [], words: [], sessions: [] },
|
||||||
|
progress: {
|
||||||
|
watchTime: [],
|
||||||
|
sessions: [],
|
||||||
|
words: [],
|
||||||
|
newWords: [],
|
||||||
|
cards: [],
|
||||||
|
episodes: [],
|
||||||
|
lookups: [],
|
||||||
|
},
|
||||||
|
ratios: { lookupsPerHundred: [] },
|
||||||
|
animePerDay: {
|
||||||
|
episodes: [],
|
||||||
|
watchTime: [],
|
||||||
|
cards: [],
|
||||||
|
words: [],
|
||||||
|
lookups: [],
|
||||||
|
lookupsPerHundred: [],
|
||||||
|
},
|
||||||
|
animeCumulative: {
|
||||||
|
watchTime: [],
|
||||||
|
episodes: [],
|
||||||
|
cards: [],
|
||||||
|
words: [],
|
||||||
|
},
|
||||||
|
patterns: {
|
||||||
|
watchTimeByDayOfWeek: [],
|
||||||
|
watchTimeByHour: [],
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
{ status: 200, headers: { 'Content-Type': 'application/json' } },
|
||||||
|
);
|
||||||
|
}) as typeof globalThis.fetch;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await apiClient.getTrendsDashboard('365d', 'day');
|
||||||
|
assert.equal(seenUrl, `${BASE_URL}/api/stats/trends/dashboard?range=365d&groupBy=day`);
|
||||||
|
} finally {
|
||||||
|
globalThis.fetch = originalFetch;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
test('getSessionEvents can request only specific event types', async () => {
|
test('getSessionEvents can request only specific event types', async () => {
|
||||||
const originalFetch = globalThis.fetch;
|
const originalFetch = globalThis.fetch;
|
||||||
let seenUrl = '';
|
let seenUrl = '';
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ export const apiClient = {
|
|||||||
fetchJson<NewAnimePerDay[]>(`/api/stats/trends/new-anime-per-day?limit=${limit}`),
|
fetchJson<NewAnimePerDay[]>(`/api/stats/trends/new-anime-per-day?limit=${limit}`),
|
||||||
getWatchTimePerAnime: (limit = 90) =>
|
getWatchTimePerAnime: (limit = 90) =>
|
||||||
fetchJson<WatchTimePerAnime[]>(`/api/stats/trends/watch-time-per-anime?limit=${limit}`),
|
fetchJson<WatchTimePerAnime[]>(`/api/stats/trends/watch-time-per-anime?limit=${limit}`),
|
||||||
getTrendsDashboard: (range: '7d' | '30d' | '90d' | 'all', groupBy: 'day' | 'month') =>
|
getTrendsDashboard: (range: '7d' | '30d' | '90d' | '365d' | 'all', groupBy: 'day' | 'month') =>
|
||||||
fetchJson<TrendsDashboardData>(
|
fetchJson<TrendsDashboardData>(
|
||||||
`/api/stats/trends/dashboard?range=${encodeURIComponent(range)}&groupBy=${encodeURIComponent(groupBy)}`,
|
`/api/stats/trends/dashboard?range=${encodeURIComponent(range)}&groupBy=${encodeURIComponent(groupBy)}`,
|
||||||
),
|
),
|
||||||
|
|||||||
Reference in New Issue
Block a user