221 lines
7.4 KiB
TypeScript
221 lines
7.4 KiB
TypeScript
'use client'
|
|
|
|
import React, { useState } from 'react'
|
|
import { Gutter } from '@payloadcms/ui'
|
|
import './styles.scss'
|
|
|
|
interface KitchenReportResponse {
|
|
date: string
|
|
mealType: string
|
|
totalMeals: number
|
|
ingredients: Record<string, number>
|
|
labels: Record<string, string>
|
|
portionSizes?: Record<string, number>
|
|
error?: string
|
|
}
|
|
|
|
export const KitchenDashboard: React.FC = () => {
|
|
const [date, setDate] = useState(() => {
|
|
const today = new Date()
|
|
return today.toISOString().split('T')[0]
|
|
})
|
|
const [mealType, setMealType] = useState<'breakfast' | 'lunch' | 'dinner'>('breakfast')
|
|
const [loading, setLoading] = useState(false)
|
|
const [error, setError] = useState<string | null>(null)
|
|
const [report, setReport] = useState<KitchenReportResponse | null>(null)
|
|
|
|
const generateReport = async () => {
|
|
setLoading(true)
|
|
setError(null)
|
|
setReport(null)
|
|
|
|
try {
|
|
const response = await fetch(
|
|
`/api/meals/kitchen-report?date=${date}&mealType=${mealType}`,
|
|
{
|
|
credentials: 'include',
|
|
},
|
|
)
|
|
|
|
const data = await response.json()
|
|
|
|
if (!response.ok) {
|
|
throw new Error(data.error || 'Failed to generate report')
|
|
}
|
|
|
|
setReport(data)
|
|
} catch (err) {
|
|
setError(err instanceof Error ? err.message : 'An error occurred')
|
|
} finally {
|
|
setLoading(false)
|
|
}
|
|
}
|
|
|
|
const getMealTypeLabel = (type: string) => {
|
|
switch (type) {
|
|
case 'breakfast':
|
|
return 'Breakfast (Frühstück)'
|
|
case 'lunch':
|
|
return 'Lunch (Mittagessen)'
|
|
case 'dinner':
|
|
return 'Dinner (Abendessen)'
|
|
default:
|
|
return type
|
|
}
|
|
}
|
|
|
|
const formatDate = (dateStr: string) => {
|
|
const d = new Date(dateStr)
|
|
return d.toLocaleDateString('en-US', {
|
|
weekday: 'long',
|
|
year: 'numeric',
|
|
month: 'long',
|
|
day: 'numeric',
|
|
})
|
|
}
|
|
|
|
return (
|
|
<Gutter>
|
|
<div className="kitchen-dashboard">
|
|
<header className="kitchen-dashboard__header">
|
|
<h1>Kitchen Dashboard</h1>
|
|
<p>Generate ingredient reports for meal preparation</p>
|
|
</header>
|
|
|
|
<section className="kitchen-dashboard__controls">
|
|
<div className="kitchen-dashboard__form">
|
|
<div className="kitchen-dashboard__field">
|
|
<label htmlFor="report-date">Date</label>
|
|
<input
|
|
type="date"
|
|
id="report-date"
|
|
value={date}
|
|
onChange={(e) => setDate(e.target.value)}
|
|
className="kitchen-dashboard__input"
|
|
/>
|
|
</div>
|
|
|
|
<div className="kitchen-dashboard__field">
|
|
<label htmlFor="meal-type">Meal Type</label>
|
|
<select
|
|
id="meal-type"
|
|
value={mealType}
|
|
onChange={(e) => setMealType(e.target.value as 'breakfast' | 'lunch' | 'dinner')}
|
|
className="kitchen-dashboard__select"
|
|
>
|
|
<option value="breakfast">Breakfast (Frühstück)</option>
|
|
<option value="lunch">Lunch (Mittagessen)</option>
|
|
<option value="dinner">Dinner (Abendessen)</option>
|
|
</select>
|
|
</div>
|
|
|
|
<button
|
|
type="button"
|
|
onClick={generateReport}
|
|
disabled={loading}
|
|
className="kitchen-dashboard__button"
|
|
>
|
|
{loading ? 'Generating...' : 'Generate Report'}
|
|
</button>
|
|
</div>
|
|
</section>
|
|
|
|
{error && (
|
|
<div className="kitchen-dashboard__error">
|
|
<strong>Error:</strong> {error}
|
|
</div>
|
|
)}
|
|
|
|
{report && (
|
|
<section className="kitchen-dashboard__report">
|
|
<div className="kitchen-dashboard__report-header">
|
|
<h2>Ingredient Report</h2>
|
|
<div className="kitchen-dashboard__report-meta">
|
|
<span className="kitchen-dashboard__meta-item">
|
|
<strong>Date:</strong> {formatDate(report.date)}
|
|
</span>
|
|
<span className="kitchen-dashboard__meta-item">
|
|
<strong>Meal:</strong> {getMealTypeLabel(report.mealType)}
|
|
</span>
|
|
<span className="kitchen-dashboard__meta-item kitchen-dashboard__meta-item--highlight">
|
|
<strong>Total Meals:</strong> {report.totalMeals}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
|
|
{report.totalMeals === 0 ? (
|
|
<div className="kitchen-dashboard__empty">
|
|
<p>No meals found for this date and meal type.</p>
|
|
</div>
|
|
) : (
|
|
<>
|
|
{report.portionSizes && Object.keys(report.portionSizes).length > 0 && (
|
|
<div className="kitchen-dashboard__portion-sizes">
|
|
<h3>Portion Sizes</h3>
|
|
<div className="kitchen-dashboard__portion-grid">
|
|
{Object.entries(report.portionSizes).map(([size, count]) => (
|
|
<div key={size} className="kitchen-dashboard__portion-item">
|
|
<span className="kitchen-dashboard__portion-label">
|
|
{size === 'small'
|
|
? 'Small (Kleine)'
|
|
: size === 'large'
|
|
? 'Large (Große)'
|
|
: 'Vegetarian'}
|
|
</span>
|
|
<span className="kitchen-dashboard__portion-count">{count}</span>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
<div className="kitchen-dashboard__ingredients">
|
|
<h3>Ingredients Required</h3>
|
|
{Object.keys(report.ingredients).length === 0 ? (
|
|
<p className="kitchen-dashboard__no-ingredients">
|
|
No specific ingredients selected in orders.
|
|
</p>
|
|
) : (
|
|
<table className="kitchen-dashboard__table">
|
|
<thead>
|
|
<tr>
|
|
<th>Ingredient</th>
|
|
<th>Quantity</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{Object.entries(report.ingredients)
|
|
.sort(([, a], [, b]) => b - a)
|
|
.map(([key, count]) => (
|
|
<tr key={key}>
|
|
<td>{report.labels[key] || key}</td>
|
|
<td className="kitchen-dashboard__count">{count}</td>
|
|
</tr>
|
|
))}
|
|
</tbody>
|
|
<tfoot>
|
|
<tr>
|
|
<td>
|
|
<strong>Total Items</strong>
|
|
</td>
|
|
<td className="kitchen-dashboard__count">
|
|
<strong>
|
|
{Object.values(report.ingredients).reduce((a, b) => a + b, 0)}
|
|
</strong>
|
|
</td>
|
|
</tr>
|
|
</tfoot>
|
|
</table>
|
|
)}
|
|
</div>
|
|
</>
|
|
)}
|
|
</section>
|
|
)}
|
|
</div>
|
|
</Gutter>
|
|
)
|
|
}
|
|
|
|
export default KitchenDashboard
|