You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

248 lines
10 KiB

from nicegui import ui
from services.api_client import APIClient
import asyncio
from typing import List, Dict, Any, Optional
class PietanzePage:
def __init__(self, api_client: APIClient):
self.api_client = api_client
self.pietanze_data = []
self.search_filter = ""
self.allergen_filter = []
self.selected_pietanza = None
# Available allergens
self.available_allergens = [
'glutine', 'lattosio', 'uova', 'pesce', 'crostacei',
'arachidi', 'frutta_a_guscio', 'soia', 'sedano',
'senape', 'sesamo', 'solfiti'
]
def render(self):
"""Render pietanze management page"""
ui.label('Gestione Pietanze').classes('text-3xl font-bold text-gray-800 mb-6')
# Toolbar
with ui.row().classes('w-full justify-between items-center mb-6'):
with ui.row().classes('gap-4 items-center'):
# Search input
search_input = ui.input('Cerca pietanze...', on_change=self._on_search_change).classes('w-64')
search_input.bind_value(self, 'search_filter')
# Allergen filter
with ui.select(
self.available_allergens,
multiple=True,
label='Filtra per allergeni',
on_change=self._on_filter_change
).classes('w-48') as allergen_select:
allergen_select.bind_value(self, 'allergen_filter')
# Refresh button
ui.button('Aggiorna', icon='refresh', on_click=self._load_pietanze).props('outline')
# Add new button
ui.button('Nuova Pietanza', icon='add', on_click=self._show_create_dialog).classes('bg-green-600 hover:bg-green-700')
# Pietanze table
self._render_pietanze_table()
# Load initial data
asyncio.create_task(self._load_pietanze())
def _render_pietanze_table(self):
"""Render pietanze data table"""
columns = [
{'name': 'id', 'label': 'ID', 'field': 'id', 'sortable': True},
{'name': 'nome', 'label': 'Nome', 'field': 'nome', 'sortable': True, 'align': 'left'},
{'name': 'descrizione', 'label': 'Descrizione', 'field': 'descrizione', 'align': 'left'},
{'name': 'allergeni', 'label': 'Allergeni', 'field': 'allergeni_display'},
{'name': 'actions', 'label': 'Azioni', 'field': 'actions'},
]
self.pietanze_table = ui.table(
columns=columns,
rows=[],
row_key='id'
).classes('w-full')
# Add action buttons to each row
self.pietanze_table.add_slot('body-cell-actions', '''
<q-td :props="props">
<q-btn flat round dense icon="edit" color="primary" @click="$parent.$emit('edit', props.row)" />
<q-btn flat round dense icon="delete" color="negative" @click="$parent.$emit('delete', props.row)" />
</q-td>
''')
self.pietanze_table.on('edit', self._show_edit_dialog)
self.pietanze_table.on('delete', self._show_delete_dialog)
def _show_create_dialog(self):
"""Show create pietanza dialog"""
self.selected_pietanza = None
self._show_pietanza_dialog()
def _show_edit_dialog(self, e):
"""Show edit pietanza dialog"""
self.selected_pietanza = e.args
self._show_pietanza_dialog()
def _show_pietanza_dialog(self):
"""Show pietanza create/edit dialog"""
is_edit = self.selected_pietanza is not None
title = 'Modifica Pietanza' if is_edit else 'Nuova Pietanza'
with ui.dialog() as dialog, ui.card().classes('w-96'):
ui.label(title).classes('text-xl font-bold mb-4')
# Form fields
nome_input = ui.input('Nome', placeholder='Nome della pietanza').classes('w-full')
descrizione_input = ui.textarea('Descrizione', placeholder='Descrizione dettagliata').classes('w-full')
allergeni_select = ui.select(
self.available_allergens,
multiple=True,
label='Allergeni'
).classes('w-full')
# Pre-fill form if editing
if is_edit:
nome_input.value = self.selected_pietanza['nome']
descrizione_input.value = self.selected_pietanza.get('descrizione', '')
allergeni_select.value = self.selected_pietanza.get('allergeni', [])
# Action buttons
with ui.row().classes('w-full justify-end gap-2 mt-4'):
ui.button('Annulla', on_click=dialog.close).props('flat')
save_btn = ui.button(
'Salva' if is_edit else 'Crea',
on_click=lambda: self._save_pietanza(
dialog, nome_input.value, descrizione_input.value, allergeni_select.value, is_edit
)
).classes('bg-green-600 hover:bg-green-700')
dialog.open()
def _show_delete_dialog(self, e):
"""Show delete confirmation dialog"""
pietanza = e.args
with ui.dialog() as dialog, ui.card():
ui.label('Conferma Eliminazione').classes('text-xl font-bold mb-4')
ui.label(f'Sei sicuro di voler eliminare "{pietanza["nome"]}"?').classes('mb-4')
with ui.row().classes('w-full justify-end gap-2'):
ui.button('Annulla', on_click=dialog.close).props('flat')
ui.button(
'Elimina',
on_click=lambda: self._delete_pietanza(dialog, pietanza['id'])
).classes('bg-red-600 hover:bg-red-700')
dialog.open()
async def _save_pietanza(self, dialog, nome: str, descrizione: str, allergeni: List[str], is_edit: bool):
"""Save pietanza (create or update)"""
if not nome.strip():
ui.notify('Il nome è obbligatorio', type='negative')
return
try:
pietanza_data = {
'nome': nome.strip(),
'descrizione': descrizione.strip() if descrizione else None,
'allergeni': allergeni or []
}
if is_edit:
await self.api_client.update_pietanza(self.selected_pietanza['id'], pietanza_data)
ui.notify('Pietanza aggiornata con successo', type='positive')
else:
await self.api_client.create_pietanza(pietanza_data)
ui.notify('Pietanza creata con successo', type='positive')
dialog.close()
await self._load_pietanze()
except Exception as e:
ui.notify(f'Errore nel salvataggio: {str(e)}', type='negative')
async def _delete_pietanza(self, dialog, pietanza_id: int):
"""Delete pietanza"""
try:
await self.api_client.delete_pietanza(pietanza_id)
ui.notify('Pietanza eliminata con successo', type='positive')
dialog.close()
await self._load_pietanze()
except Exception as e:
ui.notify(f'Errore nell\'eliminazione: {str(e)}', type='negative')
async def _load_pietanze(self):
"""Load pietanze from API"""
try:
# Call actual API with current filters
response = await self.api_client.get_pietanze(
skip=0,
limit=1000, # Load all pietanze for now
search=self.search_filter if self.search_filter else None,
allergeni=self.allergen_filter if self.allergen_filter else None
)
# Extract pietanze from response
pietanze_list = response.get('items', []) if isinstance(response, dict) else response
# Format data for table display
self.pietanze_data = []
for pietanza in pietanze_list:
formatted_pietanza = {
'id': pietanza['id'],
'nome': pietanza['nome'],
'descrizione': pietanza.get('descrizione', ''),
'allergeni': pietanza.get('allergeni', []),
'allergeni_display': ', '.join(pietanza.get('allergeni', [])) if pietanza.get('allergeni') else 'Nessuno',
'created_at': pietanza.get('created_at', '')
}
self.pietanze_data.append(formatted_pietanza)
self._update_table()
except Exception as e:
ui.notify(f'Errore nel caricamento pietanze: {str(e)}', type='negative')
# Keep existing data on error
self._update_table()
def _update_table(self):
"""Update table with filtered data"""
filtered_data = self._filter_pietanze()
self.pietanze_table.rows = filtered_data
ui.update()
def _filter_pietanze(self) -> List[Dict[str, Any]]:
"""Filter pietanze based on search and allergen filters"""
filtered = self.pietanze_data
# Apply search filter
if self.search_filter:
search_lower = self.search_filter.lower()
filtered = [
p for p in filtered
if search_lower in p['nome'].lower() or
(p['descrizione'] and search_lower in p['descrizione'].lower())
]
# Apply allergen filter
if self.allergen_filter:
filtered = [
p for p in filtered
if any(allergen in p['allergeni'] for allergen in self.allergen_filter)
]
return filtered
def _on_search_change(self):
"""Handle search filter change"""
self._update_table()
def _on_filter_change(self):
"""Handle allergen filter change"""
self._update_table()