Add frontend imporvements 2
This commit is contained in:
@@ -61,9 +61,9 @@ export const inventoryKeys = {
|
||||
export const useIngredients = (
|
||||
tenantId: string,
|
||||
filter?: InventoryFilter,
|
||||
options?: Omit<UseQueryOptions<PaginatedResponse<IngredientResponse>, ApiError>, 'queryKey' | 'queryFn'>
|
||||
options?: Omit<UseQueryOptions<IngredientResponse[], ApiError>, 'queryKey' | 'queryFn'>
|
||||
) => {
|
||||
return useQuery<PaginatedResponse<IngredientResponse>, ApiError>({
|
||||
return useQuery<IngredientResponse[], ApiError>({
|
||||
queryKey: inventoryKeys.ingredients.list(tenantId, filter),
|
||||
queryFn: () => inventoryService.getIngredients(tenantId, filter),
|
||||
enabled: !!tenantId,
|
||||
|
||||
@@ -36,7 +36,7 @@ export class InventoryService {
|
||||
async getIngredients(
|
||||
tenantId: string,
|
||||
filter?: InventoryFilter
|
||||
): Promise<PaginatedResponse<IngredientResponse>> {
|
||||
): Promise<IngredientResponse[]> {
|
||||
const queryParams = new URLSearchParams();
|
||||
|
||||
if (filter?.category) queryParams.append('category', filter.category);
|
||||
@@ -60,7 +60,7 @@ export class InventoryService {
|
||||
? `${this.baseUrl}/${tenantId}/ingredients?${queryParams.toString()}`
|
||||
: `${this.baseUrl}/${tenantId}/ingredients`;
|
||||
|
||||
return apiClient.get<PaginatedResponse<IngredientResponse>>(url);
|
||||
return apiClient.get<IngredientResponse[]>(url);
|
||||
}
|
||||
|
||||
async updateIngredient(
|
||||
@@ -218,8 +218,8 @@ export class InventoryService {
|
||||
if (endDate) queryParams.append('end_date', endDate);
|
||||
|
||||
const url = queryParams.toString()
|
||||
? `${this.baseUrl}/${tenantId}/dashboard/analytics?${queryParams.toString()}`
|
||||
: `${this.baseUrl}/${tenantId}/dashboard/analytics`;
|
||||
? `/tenants/${tenantId}/dashboard/analytics?${queryParams.toString()}`
|
||||
: `/tenants/${tenantId}/dashboard/analytics`;
|
||||
|
||||
return apiClient.get(url);
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import React, { useState, useMemo } from 'react';
|
||||
import { Plus, Download, AlertTriangle, Package, Clock, CheckCircle, Eye, Edit, Calendar, DollarSign } from 'lucide-react';
|
||||
import { Button, Input, Card, Badge, StatsGrid, StatusCard, getStatusColor, StatusModal } from '../../../../components/ui';
|
||||
import { Button, Input, Card, StatsGrid, StatusCard, getStatusColor, StatusModal } from '../../../../components/ui';
|
||||
import { LoadingSpinner } from '../../../../components/shared';
|
||||
import { formatters } from '../../../../components/ui/Stats/StatsPresets';
|
||||
import { PageHeader } from '../../../../components/layout';
|
||||
import { InventoryForm, LowStockAlert } from '../../../../components/domain/inventory';
|
||||
import { useIngredients, useLowStockIngredients, useStockAnalytics } from '../../../../api/hooks/inventory';
|
||||
import { LowStockAlert } from '../../../../components/domain/inventory';
|
||||
import { useIngredients, useStockAnalytics } from '../../../../api/hooks/inventory';
|
||||
import { useCurrentTenant } from '../../../../stores/tenant.store';
|
||||
import { IngredientResponse } from '../../../../api/types/inventory';
|
||||
|
||||
@@ -25,21 +25,16 @@ const InventoryPage: React.FC = () => {
|
||||
error: ingredientsError
|
||||
} = useIngredients(tenantId, { search: searchTerm || undefined });
|
||||
|
||||
const {
|
||||
data: lowStockData,
|
||||
isLoading: lowStockLoading
|
||||
} = useLowStockIngredients(tenantId);
|
||||
|
||||
const {
|
||||
data: analyticsData,
|
||||
isLoading: analyticsLoading
|
||||
} = useStockAnalytics(tenantId);
|
||||
|
||||
const ingredients = ingredientsData?.items || [];
|
||||
const lowStockItems = lowStockData || [];
|
||||
const ingredients = ingredientsData || [];
|
||||
const lowStockItems = ingredients.filter(ingredient => ingredient.stock_status === 'low_stock');
|
||||
|
||||
const getInventoryStatusConfig = (ingredient: IngredientResponse) => {
|
||||
const { current_stock_level, low_stock_threshold, stock_status } = ingredient;
|
||||
const { stock_status } = ingredient;
|
||||
|
||||
switch (stock_status) {
|
||||
case 'out_of_stock':
|
||||
|
||||
@@ -172,6 +172,13 @@ async def proxy_tenant_stock(request: Request, tenant_id: str = Path(...), path:
|
||||
target_path = f"/api/v1/tenants/{tenant_id}/stock/{path}".rstrip("/")
|
||||
return await _proxy_to_inventory_service(request, target_path, tenant_id=tenant_id)
|
||||
|
||||
@router.api_route("/{tenant_id}/dashboard/{path:path}", methods=["GET", "POST", "PUT", "DELETE", "OPTIONS"])
|
||||
async def proxy_tenant_dashboard(request: Request, tenant_id: str = Path(...), path: str = ""):
|
||||
"""Proxy tenant dashboard requests to inventory service"""
|
||||
# The inventory service dashboard endpoints are tenant-scoped: /api/v1/tenants/{tenant_id}/dashboard/{path}
|
||||
target_path = f"/api/v1/tenants/{tenant_id}/dashboard/{path}".rstrip("/")
|
||||
return await _proxy_to_inventory_service(request, target_path, tenant_id=tenant_id)
|
||||
|
||||
# ================================================================
|
||||
# TENANT-SCOPED PRODUCTION SERVICE ENDPOINTS
|
||||
# ================================================================
|
||||
|
||||
@@ -31,7 +31,7 @@ from app.schemas.dashboard import (
|
||||
|
||||
logger = structlog.get_logger()
|
||||
|
||||
router = APIRouter(prefix="/dashboard", tags=["dashboard"])
|
||||
router = APIRouter(tags=["dashboard"])
|
||||
|
||||
|
||||
# ===== Dependency Injection =====
|
||||
@@ -46,7 +46,7 @@ async def get_dashboard_service(db: AsyncSession = Depends(get_db)) -> Dashboard
|
||||
|
||||
# ===== Main Dashboard Endpoints =====
|
||||
|
||||
@router.get("/tenants/{tenant_id}/summary", response_model=InventoryDashboardSummary)
|
||||
@router.get("/tenants/{tenant_id}/dashboard/summary", response_model=InventoryDashboardSummary)
|
||||
async def get_inventory_dashboard_summary(
|
||||
tenant_id: UUID = Path(...),
|
||||
filters: Optional[DashboardFilter] = None,
|
||||
@@ -74,7 +74,7 @@ async def get_inventory_dashboard_summary(
|
||||
)
|
||||
|
||||
|
||||
@router.get("/tenants/{tenant_id}/food-safety", response_model=FoodSafetyDashboard)
|
||||
@router.get("/tenants/{tenant_id}/dashboard/food-safety", response_model=FoodSafetyDashboard)
|
||||
async def get_food_safety_dashboard(
|
||||
tenant_id: UUID = Path(...),
|
||||
current_user: dict = Depends(get_current_user_dep),
|
||||
@@ -101,7 +101,7 @@ async def get_food_safety_dashboard(
|
||||
)
|
||||
|
||||
|
||||
@router.get("/tenants/{tenant_id}/analytics", response_model=InventoryAnalytics)
|
||||
@router.get("/tenants/{tenant_id}/dashboard/analytics", response_model=InventoryAnalytics)
|
||||
async def get_inventory_analytics(
|
||||
tenant_id: UUID = Path(...),
|
||||
days_back: int = Query(30, ge=1, le=365, description="Number of days to analyze"),
|
||||
@@ -129,7 +129,7 @@ async def get_inventory_analytics(
|
||||
)
|
||||
|
||||
|
||||
@router.get("/tenants/{tenant_id}/business-model", response_model=BusinessModelInsights)
|
||||
@router.get("/tenants/{tenant_id}/dashboard/business-model", response_model=BusinessModelInsights)
|
||||
async def get_business_model_insights(
|
||||
tenant_id: UUID = Path(...),
|
||||
current_user: dict = Depends(get_current_user_dep),
|
||||
@@ -158,7 +158,7 @@ async def get_business_model_insights(
|
||||
|
||||
# ===== Detailed Dashboard Data Endpoints =====
|
||||
|
||||
@router.get("/tenants/{tenant_id}/stock-status", response_model=List[StockStatusSummary])
|
||||
@router.get("/tenants/{tenant_id}/dashboard/stock-status", response_model=List[StockStatusSummary])
|
||||
async def get_stock_status_by_category(
|
||||
tenant_id: UUID = Path(...),
|
||||
current_user: dict = Depends(get_current_user_dep),
|
||||
@@ -181,7 +181,7 @@ async def get_stock_status_by_category(
|
||||
)
|
||||
|
||||
|
||||
@router.get("/tenants/{tenant_id}/alerts-summary", response_model=List[AlertSummary])
|
||||
@router.get("/tenants/{tenant_id}/dashboard/alerts-summary", response_model=List[AlertSummary])
|
||||
async def get_alerts_summary(
|
||||
tenant_id: UUID = Path(...),
|
||||
filters: Optional[AlertsFilter] = None,
|
||||
@@ -205,7 +205,7 @@ async def get_alerts_summary(
|
||||
)
|
||||
|
||||
|
||||
@router.get("/tenants/{tenant_id}/recent-activity", response_model=List[RecentActivity])
|
||||
@router.get("/tenants/{tenant_id}/dashboard/recent-activity", response_model=List[RecentActivity])
|
||||
async def get_recent_activity(
|
||||
tenant_id: UUID = Path(...),
|
||||
limit: int = Query(20, ge=1, le=100, description="Number of activities to return"),
|
||||
@@ -234,7 +234,7 @@ async def get_recent_activity(
|
||||
|
||||
# ===== Real-time Data Endpoints =====
|
||||
|
||||
@router.get("/tenants/{tenant_id}/live-metrics")
|
||||
@router.get("/tenants/{tenant_id}/dashboard/live-metrics")
|
||||
async def get_live_metrics(
|
||||
tenant_id: UUID = Path(...),
|
||||
current_user: dict = Depends(get_current_user_dep),
|
||||
@@ -261,7 +261,7 @@ async def get_live_metrics(
|
||||
)
|
||||
|
||||
|
||||
@router.get("/tenants/{tenant_id}/temperature-status")
|
||||
@router.get("/tenants/{tenant_id}/dashboard/temperature-status")
|
||||
async def get_temperature_monitoring_status(
|
||||
tenant_id: UUID = Path(...),
|
||||
current_user: dict = Depends(get_current_user_dep),
|
||||
@@ -289,7 +289,7 @@ async def get_temperature_monitoring_status(
|
||||
|
||||
# ===== Dashboard Configuration Endpoints =====
|
||||
|
||||
@router.get("/tenants/{tenant_id}/config")
|
||||
@router.get("/tenants/{tenant_id}/dashboard/config")
|
||||
async def get_dashboard_config(
|
||||
tenant_id: UUID = Path(...),
|
||||
current_user: dict = Depends(get_current_user_dep)
|
||||
|
||||
@@ -209,9 +209,9 @@ async def get_stock_entry(
|
||||
|
||||
@router.put("/tenants/{tenant_id}/stock/{stock_id}", response_model=StockResponse)
|
||||
async def update_stock(
|
||||
stock_data: StockUpdate,
|
||||
stock_id: UUID = Path(..., description="Stock entry ID"),
|
||||
tenant_id: UUID = Path(..., description="Tenant ID"),
|
||||
stock_data: StockUpdate,
|
||||
db: AsyncSession = Depends(get_db)
|
||||
):
|
||||
"""Update stock entry"""
|
||||
@@ -269,8 +269,8 @@ async def delete_stock(
|
||||
|
||||
@router.post("/tenants/{tenant_id}/stock/movements", response_model=StockMovementResponse)
|
||||
async def create_stock_movement(
|
||||
tenant_id: UUID = Path(..., description="Tenant ID"),
|
||||
movement_data: StockMovementCreate,
|
||||
tenant_id: UUID = Path(..., description="Tenant ID"),
|
||||
current_user: dict = Depends(get_current_user_dep),
|
||||
db: AsyncSession = Depends(get_db)
|
||||
):
|
||||
|
||||
Reference in New Issue
Block a user