fix(frontend): add missing priorities field to skin snapshots UI

priorities was present in the model, API, and LLM prompt but never
surfaced in the frontend — add it to create/edit forms, read view,
AI photo pre-fill, and page.server.ts actions.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Piotr Oleszczyk 2026-03-01 19:58:38 +01:00
parent 75ef1bca56
commit 17eaa5d1bd
4 changed files with 42 additions and 2 deletions

View file

@ -223,6 +223,9 @@
"skin_sebumCheeks": "Sebum cheeks (15)", "skin_sebumCheeks": "Sebum cheeks (15)",
"skin_activeConcerns": "Active concerns (comma-separated)", "skin_activeConcerns": "Active concerns (comma-separated)",
"skin_activeConcernsPlaceholder": "acne, redness, dehydration", "skin_activeConcernsPlaceholder": "acne, redness, dehydration",
"skin_priorities": "Priorities (comma-separated)",
"skin_prioritiesPlaceholder": "strengthen barrier, reduce redness",
"skin_prioritiesLabel": "Priorities",
"skin_notes": "Notes", "skin_notes": "Notes",
"skin_addSnapshot": "Add snapshot", "skin_addSnapshot": "Add snapshot",
"skin_snapshotAdded": "Snapshot added.", "skin_snapshotAdded": "Snapshot added.",

View file

@ -223,6 +223,9 @@
"skin_sebumCheeks": "Sebum policzki (15)", "skin_sebumCheeks": "Sebum policzki (15)",
"skin_activeConcerns": "Aktywne problemy (przecinek)", "skin_activeConcerns": "Aktywne problemy (przecinek)",
"skin_activeConcernsPlaceholder": "trądzik, zaczerwienienie, odwodnienie", "skin_activeConcernsPlaceholder": "trądzik, zaczerwienienie, odwodnienie",
"skin_priorities": "Priorytety (przecinek)",
"skin_prioritiesPlaceholder": "wzmocnić barierę, redukować zaczerwienienie",
"skin_prioritiesLabel": "Priorytety",
"skin_notes": "Notatki", "skin_notes": "Notatki",
"skin_addSnapshot": "Dodaj wpis", "skin_addSnapshot": "Dodaj wpis",
"skin_snapshotAdded": "Wpis dodany.", "skin_snapshotAdded": "Wpis dodany.",

View file

