feat(frontend): group product selector by category in routine step forms
Products in the Add/Edit step dropdowns are now grouped by category (Cleanser → Serum → Moisturizer → …) using SelectGroup/SelectGroupHeading, and sorted alphabetically by brand then name within each group. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
78c67b6179
commit
3aa03b412b
1 changed files with 50 additions and 5 deletions
|
|
@ -10,7 +10,14 @@
|
||||||
import { Card, CardContent, CardHeader, CardTitle } from '$lib/components/ui/card';
|
import { Card, CardContent, CardHeader, CardTitle } from '$lib/components/ui/card';
|
||||||
import { Input } from '$lib/components/ui/input';
|
import { Input } from '$lib/components/ui/input';
|
||||||
import { Label } from '$lib/components/ui/label';
|
import { Label } from '$lib/components/ui/label';
|
||||||
import { Select, SelectContent, SelectItem, SelectTrigger } from '$lib/components/ui/select';
|
import {
|
||||||
|
Select,
|
||||||
|
SelectContent,
|
||||||
|
SelectGroup,
|
||||||
|
SelectGroupHeading,
|
||||||
|
SelectItem,
|
||||||
|
SelectTrigger
|
||||||
|
} from '$lib/components/ui/select';
|
||||||
import { Separator } from '$lib/components/ui/separator';
|
import { Separator } from '$lib/components/ui/separator';
|
||||||
|
|
||||||
let { data, form }: { data: PageData; form: ActionData } = $props();
|
let { data, form }: { data: PageData; form: ActionData } = $props();
|
||||||
|
|
@ -103,6 +110,34 @@
|
||||||
let selectedProductId = $state('');
|
let selectedProductId = $state('');
|
||||||
|
|
||||||
const GROOMING_ACTIONS: GroomingAction[] = ['shaving_razor', 'shaving_oneblade', 'dermarolling'];
|
const GROOMING_ACTIONS: GroomingAction[] = ['shaving_razor', 'shaving_oneblade', 'dermarolling'];
|
||||||
|
|
||||||
|
const CATEGORY_ORDER = [
|
||||||
|
'cleanser', 'toner', 'essence', 'serum', 'moisturizer',
|
||||||
|
'spf', 'mask', 'exfoliant', 'spot_treatment', 'oil',
|
||||||
|
'hair_treatment', 'tool', 'other'
|
||||||
|
];
|
||||||
|
|
||||||
|
function formatCategory(cat: string): string {
|
||||||
|
return cat.charAt(0).toUpperCase() + cat.slice(1).replace(/_/g, ' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
const groupedProducts = $derived.by(() => {
|
||||||
|
const groups = new Map<string, typeof products>();
|
||||||
|
for (const p of products) {
|
||||||
|
const key = p.category ?? 'other';
|
||||||
|
if (!groups.has(key)) groups.set(key, []);
|
||||||
|
groups.get(key)!.push(p);
|
||||||
|
}
|
||||||
|
for (const list of groups.values()) {
|
||||||
|
list.sort((a, b) => {
|
||||||
|
const b_cmp = (a.brand ?? '').localeCompare(b.brand ?? '');
|
||||||
|
return b_cmp !== 0 ? b_cmp : a.name.localeCompare(b.name);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return CATEGORY_ORDER
|
||||||
|
.filter((c) => groups.has(c))
|
||||||
|
.map((c) => [c, groups.get(c)!] as const);
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:head><title>Routine {routine.routine_date} {routine.part_of_day.toUpperCase()} — innercontext</title></svelte:head>
|
<svelte:head><title>Routine {routine.routine_date} {routine.part_of_day.toUpperCase()} — innercontext</title></svelte:head>
|
||||||
|
|
@ -150,8 +185,13 @@
|
||||||
{/if}
|
{/if}
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
{#each products as p (p.id)}
|
{#each groupedProducts as [cat, items]}
|
||||||
<SelectItem value={p.id}>{p.name} ({p.brand})</SelectItem>
|
<SelectGroup>
|
||||||
|
<SelectGroupHeading>{formatCategory(cat)}</SelectGroupHeading>
|
||||||
|
{#each items as p (p.id)}
|
||||||
|
<SelectItem value={p.id}>{p.name} · {p.brand}</SelectItem>
|
||||||
|
{/each}
|
||||||
|
</SelectGroup>
|
||||||
{/each}
|
{/each}
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
|
|
@ -202,8 +242,13 @@
|
||||||
{/if}
|
{/if}
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
{#each products as p (p.id)}
|
{#each groupedProducts as [cat, items]}
|
||||||
<SelectItem value={p.id}>{p.name} ({p.brand})</SelectItem>
|
<SelectGroup>
|
||||||
|
<SelectGroupHeading>{formatCategory(cat)}</SelectGroupHeading>
|
||||||
|
{#each items as p (p.id)}
|
||||||
|
<SelectItem value={p.id}>{p.name} · {p.brand}</SelectItem>
|
||||||
|
{/each}
|
||||||
|
</SelectGroup>
|
||||||
{/each}
|
{/each}
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue