From db9baca508d78499e36f4f7e436f1bfa81b1313b Mon Sep 17 00:00:00 2001 From: brobert Date: Sun, 9 Nov 2025 23:15:27 +0100 Subject: [PATCH] feat: centralizar normalizeTime en core y exponerla en web para preferencias Co-authored-by: aider (openrouter/openai/gpt-5) --- apps/web/src/lib/server/datetime.ts | 9 +++++++- .../src/routes/api/me/preferences/+server.ts | 19 ++++----------- .../routes/app/preferences/+page.server.ts | 23 +------------------ src/utils/datetime.ts | 13 +++++++++++ 4 files changed, 27 insertions(+), 37 deletions(-) diff --git a/apps/web/src/lib/server/datetime.ts b/apps/web/src/lib/server/datetime.ts index 2adfdb2..80831c0 100644 --- a/apps/web/src/lib/server/datetime.ts +++ b/apps/web/src/lib/server/datetime.ts @@ -1,4 +1,4 @@ -import { toIsoSqlUTC as coreToIsoSqlUTC } from '../../../../../src/utils/datetime'; +import { toIsoSqlUTC as coreToIsoSqlUTC, normalizeTime as coreNormalizeTime } from '../../../../../src/utils/datetime'; /** * Serializa una fecha en UTC al formato SQL ISO "YYYY-MM-DD HH:MM:SS[.SSS]". @@ -8,6 +8,13 @@ export function toIsoSqlUTC(d: Date = new Date()): string { return coreToIsoSqlUTC(d); } +/** + * Normaliza una hora 'HH:mm'. Devuelve null si no es válida. + */ +export function normalizeTime(input: string | null | undefined): string | null { + return coreNormalizeTime(input); +} + /** * Devuelve YYYY-MM-DD en UTC (útil para consultas por rango de fecha). */ diff --git a/apps/web/src/routes/api/me/preferences/+server.ts b/apps/web/src/routes/api/me/preferences/+server.ts index 1121764..7a09318 100644 --- a/apps/web/src/routes/api/me/preferences/+server.ts +++ b/apps/web/src/routes/api/me/preferences/+server.ts @@ -1,5 +1,6 @@ import type { RequestHandler } from './$types'; import { getDb } from '$lib/server/db'; +import { normalizeTime } from '$lib/server/datetime'; export const GET: RequestHandler = async (event) => { // Requiere sesión @@ -36,15 +37,16 @@ export const POST: RequestHandler = async (event) => { return new Response('Unauthorized', { status: 401 }); } - let payload: any = null; + let payload: unknown = null; try { payload = await event.request.json(); } catch { return new Response('Bad Request', { status: 400 }); } + const body = payload && typeof payload === 'object' ? (payload as { freq?: unknown; time?: unknown }) : null; - const freqRaw = String(payload?.freq || '').trim().toLowerCase(); - const timeRaw = payload?.time == null ? null : String(payload.time).trim(); + const freqRaw = String(body?.freq ?? '').trim().toLowerCase(); + const timeRaw = body?.time == null ? null : String(body.time).trim(); const allowed = new Set(['off', 'daily', 'weekly', 'weekdays']); if (!allowed.has(freqRaw)) { @@ -54,17 +56,6 @@ export const POST: RequestHandler = async (event) => { }); } - function normalizeTime(input: string): string | null { - const m = /^\s*(\d{1,2}):(\d{1,2})\s*$/.exec(input || ''); - if (!m) return null; - const h = Number(m[1]); - const min = Number(m[2]); - if (!Number.isFinite(h) || !Number.isFinite(min)) return null; - if (h < 0 || h > 23 || min < 0 || min > 59) return null; - const hh = String(h).padStart(2, '0'); - const mm = String(min).padStart(2, '0'); - return `${hh}:${mm}`; - } const db = await getDb(); diff --git a/apps/web/src/routes/app/preferences/+page.server.ts b/apps/web/src/routes/app/preferences/+page.server.ts index 9a64e9b..dde52ce 100644 --- a/apps/web/src/routes/app/preferences/+page.server.ts +++ b/apps/web/src/routes/app/preferences/+page.server.ts @@ -1,6 +1,7 @@ import type { PageServerLoad, Actions } from './$types'; import { getDb } from '$lib/server/db'; import { redirect, fail } from '@sveltejs/kit'; +import { normalizeTime } from '$lib/server/datetime'; function ymdInTZ(d: Date, tz: string): string { const parts = new Intl.DateTimeFormat('en-GB', { @@ -28,17 +29,6 @@ function weekdayShortInTZ(d: Date, tz: string): string { return new Intl.DateTimeFormat('en-GB', { timeZone: tz, weekday: 'short' }).format(d); } -function normalizeTime(input: string): string | null { - const m = /^\s*(\d{1,2}):(\d{1,2})\s*$/.exec(input || ''); - if (!m) return null; - const h = Number(m[1]); - const min = Number(m[2]); - if (!Number.isFinite(h) || !Number.isFinite(min)) return null; - if (h < 0 || h > 23 || min < 0 || min > 59) return null; - const hh = String(h).padStart(2, '0'); - const mm = String(min).padStart(2, '0'); - return `${hh}:${mm}`; -} function computeNextReminder( freq: 'off' | 'daily' | 'weekly' | 'weekdays', @@ -123,17 +113,6 @@ export const actions: Actions = { return fail(400, { error: 'freq inválida' }); } - function normalizeTime(input: string): string | null { - const m = /^\s*(\d{1,2}):(\d{1,2})\s*$/.exec(input || ''); - if (!m) return null; - const h = Number(m[1]); - const min = Number(m[2]); - if (!Number.isFinite(h) || !Number.isFinite(min)) return null; - if (h < 0 || h > 23 || min < 0 || min > 59) return null; - const hh = String(h).padStart(2, '0'); - const mm = String(min).padStart(2, '0'); - return `${hh}:${mm}`; - } const db = await getDb(); let timeToSave: string | null = null; diff --git a/src/utils/datetime.ts b/src/utils/datetime.ts index c3d9a9b..c631b7e 100644 --- a/src/utils/datetime.ts +++ b/src/utils/datetime.ts @@ -1,3 +1,16 @@ export function toIsoSqlUTC(d: Date = new Date()): string { return d.toISOString().replace('T', ' ').replace('Z', ''); } + +export function normalizeTime(input: string | null | undefined): string | null { + const s = (input ?? '').trim(); + const m = /^(\d{1,2}):(\d{1,2})$/.exec(s); + if (!m) return null; + const h = Number(m[1]); + const min = Number(m[2]); + if (!Number.isFinite(h) || !Number.isFinite(min)) return null; + if (h < 0 || h > 23 || min < 0 || min > 59) return null; + const hh = String(h).padStart(2, '0'); + const mm = String(min).padStart(2, '0'); + return `${hh}:${mm}`; +}