feat: initial setup, collections, caregiver frontend
This commit is contained in:
220
src/app/(payload)/admin/views/KitchenDashboard/index.tsx
Normal file
220
src/app/(payload)/admin/views/KitchenDashboard/index.tsx
Normal file
@@ -0,0 +1,220 @@
|
||||
'use client'
|
||||
|
||||
import React, { useState } from 'react'
|
||||
import { Gutter } from '@payloadcms/ui'
|
||||
import './styles.scss'
|
||||
|
||||
interface KitchenReportResponse {
|
||||
date: string
|
||||
mealType: string
|
||||
totalOrders: 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/meal-orders/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 Orders:</strong> {report.totalOrders}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{report.totalOrders === 0 ? (
|
||||
<div className="kitchen-dashboard__empty">
|
||||
<p>No orders 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
|
||||
Reference in New Issue
Block a user