178 lines
5.6 KiB
TypeScript
178 lines
5.6 KiB
TypeScript
// app/(app)/dashboard/page.tsx
|
||
import Alerts from '@/components/ui/Alerts';
|
||
import { prisma } from '@/lib/prisma';
|
||
|
||
const dtf = new Intl.DateTimeFormat('de-DE', {
|
||
dateStyle: 'short',
|
||
});
|
||
|
||
export default async function DashboardPage() {
|
||
const now = new Date();
|
||
|
||
// Start / Ende des heutigen Tages (ohne Uhrzeit)
|
||
const startOfToday = new Date(
|
||
now.getFullYear(),
|
||
now.getMonth(),
|
||
now.getDate(),
|
||
);
|
||
const startOfTomorrow = new Date(
|
||
now.getFullYear(),
|
||
now.getMonth(),
|
||
now.getDate() + 1,
|
||
);
|
||
|
||
// 🔴 Überfällige Geräte: loanedUntil < heute
|
||
const overdueDevices = await prisma.device.findMany({
|
||
where: {
|
||
loanedTo: { not: null },
|
||
loanedUntil: { lt: startOfToday },
|
||
},
|
||
orderBy: { loanedUntil: 'asc' },
|
||
select: {
|
||
inventoryNumber: true,
|
||
name: true,
|
||
loanedTo: true,
|
||
loanedUntil: true,
|
||
},
|
||
});
|
||
|
||
// 🟡 Heute fällige Geräte: loanedUntil am heutigen Tag
|
||
const dueTodayDevices = await prisma.device.findMany({
|
||
where: {
|
||
loanedTo: { not: null },
|
||
loanedUntil: {
|
||
gte: startOfToday,
|
||
lt: startOfTomorrow,
|
||
},
|
||
},
|
||
orderBy: { loanedUntil: 'asc' },
|
||
select: {
|
||
inventoryNumber: true,
|
||
name: true,
|
||
loanedTo: true,
|
||
loanedUntil: true,
|
||
},
|
||
});
|
||
|
||
const hasOverdue = overdueDevices.length > 0;
|
||
const hasDueToday = dueTodayDevices.length > 0;
|
||
|
||
return (
|
||
<>
|
||
{/* 🔴 Überfällige Geräte (rot) */}
|
||
{hasOverdue && (
|
||
<div className="mb-4">
|
||
<Alerts
|
||
tone="error"
|
||
title={
|
||
overdueDevices.length === 1
|
||
? 'Es gibt ein überfälliges Gerät'
|
||
: `Es gibt ${overdueDevices.length} überfällige Geräte`
|
||
}
|
||
description={
|
||
<div className="space-y-2">
|
||
<p>Diese Geräte haben das Rückgabedatum bereits überschritten:</p>
|
||
<ul className="list-disc space-y-1 pl-5 text-sm">
|
||
{overdueDevices.map((d) => (
|
||
<li key={d.inventoryNumber}>
|
||
<span className="font-mono">
|
||
{d.inventoryNumber}
|
||
</span>
|
||
{d.name && (
|
||
<>
|
||
{' – '}
|
||
<a
|
||
href={`/devices?device=${encodeURIComponent(
|
||
d.inventoryNumber,
|
||
)}`}
|
||
className="font-medium underline text-red-800 hover:text-red-700 dark:text-red-200 dark:hover:text-red-100"
|
||
>
|
||
{d.name}
|
||
</a>
|
||
</>
|
||
)}
|
||
{d.loanedTo && <span> (an {d.loanedTo})</span>}
|
||
{d.loanedUntil && (
|
||
<span>
|
||
{' '}
|
||
– fällig am {dtf.format(d.loanedUntil)}
|
||
</span>
|
||
)}
|
||
</li>
|
||
))}
|
||
</ul>
|
||
</div>
|
||
}
|
||
rightContent={
|
||
<a
|
||
href="/devices"
|
||
className="font-medium whitespace-nowrap text-red-800 hover:text-red-700 dark:text-red-200 dark:hover:text-red-100"
|
||
>
|
||
Zur Geräteliste
|
||
<span aria-hidden="true"> →</span>
|
||
</a>
|
||
}
|
||
/>
|
||
</div>
|
||
)}
|
||
|
||
{/* 🟡 Heute fällige Geräte (gelb) */}
|
||
{hasDueToday && (
|
||
<div className="mb-4">
|
||
<Alerts
|
||
tone="warning"
|
||
title={
|
||
dueTodayDevices.length === 1
|
||
? 'Ein Gerät ist heute fällig'
|
||
: `${dueTodayDevices.length} Geräte sind heute fällig`
|
||
}
|
||
description={
|
||
<div className="space-y-2">
|
||
<p>Diese Geräte sollten heute zurückgegeben werden:</p>
|
||
<ul className="list-disc space-y-1 pl-5 text-sm">
|
||
{dueTodayDevices.map((d) => (
|
||
<li key={d.inventoryNumber}>
|
||
<span className="font-mono">
|
||
{d.inventoryNumber}
|
||
</span>
|
||
{d.name && (
|
||
<>
|
||
{' – '}
|
||
<a
|
||
href={`/devices?device=${encodeURIComponent(
|
||
d.inventoryNumber,
|
||
)}`}
|
||
className="font-medium underline text-yellow-800 hover:text-yellow-700 dark:text-yellow-200 dark:hover:text-yellow-100"
|
||
>
|
||
{d.name}
|
||
</a>
|
||
</>
|
||
)}
|
||
{d.loanedTo && <span> (an {d.loanedTo})</span>}
|
||
{d.loanedUntil && (
|
||
<span>
|
||
{' '}
|
||
– fällig am {dtf.format(d.loanedUntil)}
|
||
</span>
|
||
)}
|
||
</li>
|
||
))}
|
||
</ul>
|
||
</div>
|
||
}
|
||
rightContent={
|
||
<a
|
||
href="/devices"
|
||
className="font-medium whitespace-nowrap text-yellow-800 hover:text-yellow-700 dark:text-yellow-200 dark:hover:text-yellow-100"
|
||
>
|
||
Zur Geräteliste
|
||
<span aria-hidden="true"> →</span>
|
||
</a>
|
||
}
|
||
/>
|
||
</div>
|
||
)}
|
||
</>
|
||
);
|
||
}
|