2025-12-05 13:53:29 +01:00

178 lines
5.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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"> &rarr;</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"> &rarr;</span>
</a>
}
/>
</div>
)}
</>
);
}