761 lines
34 KiB
TypeScript
761 lines
34 KiB
TypeScript
'use client'
|
|
|
|
import React, { useState, useEffect, Suspense } from 'react'
|
|
import { useRouter, useSearchParams } from 'next/navigation'
|
|
import Link from 'next/link'
|
|
import { format } from 'date-fns'
|
|
import {
|
|
ArrowLeft,
|
|
Loader2,
|
|
Search,
|
|
Sunrise,
|
|
Sun,
|
|
Moon,
|
|
AlertTriangle,
|
|
Check,
|
|
} from 'lucide-react'
|
|
|
|
import { Button } from '@/components/ui/button'
|
|
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
|
|
import { Input } from '@/components/ui/input'
|
|
import { Label } from '@/components/ui/label'
|
|
import { Checkbox } from '@/components/ui/checkbox'
|
|
import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group'
|
|
import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'
|
|
import { Separator } from '@/components/ui/separator'
|
|
import { Badge } from '@/components/ui/badge'
|
|
import { cn } from '@/lib/utils'
|
|
|
|
interface Resident {
|
|
id: number
|
|
name: string
|
|
room: string
|
|
table?: string
|
|
station?: string
|
|
highCaloric?: boolean
|
|
aversions?: string
|
|
notes?: string
|
|
}
|
|
|
|
type MealType = 'breakfast' | 'lunch' | 'dinner'
|
|
|
|
interface BreakfastOptions {
|
|
accordingToPlan: boolean
|
|
bread: {
|
|
breadRoll: boolean
|
|
wholeGrainRoll: boolean
|
|
greyBread: boolean
|
|
wholeGrainBread: boolean
|
|
whiteBread: boolean
|
|
crispbread: boolean
|
|
}
|
|
porridge: boolean
|
|
preparation: { sliced: boolean; spread: boolean }
|
|
spreads: {
|
|
butter: boolean
|
|
margarine: boolean
|
|
jam: boolean
|
|
diabeticJam: boolean
|
|
honey: boolean
|
|
cheese: boolean
|
|
quark: boolean
|
|
sausage: boolean
|
|
}
|
|
beverages: { coffee: boolean; tea: boolean; hotMilk: boolean; coldMilk: boolean }
|
|
additions: { sugar: boolean; sweetener: boolean; coffeeCreamer: boolean }
|
|
}
|
|
|
|
interface LunchOptions {
|
|
portionSize: 'small' | 'large' | 'vegetarian'
|
|
soup: boolean
|
|
dessert: boolean
|
|
specialPreparations: {
|
|
pureedFood: boolean
|
|
pureedMeat: boolean
|
|
slicedMeat: boolean
|
|
mashedPotatoes: boolean
|
|
}
|
|
restrictions: { noFish: boolean; fingerFood: boolean; onlySweet: boolean }
|
|
}
|
|
|
|
interface DinnerOptions {
|
|
accordingToPlan: boolean
|
|
bread: { greyBread: boolean; wholeGrainBread: boolean; whiteBread: boolean; crispbread: boolean }
|
|
preparation: { spread: boolean; sliced: boolean }
|
|
spreads: { butter: boolean; margarine: boolean }
|
|
soup: boolean
|
|
porridge: boolean
|
|
noFish: boolean
|
|
beverages: { tea: boolean; cocoa: boolean; hotMilk: boolean; coldMilk: boolean }
|
|
additions: { sugar: boolean; sweetener: boolean }
|
|
}
|
|
|
|
const defaultBreakfast: BreakfastOptions = {
|
|
accordingToPlan: false,
|
|
bread: {
|
|
breadRoll: false,
|
|
wholeGrainRoll: false,
|
|
greyBread: false,
|
|
wholeGrainBread: false,
|
|
whiteBread: false,
|
|
crispbread: false,
|
|
},
|
|
porridge: false,
|
|
preparation: { sliced: false, spread: false },
|
|
spreads: {
|
|
butter: false,
|
|
margarine: false,
|
|
jam: false,
|
|
diabeticJam: false,
|
|
honey: false,
|
|
cheese: false,
|
|
quark: false,
|
|
sausage: false,
|
|
},
|
|
beverages: { coffee: false, tea: false, hotMilk: false, coldMilk: false },
|
|
additions: { sugar: false, sweetener: false, coffeeCreamer: false },
|
|
}
|
|
|
|
const defaultLunch: LunchOptions = {
|
|
portionSize: 'large',
|
|
soup: false,
|
|
dessert: true,
|
|
specialPreparations: {
|
|
pureedFood: false,
|
|
pureedMeat: false,
|
|
slicedMeat: false,
|
|
mashedPotatoes: false,
|
|
},
|
|
restrictions: { noFish: false, fingerFood: false, onlySweet: false },
|
|
}
|
|
|
|
const defaultDinner: DinnerOptions = {
|
|
accordingToPlan: false,
|
|
bread: { greyBread: false, wholeGrainBread: false, whiteBread: false, crispbread: false },
|
|
preparation: { spread: false, sliced: false },
|
|
spreads: { butter: false, margarine: false },
|
|
soup: false,
|
|
porridge: false,
|
|
noFish: false,
|
|
beverages: { tea: false, cocoa: false, hotMilk: false, coldMilk: false },
|
|
additions: { sugar: false, sweetener: false },
|
|
}
|
|
|
|
function CheckboxOption({
|
|
id,
|
|
label,
|
|
checked,
|
|
onCheckedChange,
|
|
}: {
|
|
id: string
|
|
label: string
|
|
checked: boolean
|
|
onCheckedChange: (checked: boolean) => void
|
|
}) {
|
|
return (
|
|
<div
|
|
className={cn(
|
|
'flex items-center space-x-3 rounded-lg border p-3 cursor-pointer transition-colors',
|
|
checked ? 'border-primary bg-primary/5' : 'border-border hover:bg-muted/50'
|
|
)}
|
|
onClick={() => onCheckedChange(!checked)}
|
|
>
|
|
<Checkbox id={id} checked={checked} onCheckedChange={onCheckedChange} />
|
|
<Label htmlFor={id} className="cursor-pointer flex-1">
|
|
{label}
|
|
</Label>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
function NewOrderContent() {
|
|
const router = useRouter()
|
|
const searchParams = useSearchParams()
|
|
const initialMealType = (searchParams.get('mealType') as MealType) || null
|
|
|
|
const [step, setStep] = useState(initialMealType ? 2 : 1)
|
|
const [residents, setResidents] = useState<Resident[]>([])
|
|
const [selectedResident, setSelectedResident] = useState<Resident | null>(null)
|
|
const [mealType, setMealType] = useState<MealType | null>(initialMealType)
|
|
const [date, setDate] = useState(() => format(new Date(), 'yyyy-MM-dd'))
|
|
const [breakfast, setBreakfast] = useState<BreakfastOptions>(defaultBreakfast)
|
|
const [lunch, setLunch] = useState<LunchOptions>(defaultLunch)
|
|
const [dinner, setDinner] = useState<DinnerOptions>(defaultDinner)
|
|
const [loading, setLoading] = useState(true)
|
|
const [submitting, setSubmitting] = useState(false)
|
|
const [error, setError] = useState<string | null>(null)
|
|
const [searchQuery, setSearchQuery] = useState('')
|
|
|
|
useEffect(() => {
|
|
const fetchResidents = async () => {
|
|
try {
|
|
const res = await fetch('/api/residents?where[active][equals]=true&limit=100&sort=name', {
|
|
credentials: 'include',
|
|
})
|
|
if (res.ok) {
|
|
const data = await res.json()
|
|
setResidents(data.docs || [])
|
|
} else if (res.status === 401) {
|
|
router.push('/caregiver/login')
|
|
}
|
|
} catch (err) {
|
|
console.error('Error fetching residents:', err)
|
|
} finally {
|
|
setLoading(false)
|
|
}
|
|
}
|
|
fetchResidents()
|
|
}, [router])
|
|
|
|
const filteredResidents = residents.filter(
|
|
(r) =>
|
|
r.name.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
|
r.room.toLowerCase().includes(searchQuery.toLowerCase()),
|
|
)
|
|
|
|
const handleSubmit = async () => {
|
|
if (!selectedResident || !mealType || !date) return
|
|
|
|
setSubmitting(true)
|
|
setError(null)
|
|
|
|
try {
|
|
const orderData: Record<string, unknown> = {
|
|
resident: selectedResident.id,
|
|
date,
|
|
mealType,
|
|
status: 'pending',
|
|
}
|
|
|
|
if (mealType === 'breakfast') {
|
|
orderData.breakfast = breakfast
|
|
} else if (mealType === 'lunch') {
|
|
orderData.lunch = lunch
|
|
} else if (mealType === 'dinner') {
|
|
orderData.dinner = dinner
|
|
}
|
|
|
|
const res = await fetch('/api/meal-orders', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(orderData),
|
|
credentials: 'include',
|
|
})
|
|
|
|
if (!res.ok) {
|
|
const data = await res.json()
|
|
throw new Error(data.errors?.[0]?.message || 'Failed to create order')
|
|
}
|
|
|
|
router.push('/caregiver/dashboard')
|
|
} catch (err) {
|
|
setError(err instanceof Error ? err.message : 'An error occurred')
|
|
} finally {
|
|
setSubmitting(false)
|
|
}
|
|
}
|
|
|
|
const getMealTypeLabel = (type: MealType) => {
|
|
switch (type) {
|
|
case 'breakfast':
|
|
return 'Breakfast (Frühstück)'
|
|
case 'lunch':
|
|
return 'Lunch (Mittagessen)'
|
|
case 'dinner':
|
|
return 'Dinner (Abendessen)'
|
|
}
|
|
}
|
|
|
|
if (loading) {
|
|
return (
|
|
<div className="min-h-screen flex items-center justify-center bg-muted/50">
|
|
<Loader2 className="h-8 w-8 animate-spin text-primary" />
|
|
</div>
|
|
)
|
|
}
|
|
|
|
return (
|
|
<div className="min-h-screen bg-muted/50">
|
|
<header className="sticky top-0 z-50 w-full border-b bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60">
|
|
<div className="container flex h-16 items-center">
|
|
<Button variant="ghost" size="sm" asChild>
|
|
<Link href="/caregiver/dashboard">
|
|
<ArrowLeft className="mr-2 h-4 w-4" />
|
|
Back
|
|
</Link>
|
|
</Button>
|
|
<h1 className="ml-4 text-xl font-semibold">New Meal Order</h1>
|
|
</div>
|
|
</header>
|
|
|
|
<main className="container py-6">
|
|
{/* Progress Steps */}
|
|
<div className="flex gap-2 mb-6">
|
|
{[1, 2, 3, 4].map((s) => (
|
|
<div
|
|
key={s}
|
|
className={cn(
|
|
'h-2 flex-1 rounded-full transition-colors',
|
|
step >= s ? (step > s ? 'bg-green-500' : 'bg-primary') : 'bg-muted'
|
|
)}
|
|
/>
|
|
))}
|
|
</div>
|
|
|
|
{error && (
|
|
<Alert variant="destructive" className="mb-6">
|
|
<AlertTriangle className="h-4 w-4" />
|
|
<AlertDescription>{error}</AlertDescription>
|
|
</Alert>
|
|
)}
|
|
|
|
{/* Step 1: Select Meal Type */}
|
|
{step === 1 && (
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>Step 1: Select Meal Type</CardTitle>
|
|
</CardHeader>
|
|
<CardContent className="space-y-6">
|
|
<div className="space-y-2">
|
|
<Label htmlFor="date">Date</Label>
|
|
<Input
|
|
type="date"
|
|
id="date"
|
|
value={date}
|
|
onChange={(e) => setDate(e.target.value)}
|
|
/>
|
|
</div>
|
|
|
|
<div className="grid gap-4 sm:grid-cols-3">
|
|
{[
|
|
{ type: 'breakfast' as MealType, icon: Sunrise, label: 'Breakfast', sublabel: 'Frühstück', color: 'text-orange-500' },
|
|
{ type: 'lunch' as MealType, icon: Sun, label: 'Lunch', sublabel: 'Mittagessen', color: 'text-yellow-500' },
|
|
{ type: 'dinner' as MealType, icon: Moon, label: 'Dinner', sublabel: 'Abendessen', color: 'text-indigo-500' },
|
|
].map(({ type, icon: Icon, label, sublabel, color }) => (
|
|
<Card
|
|
key={type}
|
|
className={cn(
|
|
'cursor-pointer transition-colors',
|
|
mealType === type ? 'border-primary bg-primary/5' : 'hover:bg-muted/50'
|
|
)}
|
|
onClick={() => setMealType(type)}
|
|
>
|
|
<CardContent className="flex flex-col items-center justify-center p-6">
|
|
<Icon className={cn('h-10 w-10 mb-2', color)} />
|
|
<span className="font-semibold">{label}</span>
|
|
<span className="text-sm text-muted-foreground">{sublabel}</span>
|
|
</CardContent>
|
|
</Card>
|
|
))}
|
|
</div>
|
|
|
|
<Button
|
|
className="w-full"
|
|
size="lg"
|
|
disabled={!mealType}
|
|
onClick={() => setStep(2)}
|
|
>
|
|
Continue
|
|
</Button>
|
|
</CardContent>
|
|
</Card>
|
|
)}
|
|
|
|
{/* Step 2: Select Resident */}
|
|
{step === 2 && (
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>Step 2: Select Resident</CardTitle>
|
|
</CardHeader>
|
|
<CardContent className="space-y-4">
|
|
<div className="relative">
|
|
<Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" />
|
|
<Input
|
|
type="text"
|
|
placeholder="Search by name or room..."
|
|
value={searchQuery}
|
|
onChange={(e) => setSearchQuery(e.target.value)}
|
|
className="pl-10"
|
|
/>
|
|
</div>
|
|
|
|
<div className="grid gap-3 sm:grid-cols-2 lg:grid-cols-3 max-h-96 overflow-y-auto">
|
|
{filteredResidents.map((resident) => (
|
|
<Card
|
|
key={resident.id}
|
|
className={cn(
|
|
'cursor-pointer transition-colors',
|
|
selectedResident?.id === resident.id ? 'border-primary bg-primary/5' : 'hover:bg-muted/50'
|
|
)}
|
|
onClick={() => setSelectedResident(resident)}
|
|
>
|
|
<CardContent className="p-4">
|
|
<div className="font-semibold">{resident.name}</div>
|
|
<div className="flex gap-2 text-sm text-muted-foreground mt-1">
|
|
<span>Room {resident.room}</span>
|
|
{resident.table && <span>Table {resident.table}</span>}
|
|
</div>
|
|
{resident.highCaloric && (
|
|
<Badge variant="secondary" className="mt-2 bg-yellow-100 text-yellow-800">
|
|
High Caloric
|
|
</Badge>
|
|
)}
|
|
</CardContent>
|
|
</Card>
|
|
))}
|
|
</div>
|
|
|
|
<div className="flex gap-4 pt-4">
|
|
<Button variant="outline" onClick={() => setStep(1)}>
|
|
Back
|
|
</Button>
|
|
<Button
|
|
className="flex-1"
|
|
size="lg"
|
|
disabled={!selectedResident}
|
|
onClick={() => setStep(3)}
|
|
>
|
|
Continue
|
|
</Button>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
)}
|
|
|
|
{/* Step 3: Meal Options */}
|
|
{step === 3 && (
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>Step 3: {mealType && getMealTypeLabel(mealType)} Options</CardTitle>
|
|
</CardHeader>
|
|
<CardContent className="space-y-6">
|
|
{(selectedResident?.aversions || selectedResident?.notes) && (
|
|
<Alert>
|
|
<AlertTriangle className="h-4 w-4" />
|
|
<AlertTitle>Notes for {selectedResident?.name}</AlertTitle>
|
|
<AlertDescription>
|
|
{selectedResident?.aversions && <div>Aversions: {selectedResident.aversions}</div>}
|
|
{selectedResident?.notes && <div>{selectedResident.notes}</div>}
|
|
</AlertDescription>
|
|
</Alert>
|
|
)}
|
|
|
|
{/* BREAKFAST OPTIONS */}
|
|
{mealType === 'breakfast' && (
|
|
<>
|
|
<div className="space-y-3">
|
|
<h3 className="font-semibold">General</h3>
|
|
<CheckboxOption
|
|
id="accordingToPlan"
|
|
label="According to Plan (lt. Plan)"
|
|
checked={breakfast.accordingToPlan}
|
|
onCheckedChange={(v) => setBreakfast({ ...breakfast, accordingToPlan: v })}
|
|
/>
|
|
</div>
|
|
|
|
<Separator />
|
|
|
|
<div className="space-y-3">
|
|
<h3 className="font-semibold">Bread (Brot)</h3>
|
|
<div className="grid gap-2 sm:grid-cols-2">
|
|
<CheckboxOption id="breadRoll" label="Bread Roll (Brötchen)" checked={breakfast.bread.breadRoll} onCheckedChange={(v) => setBreakfast({ ...breakfast, bread: { ...breakfast.bread, breadRoll: v } })} />
|
|
<CheckboxOption id="wholeGrainRoll" label="Whole Grain Roll (Vollkornbrötchen)" checked={breakfast.bread.wholeGrainRoll} onCheckedChange={(v) => setBreakfast({ ...breakfast, bread: { ...breakfast.bread, wholeGrainRoll: v } })} />
|
|
<CheckboxOption id="greyBread" label="Grey Bread (Graubrot)" checked={breakfast.bread.greyBread} onCheckedChange={(v) => setBreakfast({ ...breakfast, bread: { ...breakfast.bread, greyBread: v } })} />
|
|
<CheckboxOption id="wholeGrainBread" label="Whole Grain Bread (Vollkornbrot)" checked={breakfast.bread.wholeGrainBread} onCheckedChange={(v) => setBreakfast({ ...breakfast, bread: { ...breakfast.bread, wholeGrainBread: v } })} />
|
|
<CheckboxOption id="whiteBread" label="White Bread (Weißbrot)" checked={breakfast.bread.whiteBread} onCheckedChange={(v) => setBreakfast({ ...breakfast, bread: { ...breakfast.bread, whiteBread: v } })} />
|
|
<CheckboxOption id="crispbread" label="Crispbread (Knäckebrot)" checked={breakfast.bread.crispbread} onCheckedChange={(v) => setBreakfast({ ...breakfast, bread: { ...breakfast.bread, crispbread: v } })} />
|
|
</div>
|
|
</div>
|
|
|
|
<Separator />
|
|
|
|
<div className="space-y-3">
|
|
<h3 className="font-semibold">Preparation</h3>
|
|
<div className="grid gap-2 sm:grid-cols-3">
|
|
<CheckboxOption id="porridge" label="Porridge (Brei)" checked={breakfast.porridge} onCheckedChange={(v) => setBreakfast({ ...breakfast, porridge: v })} />
|
|
<CheckboxOption id="sliced" label="Sliced (geschnitten)" checked={breakfast.preparation.sliced} onCheckedChange={(v) => setBreakfast({ ...breakfast, preparation: { ...breakfast.preparation, sliced: v } })} />
|
|
<CheckboxOption id="spread" label="Spread (geschmiert)" checked={breakfast.preparation.spread} onCheckedChange={(v) => setBreakfast({ ...breakfast, preparation: { ...breakfast.preparation, spread: v } })} />
|
|
</div>
|
|
</div>
|
|
|
|
<Separator />
|
|
|
|
<div className="space-y-3">
|
|
<h3 className="font-semibold">Spreads (Aufstrich)</h3>
|
|
<div className="grid gap-2 sm:grid-cols-2">
|
|
<CheckboxOption id="butter" label="Butter" checked={breakfast.spreads.butter} onCheckedChange={(v) => setBreakfast({ ...breakfast, spreads: { ...breakfast.spreads, butter: v } })} />
|
|
<CheckboxOption id="margarine" label="Margarine" checked={breakfast.spreads.margarine} onCheckedChange={(v) => setBreakfast({ ...breakfast, spreads: { ...breakfast.spreads, margarine: v } })} />
|
|
<CheckboxOption id="jam" label="Jam (Konfitüre)" checked={breakfast.spreads.jam} onCheckedChange={(v) => setBreakfast({ ...breakfast, spreads: { ...breakfast.spreads, jam: v } })} />
|
|
<CheckboxOption id="diabeticJam" label="Diabetic Jam (Diab. Konfitüre)" checked={breakfast.spreads.diabeticJam} onCheckedChange={(v) => setBreakfast({ ...breakfast, spreads: { ...breakfast.spreads, diabeticJam: v } })} />
|
|
<CheckboxOption id="honey" label="Honey (Honig)" checked={breakfast.spreads.honey} onCheckedChange={(v) => setBreakfast({ ...breakfast, spreads: { ...breakfast.spreads, honey: v } })} />
|
|
<CheckboxOption id="cheese" label="Cheese (Käse)" checked={breakfast.spreads.cheese} onCheckedChange={(v) => setBreakfast({ ...breakfast, spreads: { ...breakfast.spreads, cheese: v } })} />
|
|
<CheckboxOption id="quark" label="Quark" checked={breakfast.spreads.quark} onCheckedChange={(v) => setBreakfast({ ...breakfast, spreads: { ...breakfast.spreads, quark: v } })} />
|
|
<CheckboxOption id="sausage" label="Sausage (Wurst)" checked={breakfast.spreads.sausage} onCheckedChange={(v) => setBreakfast({ ...breakfast, spreads: { ...breakfast.spreads, sausage: v } })} />
|
|
</div>
|
|
</div>
|
|
|
|
<Separator />
|
|
|
|
<div className="space-y-3">
|
|
<h3 className="font-semibold">Beverages (Getränke)</h3>
|
|
<div className="grid gap-2 sm:grid-cols-2">
|
|
<CheckboxOption id="coffee" label="Coffee (Kaffee)" checked={breakfast.beverages.coffee} onCheckedChange={(v) => setBreakfast({ ...breakfast, beverages: { ...breakfast.beverages, coffee: v } })} />
|
|
<CheckboxOption id="tea" label="Tea (Tee)" checked={breakfast.beverages.tea} onCheckedChange={(v) => setBreakfast({ ...breakfast, beverages: { ...breakfast.beverages, tea: v } })} />
|
|
<CheckboxOption id="hotMilk" label="Hot Milk (Milch heiß)" checked={breakfast.beverages.hotMilk} onCheckedChange={(v) => setBreakfast({ ...breakfast, beverages: { ...breakfast.beverages, hotMilk: v } })} />
|
|
<CheckboxOption id="coldMilk" label="Cold Milk (Milch kalt)" checked={breakfast.beverages.coldMilk} onCheckedChange={(v) => setBreakfast({ ...breakfast, beverages: { ...breakfast.beverages, coldMilk: v } })} />
|
|
</div>
|
|
</div>
|
|
|
|
<Separator />
|
|
|
|
<div className="space-y-3">
|
|
<h3 className="font-semibold">Additions (Zusätze)</h3>
|
|
<div className="grid gap-2 sm:grid-cols-3">
|
|
<CheckboxOption id="sugar" label="Sugar (Zucker)" checked={breakfast.additions.sugar} onCheckedChange={(v) => setBreakfast({ ...breakfast, additions: { ...breakfast.additions, sugar: v } })} />
|
|
<CheckboxOption id="sweetener" label="Sweetener (Süßstoff)" checked={breakfast.additions.sweetener} onCheckedChange={(v) => setBreakfast({ ...breakfast, additions: { ...breakfast.additions, sweetener: v } })} />
|
|
<CheckboxOption id="coffeeCreamer" label="Coffee Creamer (Kaffeesahne)" checked={breakfast.additions.coffeeCreamer} onCheckedChange={(v) => setBreakfast({ ...breakfast, additions: { ...breakfast.additions, coffeeCreamer: v } })} />
|
|
</div>
|
|
</div>
|
|
</>
|
|
)}
|
|
|
|
{/* LUNCH OPTIONS */}
|
|
{mealType === 'lunch' && (
|
|
<>
|
|
<div className="space-y-3">
|
|
<h3 className="font-semibold">Portion Size</h3>
|
|
<RadioGroup
|
|
value={lunch.portionSize}
|
|
onValueChange={(v) => setLunch({ ...lunch, portionSize: v as 'small' | 'large' | 'vegetarian' })}
|
|
className="grid gap-2 sm:grid-cols-3"
|
|
>
|
|
{[
|
|
{ value: 'small', label: 'Small (Kleine)' },
|
|
{ value: 'large', label: 'Large (Große)' },
|
|
{ value: 'vegetarian', label: 'Vegetarian' },
|
|
].map(({ value, label }) => (
|
|
<div
|
|
key={value}
|
|
className={cn(
|
|
'flex items-center space-x-3 rounded-lg border p-3 cursor-pointer transition-colors',
|
|
lunch.portionSize === value ? 'border-primary bg-primary/5' : 'border-border hover:bg-muted/50'
|
|
)}
|
|
onClick={() => setLunch({ ...lunch, portionSize: value as 'small' | 'large' | 'vegetarian' })}
|
|
>
|
|
<RadioGroupItem value={value} id={value} />
|
|
<Label htmlFor={value} className="cursor-pointer">{label}</Label>
|
|
</div>
|
|
))}
|
|
</RadioGroup>
|
|
</div>
|
|
|
|
<Separator />
|
|
|
|
<div className="space-y-3">
|
|
<h3 className="font-semibold">Meal Options</h3>
|
|
<div className="grid gap-2 sm:grid-cols-2">
|
|
<CheckboxOption id="soup" label="Soup (Suppe)" checked={lunch.soup} onCheckedChange={(v) => setLunch({ ...lunch, soup: v })} />
|
|
<CheckboxOption id="dessert" label="Dessert" checked={lunch.dessert} onCheckedChange={(v) => setLunch({ ...lunch, dessert: v })} />
|
|
</div>
|
|
</div>
|
|
|
|
<Separator />
|
|
|
|
<div className="space-y-3">
|
|
<h3 className="font-semibold">Special Preparations</h3>
|
|
<div className="grid gap-2 sm:grid-cols-2">
|
|
<CheckboxOption id="pureedFood" label="Pureed Food (passierte Kost)" checked={lunch.specialPreparations.pureedFood} onCheckedChange={(v) => setLunch({ ...lunch, specialPreparations: { ...lunch.specialPreparations, pureedFood: v } })} />
|
|
<CheckboxOption id="pureedMeat" label="Pureed Meat (passiertes Fleisch)" checked={lunch.specialPreparations.pureedMeat} onCheckedChange={(v) => setLunch({ ...lunch, specialPreparations: { ...lunch.specialPreparations, pureedMeat: v } })} />
|
|
<CheckboxOption id="slicedMeat" label="Sliced Meat (geschnittenes Fleisch)" checked={lunch.specialPreparations.slicedMeat} onCheckedChange={(v) => setLunch({ ...lunch, specialPreparations: { ...lunch.specialPreparations, slicedMeat: v } })} />
|
|
<CheckboxOption id="mashedPotatoes" label="Mashed Potatoes (Kartoffelbrei)" checked={lunch.specialPreparations.mashedPotatoes} onCheckedChange={(v) => setLunch({ ...lunch, specialPreparations: { ...lunch.specialPreparations, mashedPotatoes: v } })} />
|
|
</div>
|
|
</div>
|
|
|
|
<Separator />
|
|
|
|
<div className="space-y-3">
|
|
<h3 className="font-semibold">Restrictions</h3>
|
|
<div className="grid gap-2 sm:grid-cols-3">
|
|
<CheckboxOption id="noFish" label="No Fish (ohne Fisch)" checked={lunch.restrictions.noFish} onCheckedChange={(v) => setLunch({ ...lunch, restrictions: { ...lunch.restrictions, noFish: v } })} />
|
|
<CheckboxOption id="fingerFood" label="Finger Food" checked={lunch.restrictions.fingerFood} onCheckedChange={(v) => setLunch({ ...lunch, restrictions: { ...lunch.restrictions, fingerFood: v } })} />
|
|
<CheckboxOption id="onlySweet" label="Only Sweet (nur süß)" checked={lunch.restrictions.onlySweet} onCheckedChange={(v) => setLunch({ ...lunch, restrictions: { ...lunch.restrictions, onlySweet: v } })} />
|
|
</div>
|
|
</div>
|
|
</>
|
|
)}
|
|
|
|
{/* DINNER OPTIONS */}
|
|
{mealType === 'dinner' && (
|
|
<>
|
|
<div className="space-y-3">
|
|
<h3 className="font-semibold">General</h3>
|
|
<CheckboxOption
|
|
id="dinnerAccordingToPlan"
|
|
label="According to Plan (lt. Plan)"
|
|
checked={dinner.accordingToPlan}
|
|
onCheckedChange={(v) => setDinner({ ...dinner, accordingToPlan: v })}
|
|
/>
|
|
</div>
|
|
|
|
<Separator />
|
|
|
|
<div className="space-y-3">
|
|
<h3 className="font-semibold">Bread (Brot)</h3>
|
|
<div className="grid gap-2 sm:grid-cols-2">
|
|
<CheckboxOption id="dinnerGreyBread" label="Grey Bread (Graubrot)" checked={dinner.bread.greyBread} onCheckedChange={(v) => setDinner({ ...dinner, bread: { ...dinner.bread, greyBread: v } })} />
|
|
<CheckboxOption id="dinnerWholeGrainBread" label="Whole Grain Bread (Vollkornbrot)" checked={dinner.bread.wholeGrainBread} onCheckedChange={(v) => setDinner({ ...dinner, bread: { ...dinner.bread, wholeGrainBread: v } })} />
|
|
<CheckboxOption id="dinnerWhiteBread" label="White Bread (Weißbrot)" checked={dinner.bread.whiteBread} onCheckedChange={(v) => setDinner({ ...dinner, bread: { ...dinner.bread, whiteBread: v } })} />
|
|
<CheckboxOption id="dinnerCrispbread" label="Crispbread (Knäckebrot)" checked={dinner.bread.crispbread} onCheckedChange={(v) => setDinner({ ...dinner, bread: { ...dinner.bread, crispbread: v } })} />
|
|
</div>
|
|
</div>
|
|
|
|
<Separator />
|
|
|
|
<div className="space-y-3">
|
|
<h3 className="font-semibold">Preparation</h3>
|
|
<div className="grid gap-2 sm:grid-cols-2">
|
|
<CheckboxOption id="dinnerSpread" label="Spread (geschmiert)" checked={dinner.preparation.spread} onCheckedChange={(v) => setDinner({ ...dinner, preparation: { ...dinner.preparation, spread: v } })} />
|
|
<CheckboxOption id="dinnerSliced" label="Sliced (geschnitten)" checked={dinner.preparation.sliced} onCheckedChange={(v) => setDinner({ ...dinner, preparation: { ...dinner.preparation, sliced: v } })} />
|
|
</div>
|
|
</div>
|
|
|
|
<Separator />
|
|
|
|
<div className="space-y-3">
|
|
<h3 className="font-semibold">Spreads (Aufstrich)</h3>
|
|
<div className="grid gap-2 sm:grid-cols-2">
|
|
<CheckboxOption id="dinnerButter" label="Butter" checked={dinner.spreads.butter} onCheckedChange={(v) => setDinner({ ...dinner, spreads: { ...dinner.spreads, butter: v } })} />
|
|
<CheckboxOption id="dinnerMargarine" label="Margarine" checked={dinner.spreads.margarine} onCheckedChange={(v) => setDinner({ ...dinner, spreads: { ...dinner.spreads, margarine: v } })} />
|
|
</div>
|
|
</div>
|
|
|
|
<Separator />
|
|
|
|
<div className="space-y-3">
|
|
<h3 className="font-semibold">Additional Items</h3>
|
|
<div className="grid gap-2 sm:grid-cols-3">
|
|
<CheckboxOption id="dinnerSoup" label="Soup (Suppe)" checked={dinner.soup} onCheckedChange={(v) => setDinner({ ...dinner, soup: v })} />
|
|
<CheckboxOption id="dinnerPorridge" label="Porridge (Brei)" checked={dinner.porridge} onCheckedChange={(v) => setDinner({ ...dinner, porridge: v })} />
|
|
<CheckboxOption id="dinnerNoFish" label="No Fish (ohne Fisch)" checked={dinner.noFish} onCheckedChange={(v) => setDinner({ ...dinner, noFish: v })} />
|
|
</div>
|
|
</div>
|
|
|
|
<Separator />
|
|
|
|
<div className="space-y-3">
|
|
<h3 className="font-semibold">Beverages (Getränke)</h3>
|
|
<div className="grid gap-2 sm:grid-cols-2">
|
|
<CheckboxOption id="dinnerTea" label="Tea (Tee)" checked={dinner.beverages.tea} onCheckedChange={(v) => setDinner({ ...dinner, beverages: { ...dinner.beverages, tea: v } })} />
|
|
<CheckboxOption id="dinnerCocoa" label="Cocoa (Kakao)" checked={dinner.beverages.cocoa} onCheckedChange={(v) => setDinner({ ...dinner, beverages: { ...dinner.beverages, cocoa: v } })} />
|
|
<CheckboxOption id="dinnerHotMilk" label="Hot Milk (Milch heiß)" checked={dinner.beverages.hotMilk} onCheckedChange={(v) => setDinner({ ...dinner, beverages: { ...dinner.beverages, hotMilk: v } })} />
|
|
<CheckboxOption id="dinnerColdMilk" label="Cold Milk (Milch kalt)" checked={dinner.beverages.coldMilk} onCheckedChange={(v) => setDinner({ ...dinner, beverages: { ...dinner.beverages, coldMilk: v } })} />
|
|
</div>
|
|
</div>
|
|
|
|
<Separator />
|
|
|
|
<div className="space-y-3">
|
|
<h3 className="font-semibold">Additions (Zusätze)</h3>
|
|
<div className="grid gap-2 sm:grid-cols-2">
|
|
<CheckboxOption id="dinnerSugar" label="Sugar (Zucker)" checked={dinner.additions.sugar} onCheckedChange={(v) => setDinner({ ...dinner, additions: { ...dinner.additions, sugar: v } })} />
|
|
<CheckboxOption id="dinnerSweetener" label="Sweetener (Süßstoff)" checked={dinner.additions.sweetener} onCheckedChange={(v) => setDinner({ ...dinner, additions: { ...dinner.additions, sweetener: v } })} />
|
|
</div>
|
|
</div>
|
|
</>
|
|
)}
|
|
|
|
<div className="flex gap-4 pt-4">
|
|
<Button variant="outline" onClick={() => setStep(2)}>
|
|
Back
|
|
</Button>
|
|
<Button className="flex-1" size="lg" onClick={() => setStep(4)}>
|
|
Review Order
|
|
</Button>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
)}
|
|
|
|
{/* Step 4: Review and Submit */}
|
|
{step === 4 && (
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>Step 4: Review & Submit</CardTitle>
|
|
</CardHeader>
|
|
<CardContent className="space-y-6">
|
|
<div className="rounded-lg bg-muted p-4 space-y-3">
|
|
<div className="flex justify-between">
|
|
<span className="text-muted-foreground">Resident</span>
|
|
<span className="font-medium">{selectedResident?.name}</span>
|
|
</div>
|
|
<Separator />
|
|
<div className="flex justify-between">
|
|
<span className="text-muted-foreground">Room</span>
|
|
<span className="font-medium">{selectedResident?.room}</span>
|
|
</div>
|
|
<Separator />
|
|
<div className="flex justify-between">
|
|
<span className="text-muted-foreground">Date</span>
|
|
<span className="font-medium">{date}</span>
|
|
</div>
|
|
<Separator />
|
|
<div className="flex justify-between">
|
|
<span className="text-muted-foreground">Meal Type</span>
|
|
<span className="font-medium">{mealType && getMealTypeLabel(mealType)}</span>
|
|
</div>
|
|
</div>
|
|
|
|
{selectedResident?.highCaloric && (
|
|
<Alert>
|
|
<AlertTriangle className="h-4 w-4" />
|
|
<AlertDescription>
|
|
<strong>Note:</strong> This resident requires high caloric meals.
|
|
</AlertDescription>
|
|
</Alert>
|
|
)}
|
|
|
|
<div className="flex gap-4">
|
|
<Button variant="outline" onClick={() => setStep(3)}>
|
|
Back
|
|
</Button>
|
|
<Button
|
|
className="flex-1 bg-green-600 hover:bg-green-700"
|
|
size="lg"
|
|
onClick={handleSubmit}
|
|
disabled={submitting}
|
|
>
|
|
{submitting ? (
|
|
<>
|
|
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
|
Creating...
|
|
</>
|
|
) : (
|
|
<>
|
|
<Check className="mr-2 h-4 w-4" />
|
|
Create Order
|
|
</>
|
|
)}
|
|
</Button>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
)}
|
|
</main>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export default function NewOrderPage() {
|
|
return (
|
|
<Suspense
|
|
fallback={
|
|
<div className="min-h-screen flex items-center justify-center bg-muted/50">
|
|
<Loader2 className="h-8 w-8 animate-spin text-primary" />
|
|
</div>
|
|
}
|
|
>
|
|
<NewOrderContent />
|
|
</Suspense>
|
|
)
|
|
}
|