@ -19,6 +19,7 @@ export const actions: Actions = {
const sensitivity_level = form.get('sensitivity_level') as string; const sensitivity_level = form.get('sensitivity_level') as string;
const barrier_state = form.get('barrier_state') as string; const barrier_state = form.get('barrier_state') as string;
const active_concerns_raw = form.get('active_concerns') as string; const active_concerns_raw = form.get('active_concerns') as string;
const priorities_raw = form.get('priorities') as string;
if (!snapshot_date) { if (!snapshot_date) {
return fail(400, { error: 'Date is required' }); return fail(400, { error: 'Date is required' });
@ -29,11 +30,16 @@ export const actions: Actions = {
.map((c) => c.trim()) .map((c) => c.trim())
.filter(Boolean) ?? []; .filter(Boolean) ?? [];
const priorities = priorities_raw
?.split(',')
.map((p) => p.trim())
.filter(Boolean) ?? [];
const skin_type = form.get('skin_type') as string; const skin_type = form.get('skin_type') as string;
const sebum_tzone = form.get('sebum_tzone') as string; const sebum_tzone = form.get('sebum_tzone') as string;
const sebum_cheeks = form.get('sebum_cheeks') as string; const sebum_cheeks = form.get('sebum_cheeks') as string;
const body: Record<string, unknown> = { snapshot_date, active_concerns }; const body: Record<string, unknown> = { snapshot_date, active_concerns, priorities };
if (overall_state) body.overall_state = overall_state; if (overall_state) body.overall_state = overall_state;
if (texture) body.texture = texture; if (texture) body.texture = texture;
if (notes) body.notes = notes; if (notes) body.notes = notes;
@ -63,6 +69,7 @@ export const actions: Actions = {
const sensitivity_level = form.get('sensitivity_level') as string; const sensitivity_level = form.get('sensitivity_level') as string;
const barrier_state = form.get('barrier_state') as string; const barrier_state = form.get('barrier_state') as string;
const active_concerns_raw = form.get('active_concerns') as string; const active_concerns_raw = form.get('active_concerns') as string;
const priorities_raw = form.get('priorities') as string;
const skin_type = form.get('skin_type') as string; const skin_type = form.get('skin_type') as string;
const sebum_tzone = form.get('sebum_tzone') as string; const sebum_tzone = form.get('sebum_tzone') as string;
const sebum_cheeks = form.get('sebum_cheeks') as string; const sebum_cheeks = form.get('sebum_cheeks') as string;
@ -74,7 +81,12 @@ export const actions: Actions = {
.map((c) => c.trim()) .map((c) => c.trim())
.filter(Boolean) ?? []; .filter(Boolean) ?? [];
const body: Record<string, unknown> = { active_concerns }; const priorities = priorities_raw
?.split(',')
.map((p) => p.trim())
.filter(Boolean) ?? [];
const body: Record<string, unknown> = { active_concerns, priorities };
if (snapshot_date) body.snapshot_date = snapshot_date; if (snapshot_date) body.snapshot_date = snapshot_date;
if (overall_state) body.overall_state = overall_state; if (overall_state) body.overall_state = overall_state;
if (texture) body.texture = texture; if (texture) body.texture = texture;

View file

@ -66,6 +66,7 @@
let sebumTzone = $state(''); let sebumTzone = $state('');
let sebumCheeks = $state(''); let sebumCheeks = $state('');
let activeConcernsRaw = $state(''); let activeConcernsRaw = $state('');
let prioritiesRaw = $state('');
let notes = $state(''); let notes = $state('');
// Edit state // Edit state
@ -80,6 +81,7 @@
let editSebumTzone = $state(''); let editSebumTzone = $state('');
let editSebumCheeks = $state(''); let editSebumCheeks = $state('');
let editActiveConcernsRaw = $state(''); let editActiveConcernsRaw = $state('');
let editPrioritiesRaw = $state('');
let editNotes = $state(''); let editNotes = $state('');
function startEdit(snap: (typeof data.snapshots)[number]) { function startEdit(snap: (typeof data.snapshots)[number]) {
@ -94,6 +96,7 @@
editSebumTzone = snap.sebum_tzone != null ? String(snap.sebum_tzone) : ''; editSebumTzone = snap.sebum_tzone != null ? String(snap.sebum_tzone) : '';
editSebumCheeks = snap.sebum_cheeks != null ? String(snap.sebum_cheeks) : ''; editSebumCheeks = snap.sebum_cheeks != null ? String(snap.sebum_cheeks) : '';
editActiveConcernsRaw = snap.active_concerns?.join(', ') ?? ''; editActiveConcernsRaw = snap.active_concerns?.join(', ') ?? '';
editPrioritiesRaw = snap.priorities?.join(', ') ?? '';
editNotes = snap.notes ?? ''; editNotes = snap.notes ?? '';
showForm = false; showForm = false;
} }
@ -132,6 +135,7 @@
if (r.sebum_tzone != null) sebumTzone = String(r.sebum_tzone); if (r.sebum_tzone != null) sebumTzone = String(r.sebum_tzone);
if (r.sebum_cheeks != null) sebumCheeks = String(r.sebum_cheeks); if (r.sebum_cheeks != null) sebumCheeks = String(r.sebum_cheeks);
if (r.active_concerns?.length) activeConcernsRaw = r.active_concerns.join(', '); if (r.active_concerns?.length) activeConcernsRaw = r.active_concerns.join(', ');
if (r.priorities?.length) prioritiesRaw = r.priorities.join(', ');
if (r.notes) notes = r.notes; if (r.notes) notes = r.notes;
aiPanelOpen = false; aiPanelOpen = false;
} catch (e) { } catch (e) {
@ -299,6 +303,10 @@
<Label for="active_concerns">{m["skin_activeConcerns"]()}</Label> <Label for="active_concerns">{m["skin_activeConcerns"]()}</Label>
<Input id="active_concerns" name="active_concerns" placeholder={m["skin_activeConcernsPlaceholder"]()} bind:value={activeConcernsRaw} /> <Input id="active_concerns" name="active_concerns" placeholder={m["skin_activeConcernsPlaceholder"]()} bind:value={activeConcernsRaw} />
</div> </div>
<div class="space-y-1 col-span-2">
<Label for="priorities">{m["skin_priorities"]()}</Label>
<Input id="priorities" name="priorities" placeholder={m["skin_prioritiesPlaceholder"]()} bind:value={prioritiesRaw} />
</div>
<div class="space-y-1 col-span-2"> <div class="space-y-1 col-span-2">
<Label for="notes">{m.skin_notes()}</Label> <Label for="notes">{m.skin_notes()}</Label>
<Input id="notes" name="notes" bind:value={notes} /> <Input id="notes" name="notes" bind:value={notes} />
@ -399,6 +407,10 @@
<Label for="edit_active_concerns">{m["skin_activeConcerns"]()}</Label> <Label for="edit_active_concerns">{m["skin_activeConcerns"]()}</Label>
<Input id="edit_active_concerns" name="active_concerns" placeholder={m["skin_activeConcernsPlaceholder"]()} bind:value={editActiveConcernsRaw} /> <Input id="edit_active_concerns" name="active_concerns" placeholder={m["skin_activeConcernsPlaceholder"]()} bind:value={editActiveConcernsRaw} />
</div> </div>
<div class="space-y-1 col-span-2">
<Label for="edit_priorities">{m["skin_priorities"]()}</Label>
<Input id="edit_priorities" name="priorities" placeholder={m["skin_prioritiesPlaceholder"]()} bind:value={editPrioritiesRaw} />
</div>
<div class="space-y-1 col-span-2"> <div class="space-y-1 col-span-2">
<Label for="edit_notes">{m.skin_notes()}</Label> <Label for="edit_notes">{m.skin_notes()}</Label>
<Input id="edit_notes" name="notes" bind:value={editNotes} /> <Input id="edit_notes" name="notes" bind:value={editNotes} />
@ -459,6 +471,16 @@
{/each} {/each}
</div> </div>
{/if} {/if}
{#if snap.priorities?.length}
<div class="mt-2">
<p class="text-xs text-muted-foreground mb-1">{m["skin_prioritiesLabel"]()}</p>
<div class="flex flex-wrap gap-1">
{#each snap.priorities as p (p)}
<Badge variant="outline" class="text-xs">{p}</Badge>
{/each}
</div>
</div>
{/if}
{#if snap.notes} {#if snap.notes}
<p class="mt-2 text-sm text-muted-foreground">{snap.notes}</p> <p class="mt-2 text-sm text-muted-foreground">{snap.notes}</p>
{/if} {/if}