export type EtcDetailView = 'records' | 'bills'; export interface EtcDrillContext { view: EtcDetailView; startDate: string; endDate: string; search: string; page: number; } interface LocationParts { pathname: string; search: string; hash: string; } const DATE_PATTERN = /^\d{4}-\d{2}-\d{2}$/; function validDate(value: string | null): string { if (!value || !DATE_PATTERN.test(value)) return ''; const [year, month, day] = value.split('-').map(Number); const date = new Date(Date.UTC(year, month - 1, day)); return date.getUTCFullYear() === year && date.getUTCMonth() === month - 1 && date.getUTCDate() === day ? value : ''; } function validPage(value: string | null): number { if (!value || !/^\d+$/.test(value)) return 1; const parsed = Number(value); return Number.isSafeInteger(parsed) && parsed > 0 ? parsed : 1; } export function parseEtcDrillContext(search: string): EtcDrillContext { const params = new URLSearchParams(search); const rawSearch = params.get('etcSearch')?.trim() ?? ''; const firstDate = validDate(params.get('etcStart')); const secondDate = validDate(params.get('etcEnd')); const startDate = firstDate && secondDate && firstDate > secondDate ? secondDate : firstDate; const endDate = firstDate && secondDate && firstDate > secondDate ? firstDate : secondDate; return { view: params.get('etcView') === 'bills' ? 'bills' : 'records', startDate, endDate, search: rawSearch.length <= 128 ? rawSearch : '', page: validPage(params.get('etcPage')), }; } export function buildEtcDrillUrl(location: LocationParts, context: EtcDrillContext): string { const params = new URLSearchParams(location.search); for (const key of ['etcView', 'etcStart', 'etcEnd', 'etcSearch', 'etcPage']) params.delete(key); params.set('etcView', context.view); if (context.startDate) params.set('etcStart', context.startDate); if (context.endDate) params.set('etcEnd', context.endDate); const search = context.search.trim(); if (search && search.length <= 128) params.set('etcSearch', search); if (context.page > 1) params.set('etcPage', String(context.page)); const query = params.toString(); return `${location.pathname}${query ? `?${query}` : ''}${location.hash}`; }