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
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()
|
|
|