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,168 @@
'use client'
import React, { useState, useEffect } from 'react'
import { useRouter } from 'next/navigation'
import Link from 'next/link'
interface Resident {
id: number
name: string
room: string
}
interface MealOrder {
id: number
title: string
date: string
mealType: 'breakfast' | 'lunch' | 'dinner'
status: 'pending' | 'preparing' | 'prepared'
resident: Resident | number
createdAt: string
}
export default function OrdersListPage() {
const router = useRouter()
const [orders, setOrders] = useState<MealOrder[]>([])
const [loading, setLoading] = useState(true)
const [dateFilter, setDateFilter] = useState(() => new Date().toISOString().split('T')[0])
const [mealTypeFilter, setMealTypeFilter] = useState<string>('all')
useEffect(() => {
const fetchOrders = async () => {
setLoading(true)
try {
let url = `/api/meal-orders?sort=-createdAt&limit=100&depth=1`
if (dateFilter) {
url += `&where[date][equals]=${dateFilter}`
}
if (mealTypeFilter !== 'all') {
url += `&where[mealType][equals]=${mealTypeFilter}`
}
const res = await fetch(url, { credentials: 'include' })
if (res.ok) {
const data = await res.json()
setOrders(data.docs || [])
} else if (res.status === 401) {
router.push('/caregiver/login')
}
} catch (err) {
console.error('Error fetching orders:', err)
} finally {
setLoading(false)
}
}
fetchOrders()
}, [router, dateFilter, mealTypeFilter])
const getMealTypeLabel = (type: string) => {
switch (type) {
case 'breakfast':
return 'Breakfast'
case 'lunch':
return 'Lunch'
case 'dinner':
return 'Dinner'
default:
return type
}
}
const getStatusBadge = (status: string) => {
return <span className={`badge badge--${status}`}>{status.charAt(0).toUpperCase() + status.slice(1)}</span>
}
const getResidentName = (resident: Resident | number) => {
if (typeof resident === 'object') {
return resident.name
}
return `Resident #${resident}`
}
return (
<>
<header className="header">
<div className="header__content">
<Link href="/caregiver/dashboard" className="btn btn--secondary">
&larr; Back
</Link>
<h1 className="header__title">Meal Orders</h1>
<Link href="/caregiver/orders/new" className="btn btn--primary">
+ New Order
</Link>
</div>
</header>
<main className="container">
<div className="card">
<div className="card__header">
<h2>Filter Orders</h2>
</div>
<div className="card__body">
<div className="grid grid--2">
<div className="form-group">
<label htmlFor="date">Date</label>
<input
type="date"
id="date"
className="input"
value={dateFilter}
onChange={(e) => setDateFilter(e.target.value)}
/>
</div>
<div className="form-group">
<label htmlFor="mealType">Meal Type</label>
<select
id="mealType"
className="select"
value={mealTypeFilter}
onChange={(e) => setMealTypeFilter(e.target.value)}
>
<option value="all">All Types</option>
<option value="breakfast">Breakfast</option>
<option value="lunch">Lunch</option>
<option value="dinner">Dinner</option>
</select>
</div>
</div>
</div>
</div>
<div className="card" style={{ marginTop: '1rem' }}>
<div className="card__body" style={{ padding: 0, overflowX: 'auto' }}>
{loading ? (
<div style={{ padding: '2rem', textAlign: 'center' }}>
<div className="spinner" style={{ margin: '0 auto' }} />
</div>
) : orders.length === 0 ? (
<div style={{ padding: '2rem', textAlign: 'center', color: 'var(--gray-500)' }}>
No orders found for the selected criteria.
</div>
) : (
<table className="table">
<thead>
<tr>
<th>Resident</th>
<th>Date</th>
<th>Meal</th>
<th>Status</th>
</tr>
</thead>
<tbody>
{orders.map((order) => (
<tr key={order.id}>
<td>{getResidentName(order.resident)}</td>
<td>{order.date}</td>
<td>{getMealTypeLabel(order.mealType)}</td>
<td>{getStatusBadge(order.status)}</td>
</tr>
))}
</tbody>
</table>
)}
</div>
</div>
</main>
</>
)
}