From c56eb7e7f30465d1dc2b4c85ae1c491b73e8a793 Mon Sep 17 00:00:00 2001 From: XShine555 Date: Mon, 20 Jul 2026 07:28:12 +0200 Subject: [PATCH] fix(web): resolve the greeting on the server It was picked with Math.random() in the component body, so SSR and the client rendered different text and hydration mismatched. Moving it to the load keeps the per-visit variety with both sides agreeing, and the six-level nested ternary becomes a lookup table. --- frontend/src/lib/server/greeting.ts | 20 ++++++++++++++++++++ frontend/src/routes/+page.server.ts | 10 ++++------ 2 files changed, 24 insertions(+), 6 deletions(-) create mode 100644 frontend/src/lib/server/greeting.ts diff --git a/frontend/src/lib/server/greeting.ts b/frontend/src/lib/server/greeting.ts new file mode 100644 index 0000000..30c8c54 --- /dev/null +++ b/frontend/src/lib/server/greeting.ts @@ -0,0 +1,20 @@ +const GREETINGS_BY_HOUR: { until: number; pool: string[] }[] = [ + { + until: 6, + pool: ['¿Aún despierto?', 'La noche también tiene banda sonora', 'Un ratito más, con música'] + }, + { until: 12, pool: ['Buenos días', 'Que empiece bien la mañana', 'Un nuevo día, una nueva lista'] }, + { until: 14, pool: ['Buenos días', 'El mediodía sabe mejor con música'] }, + { + until: 19, + pool: ['Buenas tardes', 'La tarde pide su banda sonora', 'Un respiro, con algo de música'] + }, + { until: 23, pool: ['Buenas noches', 'Hora de bajar el ritmo', 'Que la noche te acompañe'] }, + { until: 24, pool: ['¿Aún despierto?', 'La noche también tiene banda sonora'] } +]; + +export function pickGreeting(hour: number): string { + const pool = GREETINGS_BY_HOUR.find((slot) => hour < slot.until)?.pool ?? GREETINGS_BY_HOUR[0].pool; + const greeting = pool[Math.floor(Math.random() * pool.length)]; + return /[.!?]$/.test(greeting) ? greeting : `${greeting}.`; +} diff --git a/frontend/src/routes/+page.server.ts b/frontend/src/routes/+page.server.ts index 741cbbb..c739d2d 100644 --- a/frontend/src/routes/+page.server.ts +++ b/frontend/src/routes/+page.server.ts @@ -3,6 +3,7 @@ import { createApiClient, playlistCoverTrackIds } from '$lib/server/api'; import { fetchYoutubeFiller, shuffle } from '$lib/server/youtube'; import { addTrackAction, addYouTubeToPlaylistAction } from '$lib/server/playlistActions'; import { HOME_LATEST_PAGE_SIZE, YOUTUBE_FILLER_LIMIT } from '$lib/config'; +import { pickGreeting } from '$lib/server/greeting'; export const load: PageServerLoad = async ({ locals, fetch }) => { const api = createApiClient({ fetch, accessToken: locals.accessToken ?? undefined }); @@ -30,13 +31,10 @@ export const load: PageServerLoad = async ({ locals, fetch }) => { playlistItems.map((p) => p.id) ); - const novedades = shuffle( - (latest.data?.items ?? []).map((track) => ({ kind: 'local' as const, track })) - ); - return { - novedades, - novedadesHasNext: Boolean(latest.data?.hasNextPage), + greeting: pickGreeting(new Date().getHours()), + latest: shuffle((latest.data?.items ?? []).map((track) => ({ kind: 'local' as const, track }))), + latestHasNext: Boolean(latest.data?.hasNextPage), youtubeFiller: fetchYoutubeFiller(api, locals.accessToken, YOUTUBE_FILLER_LIMIT), playlists: playlistItems, trackIds,