feat: major dashboard & waiter PWA overhaul

- Manager dashboard: replaced monolithic DashboardTab/OperationsPage with new
  DashboardPage; added OrderDetailModal, ShiftDetailModal, DeleteConfirmModal,
  PaymentMethodModal; updated Sidebar routing and App navigation
- Reports: reworked WorkDaySummary, OrderHistory, ShiftsOverview with detail modals
- Backend routers: extended orders, reports, shifts, products, business_day endpoints;
  updated cloud_sync service
- Waiter PWA: refreshed app icons, improved ConnectionLostModal UX, updated
  TableCard, SSEContext, connectionStore; added useProductCache hook; vite config tweaks

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-21 15:24:54 +03:00
parent aa92623802
commit 5de89a722c
40 changed files with 1906 additions and 1171 deletions

View File

@@ -17,9 +17,14 @@ from schemas.product import (
CategoryReparentRequest,
)
from routers.deps import get_current_user, require_manager
from services.sse_bus import broadcast_sync
router = APIRouter()
def _broadcast_products_changed():
broadcast_sync("products_changed", {})
IMAGE_DIR = "/app/data/product_images"
@@ -118,6 +123,7 @@ def create_category(body: CategoryCreate, db: Session = Depends(get_db), user: U
db.add(cat)
db.commit()
db.refresh(cat)
_broadcast_products_changed()
return cat
@@ -128,6 +134,7 @@ def reorder_categories(items: List[CategoryReorderItem], db: Session = Depends(g
if cat:
cat.sort_order = item.sort_order
db.commit()
_broadcast_products_changed()
@router.put("/categories/reorder-subcategories", status_code=status.HTTP_204_NO_CONTENT)
@@ -138,6 +145,7 @@ def reorder_subcategories(items: List[SubcategoryReorderItem], db: Session = Dep
if cat:
cat.sort_order = item.sort_order
db.commit()
_broadcast_products_changed()
@router.put("/categories/reorder-general", status_code=status.HTTP_204_NO_CONTENT)
@@ -148,6 +156,7 @@ def reorder_general(items: List[ParentGeneralReorderItem], db: Session = Depends
if cat:
cat.general_sort_order = item.general_sort_order
db.commit()
_broadcast_products_changed()
@router.put("/categories/{category_id}/reparent", response_model=CategoryOut)
@@ -176,6 +185,7 @@ def reparent_category(category_id: int, body: CategoryReparentRequest, db: Sessi
cat.sort_order = sibling_count
db.commit()
db.refresh(cat)
_broadcast_products_changed()
return cat
@@ -188,6 +198,7 @@ def update_category(category_id: int, body: CategoryUpdate, db: Session = Depend
setattr(cat, field, value)
db.commit()
db.refresh(cat)
_broadcast_products_changed()
return cat
@@ -198,6 +209,7 @@ def delete_category(category_id: int, db: Session = Depends(get_db), user: User
raise HTTPException(status_code=404, detail="Category not found")
db.delete(cat)
db.commit()
_broadcast_products_changed()
# ── Products ──────────────────────────────────────────────────────────────────
@@ -218,6 +230,7 @@ def reorder_products(items: List[ProductReorderItem], db: Session = Depends(get_
if product:
product.sort_order = item.sort_order
db.commit()
_broadcast_products_changed()
@router.post("/", response_model=ProductOut, status_code=status.HTTP_201_CREATED)
@@ -255,6 +268,7 @@ def create_product(body: ProductCreate, db: Session = Depends(get_db), user: Use
_replace_preference_sets(db, product, body.preference_sets)
db.commit()
db.refresh(product)
_broadcast_products_changed()
return product
@@ -275,6 +289,7 @@ def update_product(product_id: int, body: ProductUpdate, db: Session = Depends(g
_replace_preference_sets(db, product, body.preference_sets)
db.commit()
db.refresh(product)
_broadcast_products_changed()
return product
@@ -305,6 +320,7 @@ async def upload_product_image(product_id: int, file: UploadFile = File(...), db
product.image_url = f"/static/product_images/{filename}"
db.commit()
db.refresh(product)
_broadcast_products_changed()
return product
@@ -329,3 +345,4 @@ def delete_product(product_id: int, hard: bool = False, db: Session = Depends(ge
else:
db.delete(product)
db.commit()
_broadcast_products_changed()