feat(insights): add load, error, and empty states to the vitals dashboard

Render a skeleton row matching the resolved tile height while the derived
batch loads so the grid reserves its final footprint with no layout shift.
Hide the section heading until there is content (or a skeleton placeholder)
under it, removing the stranded-heading layout shift on empty data. Surface
an inline error message plus a Retry that refetches the shared batch query
when the batch fails, instead of the whole surface silently vanishing. Mark
the tiles container aria-busy while loading and aria-live polite, matching
the insights a11y pattern.
This commit is contained in:
Marc-André Bombeck committed 2026-06-03 08:56:19 +02:00
1 parent 786454ee2f
commit 5ae7aa7570
8 files changed
+214 -30

No files matched your search

+2
View File
@@ -2526,6 +2526,8 @@
},
"vitals": {
"sectionTitle": "Deine Vitalwerte",
"loadingLabel": "Vitalwerte werden geladen",
"loadError": "Deine Vitalwerte konnten gerade nicht geladen werden.",
"building": "Typischer Bereich entsteht — {count} von {target} Tagen",
"typicalRange": "Typisch für dich: {low}–{high}",
"fitnessYounger": "Ausdauer wie ~{years} J. jünger",
+2
View File
@@ -2526,6 +2526,8 @@
},
"vitals": {
"sectionTitle": "Your vitals",
"loadingLabel": "Loading your vitals",
"loadError": "Could not load your vitals right now.",
"building": "Building your typical range — {count} of {target} days",
"typicalRange": "Typical for you: {low}–{high}",
"fitnessYounger": "Cardio fitness of someone ~{years} yr younger",
+2
View File
@@ -2526,6 +2526,8 @@
},
"vitals": {
"sectionTitle": "Tus constantes",
"loadingLabel": "Cargando tus constantes",
"loadError": "No se pudieron cargar tus constantes en este momento.",
"building": "Creando tu rango habitual — {count} de {target} días",
"typicalRange": "Habitual para ti: {low}–{high}",
"fitnessYounger": "Forma cardiovascular de alguien ~{years} años más joven",
+2
View File
@@ -2526,6 +2526,8 @@
},
"vitals": {
"sectionTitle": "Vos constantes",
"loadingLabel": "Chargement de vos constantes",
"loadError": "Impossible de charger vos constantes pour le moment.",
"building": "Construction de votre plage habituelle — {count} sur {target} jours",
"typicalRange": "Habituel pour vous : {low}–{high}",
"fitnessYounger": "Forme cardio d'une personne ~{years} ans plus jeune",
+2
View File
@@ -2526,6 +2526,8 @@
},
"vitals": {
"sectionTitle": "I tuoi parametri vitali",
"loadingLabel": "Caricamento dei tuoi parametri vitali",
"loadError": "Al momento non è stato possibile caricare i tuoi parametri vitali.",
"building": "Creazione del tuo intervallo abituale — {count} di {target} giorni",
"typicalRange": "Abituale per te: {low}–{high}",
"fitnessYounger": "Forma cardio di chi ha ~{years} anni in meno",
+2
View File
@@ -2526,6 +2526,8 @@
},
"vitals": {
"sectionTitle": "Twoje parametry życiowe",
"loadingLabel": "Wczytywanie parametrów życiowych",
"loadError": "Nie udało się teraz wczytać Twoich parametrów życiowych.",
"building": "Budowanie Twojego typowego zakresu — {count} z {target} dni",
"typicalRange": "Typowe dla Ciebie: {low}–{high}",
"fitnessYounger": "Kondycja jak u osoby ~{years} lat młodszej",