feat: initial setup, collections, caregiver frontend

This commit is contained in:
2025-12-02 11:32:45 +01:00
parent cee5925f25
commit 274ac8afa5
48 changed files with 6149 additions and 909 deletions

View 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