feat(admin): vocabularies page for per-port pick lists
New /admin/vocabularies route + VocabulariesManager component. Catalog at src/lib/vocabularies.ts defines 11 vocabularies grouped into Interests / Berths / Expenses / Documents domains, each shipping with the canonical defaults from src/lib/constants.ts (interest temps, status-change reasons, tenure types, expense categories, document types, plus the 5 berth-spec dropdowns). Editor supports add / remove / reorder / inline-rename / reset-to- defaults; only dirty cards save. Uses the existing /api/v1/admin/settings PUT endpoint (already gated on admin.manage_settings) so storage piggybacks on system_settings (port_id, key) per the established pattern. Reps need read access without holding manage_settings — added a public-read /api/v1/vocabularies endpoint plus useVocabulary() hook (5-minute staleTime). The admin manager invalidates the vocabularies query on save so consumers (status-change dialog, expense form, etc.) pick up new lists immediately. Adds a Vocabularies card to the admin landing page. Follow-up sweep owed: actual consumers (interest-card temperature pill, berth-tabs select dropdowns, expense form category list, etc.) still read from the hardcoded constants.ts arrays. Wire them through useVocabulary in a separate pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
26
src/hooks/use-vocabulary.ts
Normal file
26
src/hooks/use-vocabulary.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
'use client';
|
||||
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
|
||||
import { apiFetch } from '@/lib/api/client';
|
||||
import { getVocabularyDef, type VocabularyKey } from '@/lib/vocabularies';
|
||||
|
||||
interface VocabulariesResponse {
|
||||
data: Record<string, readonly string[]>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the effective per-port vocabulary list for a key. Falls back
|
||||
* to the shipped defaults when the request hasn't resolved or the key
|
||||
* is missing from the response. Cached for 5 minutes — vocabularies
|
||||
* change rarely and the admin Vocabularies page invalidates by save.
|
||||
*/
|
||||
export function useVocabulary(key: VocabularyKey): readonly string[] {
|
||||
const def = getVocabularyDef(key);
|
||||
const { data } = useQuery<VocabulariesResponse>({
|
||||
queryKey: ['vocabularies'],
|
||||
queryFn: () => apiFetch<VocabulariesResponse>('/api/v1/vocabularies'),
|
||||
staleTime: 5 * 60 * 1000,
|
||||
});
|
||||
return data?.data[key] ?? def.defaults;
|
||||
}
|
||||
Reference in New Issue
Block a user