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.
This commit is contained in:
2026-07-20 07:28:12 +02:00
parent db71c4a331
commit 6f7ae9e5bb
2 changed files with 24 additions and 6 deletions
+20
View File
@@ -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}.`;
}
+4 -6
View File
@@ -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,