@fayz-ai/plugin-menu 0.9.0 → 0.9.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/locales/en.ts DELETED
@@ -1,64 +0,0 @@
1
- export const en: Record<string, string> = {
2
- 'menu.title': 'Menu',
3
- 'menu.nav.manager': 'Menu',
4
- 'menu.nav.categories': 'Categories',
5
- 'menu.nav.items': 'Items',
6
- 'menu.nav.modifiers': 'Modifiers',
7
- 'menu.manager.title': 'Menu Manager',
8
- 'menu.manager.subtitle': 'Manage your menu items and categories',
9
- 'menu.manager.search': 'Search menu...',
10
- 'menu.manager.allCategories': 'All Categories',
11
- 'menu.manager.newItem': 'New Item',
12
- 'menu.manager.noItems': 'No menu items yet',
13
- 'menu.manager.noItemsDesc': 'Add your first menu item to get started',
14
- 'menu.manager.addFirst': 'Add first item',
15
- 'menu.manager.available': 'Available',
16
- 'menu.manager.soldOut': 'Sold Out',
17
- 'menu.manager.hidden': 'Hidden',
18
- 'menu.manager.pos': 'POS',
19
- 'menu.manager.delivery': 'Delivery',
20
- 'menu.manager.featured': 'Featured',
21
- 'menu.manager.prepTime': 'Prep time',
22
- 'menu.manager.min': 'min',
23
- 'menu.manager.addCategory': 'Add Category',
24
- 'menu.manager.addProduct': 'Add Product',
25
- 'menu.manager.item': 'Item',
26
- 'menu.manager.price': 'Price',
27
- 'menu.manager.deliveryPrice': 'Delivery $',
28
- 'menu.manager.itemsCount': '{{count}} items',
29
- 'menu.manager.noResults': 'No categories or items match your search.',
30
- 'menu.manager.noResultsDesc': 'Try a different search term or category filter.',
31
- 'menu.itemForm.newTitle': 'New Menu Item',
32
- 'menu.itemForm.editTitle': 'Edit Menu Item',
33
- 'menu.itemForm.name': 'Item name',
34
- 'menu.itemForm.description': 'Description',
35
- 'menu.itemForm.price': 'Price',
36
- 'menu.itemForm.cost': 'Cost',
37
- 'menu.itemForm.category': 'Category',
38
- 'menu.itemForm.prepTime': 'Prep time (min)',
39
- 'menu.itemForm.image': 'Image URL',
40
- 'menu.itemForm.allergens': 'Allergens',
41
- 'menu.itemForm.dietaryTags': 'Dietary tags',
42
- 'menu.itemForm.availableForPos': 'Available for POS',
43
- 'menu.itemForm.availableForDelivery': 'Available for Delivery',
44
- 'menu.itemForm.deliveryPrice': 'Delivery price',
45
- 'menu.itemForm.isFeatured': 'Featured item',
46
- 'menu.itemForm.save': 'Save',
47
- 'menu.itemForm.cancel': 'Cancel',
48
- 'menu.itemForm.saving': 'Saving...',
49
- 'menu.categories.title': 'Categories',
50
- 'menu.categories.newCategory': 'New Category',
51
- 'menu.categories.name': 'Category name',
52
- 'menu.settings.title': 'Menu Settings',
53
- 'menu.settings.general': 'General',
54
- 'menu.settings.taxRate': 'Default tax rate',
55
- 'menu.settings.currency': 'Currency',
56
- 'menu.form.categoryName': 'Category name',
57
- 'menu.form.itemName': 'Item name',
58
- 'menu.form.description': 'Description',
59
- 'menu.form.category': 'Category',
60
- 'menu.form.uncategorized': 'Uncategorized',
61
- 'menu.form.optional': 'optional',
62
- 'menu.form.save': 'Save',
63
- 'menu.form.cancel': 'Cancel',
64
- }
@@ -1,4 +0,0 @@
1
- import { en } from './en'
2
- import { ptBR } from './pt-BR'
3
-
4
- export const menuLocales: Record<string, Record<string, string>> = { en, 'pt-BR': ptBR }
@@ -1,64 +0,0 @@
1
- export const ptBR: Record<string, string> = {
2
- 'menu.title': 'Cardápio',
3
- 'menu.nav.manager': 'Cardápio',
4
- 'menu.nav.categories': 'Categorias',
5
- 'menu.nav.items': 'Itens',
6
- 'menu.nav.modifiers': 'Modificadores',
7
- 'menu.manager.title': 'Gerenciar Cardápio',
8
- 'menu.manager.subtitle': 'Gerencie itens e categorias do cardápio',
9
- 'menu.manager.search': 'Buscar no cardápio...',
10
- 'menu.manager.allCategories': 'Todas as Categorias',
11
- 'menu.manager.newItem': 'Novo Item',
12
- 'menu.manager.noItems': 'Nenhum item no cardápio',
13
- 'menu.manager.noItemsDesc': 'Adicione o primeiro item para começar',
14
- 'menu.manager.addFirst': 'Adicionar primeiro item',
15
- 'menu.manager.available': 'Disponível',
16
- 'menu.manager.soldOut': 'Esgotado',
17
- 'menu.manager.hidden': 'Oculto',
18
- 'menu.manager.pos': 'PDV',
19
- 'menu.manager.delivery': 'Delivery',
20
- 'menu.manager.featured': 'Destaque',
21
- 'menu.manager.prepTime': 'Tempo de preparo',
22
- 'menu.manager.min': 'min',
23
- 'menu.manager.addCategory': 'Adicionar Categoria',
24
- 'menu.manager.addProduct': 'Adicionar Produto',
25
- 'menu.manager.item': 'Item',
26
- 'menu.manager.price': 'Preço',
27
- 'menu.manager.deliveryPrice': 'Delivery R$',
28
- 'menu.manager.itemsCount': '{{count}} itens',
29
- 'menu.manager.noResults': 'Nenhuma categoria ou item encontrado.',
30
- 'menu.manager.noResultsDesc': 'Tente um termo diferente ou filtro de categoria.',
31
- 'menu.itemForm.newTitle': 'Novo Item do Cardápio',
32
- 'menu.itemForm.editTitle': 'Editar Item do Cardápio',
33
- 'menu.itemForm.name': 'Nome do item',
34
- 'menu.itemForm.description': 'Descrição',
35
- 'menu.itemForm.price': 'Preço',
36
- 'menu.itemForm.cost': 'Custo',
37
- 'menu.itemForm.category': 'Categoria',
38
- 'menu.itemForm.prepTime': 'Tempo de preparo (min)',
39
- 'menu.itemForm.image': 'URL da imagem',
40
- 'menu.itemForm.allergens': 'Alérgenos',
41
- 'menu.itemForm.dietaryTags': 'Tags dietéticas',
42
- 'menu.itemForm.availableForPos': 'Disponível no PDV',
43
- 'menu.itemForm.availableForDelivery': 'Disponível para Delivery',
44
- 'menu.itemForm.deliveryPrice': 'Preço delivery',
45
- 'menu.itemForm.isFeatured': 'Item em destaque',
46
- 'menu.itemForm.save': 'Salvar',
47
- 'menu.itemForm.cancel': 'Cancelar',
48
- 'menu.itemForm.saving': 'Salvando...',
49
- 'menu.categories.title': 'Categorias',
50
- 'menu.categories.newCategory': 'Nova Categoria',
51
- 'menu.categories.name': 'Nome da categoria',
52
- 'menu.settings.title': 'Configurações do Cardápio',
53
- 'menu.settings.general': 'Geral',
54
- 'menu.settings.taxRate': 'Taxa padrão',
55
- 'menu.settings.currency': 'Moeda',
56
- 'menu.form.categoryName': 'Nome da categoria',
57
- 'menu.form.itemName': 'Nome do item',
58
- 'menu.form.description': 'Descrição',
59
- 'menu.form.category': 'Categoria',
60
- 'menu.form.uncategorized': 'Sem categoria',
61
- 'menu.form.optional': 'opcional',
62
- 'menu.form.save': 'Salvar',
63
- 'menu.form.cancel': 'Cancelar',
64
- }
package/src/registries.ts DELETED
@@ -1,84 +0,0 @@
1
- import type { PluginRegistryDef } from '@fayz-ai/core'
2
- import type { EntityDef } from '@fayz-ai/core'
3
-
4
- const allergenEntity: EntityDef = {
5
- name: 'Allergen',
6
- namePlural: 'Allergens',
7
- icon: 'AlertTriangle',
8
- displayField: 'name',
9
- defaultSort: 'name',
10
- fields: [
11
- { key: 'name', label: 'Name', type: 'text', required: true, showInTable: true },
12
- { key: 'icon', label: 'Icon', type: 'text', showInTable: true },
13
- { key: 'isActive', label: 'Active', type: 'boolean', showInTable: true, defaultValue: true },
14
- ],
15
- data: { table: 'menu_allergens', tenantScoped: true },
16
- }
17
-
18
- const dietaryTagEntity: EntityDef = {
19
- name: 'Dietary Tag',
20
- namePlural: 'Dietary Tags',
21
- icon: 'Leaf',
22
- displayField: 'name',
23
- defaultSort: 'name',
24
- fields: [
25
- { key: 'name', label: 'Name', type: 'text', required: true, showInTable: true },
26
- { key: 'color', label: 'Color', type: 'text', showInTable: true },
27
- { key: 'isActive', label: 'Active', type: 'boolean', showInTable: true, defaultValue: true },
28
- ],
29
- data: { table: 'menu_dietary_tags', tenantScoped: true },
30
- }
31
-
32
- const modifierGroupEntity: EntityDef = {
33
- name: 'Modifier Group',
34
- namePlural: 'Modifier Groups',
35
- icon: 'ListPlus',
36
- displayField: 'name',
37
- defaultSort: 'name',
38
- fields: [
39
- { key: 'name', label: 'Name', type: 'text', required: true, showInTable: true },
40
- { key: 'minSelections', label: 'Min Selections', type: 'number', showInTable: true, defaultValue: 0 },
41
- { key: 'maxSelections', label: 'Max Selections', type: 'number', showInTable: true, defaultValue: 1 },
42
- { key: 'isRequired', label: 'Required', type: 'boolean', showInTable: true, defaultValue: false },
43
- ],
44
- data: { table: 'menu_modifier_groups', tenantScoped: true },
45
- }
46
-
47
- export const menuRegistries: PluginRegistryDef[] = [
48
- {
49
- id: 'allergens',
50
- entity: allergenEntity,
51
- icon: 'AlertTriangle',
52
- description: 'Allergen types for menu items',
53
- display: 'table',
54
- readOnly: true,
55
- seedData: [
56
- { id: 'a-gluten', name: 'Gluten', icon: '🌾', isActive: true },
57
- { id: 'a-dairy', name: 'Dairy', icon: '🥛', isActive: true },
58
- { id: 'a-nuts', name: 'Nuts', icon: '🥜', isActive: true },
59
- { id: 'a-shellfish', name: 'Shellfish', icon: '🦐', isActive: true },
60
- { id: 'a-eggs', name: 'Eggs', icon: '🥚', isActive: true },
61
- { id: 'a-soy', name: 'Soy', icon: '🫘', isActive: true },
62
- ],
63
- },
64
- {
65
- id: 'dietary-tags',
66
- entity: dietaryTagEntity,
67
- icon: 'Leaf',
68
- description: 'Dietary tags (vegan, vegetarian, etc.)',
69
- display: 'table',
70
- readOnly: true,
71
- seedData: [
72
- { id: 'dt-vegan', name: 'Vegan', color: 'green', isActive: true },
73
- { id: 'dt-vegetarian', name: 'Vegetarian', color: 'lime', isActive: true },
74
- { id: 'dt-gf', name: 'Gluten Free', color: 'amber', isActive: true },
75
- ],
76
- },
77
- {
78
- id: 'modifier-groups',
79
- entity: modifierGroupEntity,
80
- icon: 'ListPlus',
81
- description: 'Modifier groups for item customization',
82
- display: 'table',
83
- },
84
- ]
package/src/store.ts DELETED
@@ -1,161 +0,0 @@
1
- import { createStore, type StoreApi } from 'zustand/vanilla'
2
- import { dedup } from '@fayz-ai/saas'
3
- import { toast } from 'sonner'
4
- import type { MenuDataProvider } from './data/types'
5
- import type {
6
- MenuCategory, MenuItem, ModifierGroup, MenuSummary,
7
- MenuItemQuery,
8
- CreateMenuItemInput, UpdateMenuItemInput, CreateMenuCategoryInput,
9
- } from './types'
10
-
11
- // ---------------------------------------------------------------------------
12
- // Store state
13
- // ---------------------------------------------------------------------------
14
-
15
- export interface MenuUIState {
16
- // Data cache
17
- categories: MenuCategory[]
18
- categoriesLoading: boolean
19
-
20
- menuItems: MenuItem[]
21
- menuItemsTotal: number
22
- menuItemsLoading: boolean
23
- menuItemQuery: MenuItemQuery
24
-
25
- modifierGroups: ModifierGroup[]
26
- modifiersLoading: boolean
27
-
28
- summary: MenuSummary | null
29
- summaryLoading: boolean
30
-
31
- // Actions
32
- fetchCategories(): Promise<void>
33
- fetchMenuItems(query: MenuItemQuery): Promise<void>
34
- fetchModifierGroups(): Promise<void>
35
- fetchSummary(): Promise<void>
36
- createMenuItem(input: CreateMenuItemInput): Promise<MenuItem>
37
- updateMenuItem(id: string, data: UpdateMenuItemInput): Promise<MenuItem>
38
- deleteMenuItem(id: string): Promise<void>
39
- toggleAvailability(id: string, field: string, value: any): Promise<void>
40
- createCategory(input: CreateMenuCategoryInput): Promise<MenuCategory>
41
- }
42
-
43
- // ---------------------------------------------------------------------------
44
- // Store factory
45
- // ---------------------------------------------------------------------------
46
-
47
- export function createMenuStore(provider: MenuDataProvider): StoreApi<MenuUIState> {
48
- return createStore<MenuUIState>((set, get) => ({
49
- categories: [],
50
- categoriesLoading: false,
51
-
52
- menuItems: [],
53
- menuItemsTotal: 0,
54
- menuItemsLoading: false,
55
- menuItemQuery: {},
56
-
57
- modifierGroups: [],
58
- modifiersLoading: false,
59
-
60
- summary: null,
61
- summaryLoading: false,
62
-
63
- async fetchCategories() {
64
- return dedup('menu:categories', async () => {
65
- set({ categoriesLoading: true })
66
- const categories = await provider.getCategories()
67
- set({ categories, categoriesLoading: false })
68
- })
69
- },
70
-
71
- async fetchMenuItems(query) {
72
- return dedup('menu:items:' + JSON.stringify(query), async () => {
73
- set({ menuItemsLoading: true, menuItemQuery: query })
74
- const result = await provider.getMenuItems(query)
75
- set({ menuItems: result.data, menuItemsTotal: result.total, menuItemsLoading: false })
76
- })
77
- },
78
-
79
- async fetchModifierGroups() {
80
- return dedup('menu:modifiers', async () => {
81
- set({ modifiersLoading: true })
82
- const modifierGroups = await provider.getModifierGroups()
83
- set({ modifierGroups, modifiersLoading: false })
84
- })
85
- },
86
-
87
- async fetchSummary() {
88
- return dedup('menu:summary', async () => {
89
- set({ summaryLoading: true })
90
- const summary = await provider.getSummary()
91
- set({ summary, summaryLoading: false })
92
- })
93
- },
94
-
95
- async createMenuItem(input) {
96
- try {
97
- const item = await provider.createMenuItem(input)
98
- const query = get().menuItemQuery
99
- const [result, summary] = await Promise.all([provider.getMenuItems(query), provider.getSummary()])
100
- set({ menuItems: result.data, menuItemsTotal: result.total, summary })
101
- toast.success('Menu item created')
102
- return item
103
- } catch (err: any) {
104
- toast.error('Failed to create menu item', { description: err?.message })
105
- throw err
106
- }
107
- },
108
-
109
- async updateMenuItem(id, data) {
110
- try {
111
- const item = await provider.updateMenuItem(id, data)
112
- const query = get().menuItemQuery
113
- const result = await provider.getMenuItems(query)
114
- set({ menuItems: result.data, menuItemsTotal: result.total })
115
- toast.success('Menu item updated')
116
- return item
117
- } catch (err: any) {
118
- toast.error('Failed to update menu item', { description: err?.message })
119
- throw err
120
- }
121
- },
122
-
123
- async deleteMenuItem(id) {
124
- try {
125
- await provider.deleteMenuItem(id)
126
- const query = get().menuItemQuery
127
- const [result, summary] = await Promise.all([provider.getMenuItems(query), provider.getSummary()])
128
- set({ menuItems: result.data, menuItemsTotal: result.total, summary })
129
- toast.success('Menu item deleted')
130
- } catch (err: any) {
131
- toast.error('Failed to delete menu item', { description: err?.message })
132
- throw err
133
- }
134
- },
135
-
136
- async toggleAvailability(id, field, value) {
137
- try {
138
- await provider.toggleAvailability(id, field as any, value)
139
- const query = get().menuItemQuery
140
- const result = await provider.getMenuItems(query)
141
- set({ menuItems: result.data, menuItemsTotal: result.total })
142
- } catch (err: any) {
143
- toast.error('Failed to update availability', { description: err?.message })
144
- throw err
145
- }
146
- },
147
-
148
- async createCategory(input) {
149
- try {
150
- const category = await provider.createCategory(input)
151
- const categories = await provider.getCategories()
152
- set({ categories })
153
- toast.success('Category created')
154
- return category
155
- } catch (err: any) {
156
- toast.error('Failed to create category', { description: err?.message })
157
- throw err
158
- }
159
- },
160
- }))
161
- }
package/src/types.ts DELETED
@@ -1,145 +0,0 @@
1
- // ---------------------------------------------------------------------------
2
- // Menu Plugin — Pure TypeScript types
3
- // ---------------------------------------------------------------------------
4
-
5
- // ============================================================
6
- // ENUMS / LITERALS
7
- // ============================================================
8
-
9
- export type MenuItemStatus = 'available' | 'sold_out' | 'hidden'
10
-
11
- // ============================================================
12
- // CORE ENTITIES
13
- // ============================================================
14
-
15
- /** Menu category — maps to public.categories (kind='menu_category') */
16
- export interface MenuCategory {
17
- id: string
18
- name: string
19
- parentId?: string
20
- icon?: string
21
- color?: string
22
- sortOrder: number
23
- isActive: boolean
24
- itemCount?: number
25
- tenantId: string
26
- createdAt: string
27
- updatedAt: string
28
- }
29
-
30
- /** Menu item — public.products + public.menu_items extension */
31
- export interface MenuItem {
32
- id: string
33
- name: string
34
- description?: string
35
- price: number
36
- cost?: number
37
- currency: string
38
- sku?: string
39
- imageUrl?: string
40
- categoryId?: string
41
- categoryName?: string
42
- status: MenuItemStatus
43
- isActive: boolean
44
- // Extension fields
45
- prepTimeMinutes?: number
46
- allergens?: string[]
47
- dietaryTags?: string[]
48
- availableForPos: boolean
49
- availableForDelivery: boolean
50
- deliveryPrice?: number
51
- sortOrder: number
52
- isFeatured: boolean
53
- modifierGroupIds?: string[]
54
- metadata?: Record<string, unknown>
55
- tenantId: string
56
- createdAt: string
57
- updatedAt: string
58
- }
59
-
60
- export interface ModifierGroup {
61
- id: string
62
- name: string
63
- minSelections: number
64
- maxSelections: number
65
- isRequired: boolean
66
- sortOrder: number
67
- items: ModifierItem[]
68
- tenantId: string
69
- createdAt: string
70
- }
71
-
72
- export interface ModifierItem {
73
- id: string
74
- groupId: string
75
- name: string
76
- priceAdjustment: number
77
- isActive: boolean
78
- sortOrder: number
79
- }
80
-
81
- // ============================================================
82
- // INPUT TYPES
83
- // ============================================================
84
-
85
- export interface CreateMenuItemInput {
86
- name: string
87
- description?: string
88
- price: number
89
- cost?: number
90
- imageUrl?: string
91
- categoryId?: string
92
- status?: MenuItemStatus
93
- prepTimeMinutes?: number
94
- allergens?: string[]
95
- dietaryTags?: string[]
96
- availableForPos?: boolean
97
- availableForDelivery?: boolean
98
- deliveryPrice?: number
99
- isFeatured?: boolean
100
- modifierGroupIds?: string[]
101
- }
102
-
103
- export interface UpdateMenuItemInput extends Partial<CreateMenuItemInput> {}
104
-
105
- export interface CreateMenuCategoryInput {
106
- name: string
107
- parentId?: string
108
- icon?: string
109
- color?: string
110
- sortOrder?: number
111
- }
112
-
113
- // ============================================================
114
- // QUERY TYPES
115
- // ============================================================
116
-
117
- export interface MenuItemQuery {
118
- categoryId?: string
119
- status?: MenuItemStatus | MenuItemStatus[]
120
- search?: string
121
- availableForPos?: boolean
122
- availableForDelivery?: boolean
123
- isFeatured?: boolean
124
- page?: number
125
- pageSize?: number
126
- }
127
-
128
- export interface PaginatedResult<T> {
129
- data: T[]
130
- total: number
131
- }
132
-
133
- // ============================================================
134
- // AGGREGATION
135
- // ============================================================
136
-
137
- export interface MenuSummary {
138
- totalItems: number
139
- availableItems: number
140
- soldOutItems: number
141
- hiddenItems: number
142
- categoryCount: number
143
- averagePrice: number
144
- featuredCount: number
145
- }