diff --git a/apps/web/messages/en.json b/apps/web/messages/en.json index f9f11fb..a4516a1 100644 --- a/apps/web/messages/en.json +++ b/apps/web/messages/en.json @@ -342,5 +342,24 @@ "common_items_add_name_label": "Item name", "common_items_add_name_placeholder": "e.g. olive oil", "common_items_add_visibility_label": "Visibility", - "common_items_add_save": "Add" + "common_items_add_save": "Add", + "create_list_modal_title": "New shopping list", + "create_list_input_label": "List name", + "create_list_input_placeholder": "e.g. Weekly shop", + "create_list_submit": "Create", + "create_list_suggestion_chip": "Suggestion: {title}", + "create_list_auto_numbered_toast": "Created as “{title}”", + "manage_list_titles_section_title": "Suggested titles", + "manage_list_titles_blurb": "Pre-set a default title for new lists and curate suggestions admins want to surface.", + "manage_default_list_title_label": "Default new-list title", + "manage_default_list_title_placeholder": "e.g. Weekly shop", + "manage_default_list_title_clear": "Clear", + "manage_list_titles_empty": "No curated titles yet.", + "manage_list_titles_add_button": "Add title", + "manage_list_titles_add_modal_title": "Add suggested title", + "manage_list_titles_add_name_label": "Title", + "manage_list_titles_add_name_placeholder": "e.g. Compra", + "manage_list_titles_add_save": "Add", + "manage_list_titles_remove": "Remove", + "manage_list_titles_readonly": "Only admins can curate these titles." } diff --git a/apps/web/messages/es.json b/apps/web/messages/es.json index d279f27..1f71d3f 100644 --- a/apps/web/messages/es.json +++ b/apps/web/messages/es.json @@ -342,5 +342,24 @@ "common_items_add_name_label": "Nombre del item", "common_items_add_name_placeholder": "p. ej. aceite de oliva", "common_items_add_visibility_label": "Visibilidad", - "common_items_add_save": "Añadir" + "common_items_add_save": "Añadir", + "create_list_modal_title": "Nueva lista de la compra", + "create_list_input_label": "Nombre de la lista", + "create_list_input_placeholder": "p. ej. Compra semanal", + "create_list_submit": "Crear", + "create_list_suggestion_chip": "Sugerencia: {title}", + "create_list_auto_numbered_toast": "Creada como «{title}»", + "manage_list_titles_section_title": "Títulos sugeridos", + "manage_list_titles_blurb": "Preconfigura un título por defecto para las nuevas listas y mantén una lista de sugerencias.", + "manage_default_list_title_label": "Título por defecto", + "manage_default_list_title_placeholder": "p. ej. Compra semanal", + "manage_default_list_title_clear": "Borrar", + "manage_list_titles_empty": "No hay títulos sugeridos todavía.", + "manage_list_titles_add_button": "Añadir título", + "manage_list_titles_add_modal_title": "Añadir título sugerido", + "manage_list_titles_add_name_label": "Título", + "manage_list_titles_add_name_placeholder": "p. ej. Compra", + "manage_list_titles_add_save": "Añadir", + "manage_list_titles_remove": "Borrar", + "manage_list_titles_readonly": "Solo los admins pueden gestionar estos títulos." } diff --git a/apps/web/src/lib/components/CreateListModal.svelte b/apps/web/src/lib/components/CreateListModal.svelte new file mode 100644 index 0000000..adc86f9 --- /dev/null +++ b/apps/web/src/lib/components/CreateListModal.svelte @@ -0,0 +1,283 @@ + + +{#if open} + +{/if} diff --git a/apps/web/src/routes/(app)/lists/+page.svelte b/apps/web/src/routes/(app)/lists/+page.svelte index dab8f30..194edf8 100644 --- a/apps/web/src/routes/(app)/lists/+page.svelte +++ b/apps/web/src/routes/(app)/lists/+page.svelte @@ -19,10 +19,15 @@ import { ShoppingCart, Plus, MoreHorizontal, Trash2, Archive, RotateCcw } from 'lucide-svelte'; import * as m from '$lib/paraglide/messages'; import ScreenMasthead from '$lib/components/ScreenMasthead.svelte'; + import CreateListModal from '$lib/components/CreateListModal.svelte'; // ── State ────────────────────────────────────────────────────────────────── let creating = $state(false); + let createModalOpen = $state(false); + // Fase 18.3.4: when the modal auto-suffixes "#N", surface the final name in + // a transient toast so the user sees what was actually created. + let autoNumberedToast = $state(null); let showTrash = $state(false); let trashedLists = $state([]); @@ -55,15 +60,29 @@ } // ── Create ───────────────────────────────────────────────────────────────── - // Matches the /notes flow: click the masthead button → create with an empty - // name → navigate to /lists/[id] where the user renames inline. + // Fase 18: replaces the old "create with empty name + navigate to detail to + // rename inline" flow with an explicit modal. The modal prefills the input + // with `currentCollective.default_list_title`, suggests `#N` autocomplete + // for catalog-curated prefixes, and gates submit on non-empty trim. - async function handleCreate() { - if (!$currentCollective || !$currentUser || creating) return; - creating = true; - const created = await createList($currentCollective.id, '', $currentUser.id); - creating = false; - if (created) await goto(`/lists/${created.id}`); + function openCreateModal() { + // Open eagerly — the modal itself handles missing collective/user + // (the submit button is disabled until both are set). Letting the + // modal open on click avoids a UX trap where the button looks broken + // because the auth state hasn't propagated yet. + createModalOpen = true; + } + + function closeCreateModal() { + createModalOpen = false; + } + + async function handleCreated(id: string, finalName: string, wasAutoNumbered: boolean) { + if (wasAutoNumbered) { + autoNumberedToast = finalName; + setTimeout(() => (autoNumberedToast = null), 3000); + } + await goto(`/lists/${id}`); } // ── Actions ──────────────────────────────────────────────────────────────── @@ -132,8 +151,9 @@