feat: display published Notdienst assignments in appointment calendar with custom styling for own assignments
This commit is contained in:
@@ -62,6 +62,8 @@ const categories = [
|
||||
{ label: "Fest", type: TerminType.KITA_FEST, color: "var(--good)" },
|
||||
{ label: "Geburtstag", type: TerminType.GEBURTSTAG_INTERN, color: "oklch(0.50 0.10 320)" },
|
||||
{ label: "Elterndienst", type: "elterndienst", color: "oklch(0.60 0.15 160)" },
|
||||
{ label: "Mein Notdienst", type: "mein-notdienst", color: "oklch(0.60 0.18 45)" },
|
||||
{ label: "Notdienst", type: "notdienst", color: "oklch(0.75 0.10 50)" },
|
||||
{ label: "Sonstiges", type: TerminType.SONSTIGES, color: "var(--ink-muted)" },
|
||||
];
|
||||
|
||||
@@ -113,15 +115,26 @@ export function CalendarOverviewClient({
|
||||
? item.description.toLowerCase().includes(query)
|
||||
: false;
|
||||
const familyMatch =
|
||||
item.kind === "duty" && item.familyName
|
||||
(item.kind === "duty" || item.kind === "notdienst") && item.familyName
|
||||
? item.familyName.toLowerCase().includes(query)
|
||||
: false;
|
||||
if (!titleMatch && !descMatch && !familyMatch) return false;
|
||||
const childMatch =
|
||||
item.kind === "notdienst" && item.childName
|
||||
? item.childName.toLowerCase().includes(query)
|
||||
: false;
|
||||
if (!titleMatch && !descMatch && !familyMatch && !childMatch) return false;
|
||||
}
|
||||
|
||||
// 2. Category filter
|
||||
if (activeTypes.size > 0) {
|
||||
const itemType = item.kind === "duty" ? "elterndienst" : item.type;
|
||||
const itemType =
|
||||
item.kind === "duty"
|
||||
? "elterndienst"
|
||||
: item.kind === "notdienst"
|
||||
? item.isOwn
|
||||
? "mein-notdienst"
|
||||
: "notdienst"
|
||||
: item.type;
|
||||
if (!activeTypes.has(itemType)) return false;
|
||||
}
|
||||
|
||||
@@ -309,6 +322,59 @@ export function CalendarOverviewClient({
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
) : item.kind === "notdienst" ? (
|
||||
<div className="flex items-start gap-3">
|
||||
<div
|
||||
className="absolute inset-y-3 left-0 w-[4px] rounded-r-full"
|
||||
style={{
|
||||
backgroundColor: item.isOwn
|
||||
? "oklch(0.60 0.18 45)"
|
||||
: "oklch(0.75 0.10 50)",
|
||||
}}
|
||||
/>
|
||||
<div className="pl-2 flex-1 min-w-0">
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
<h4 className="font-semibold text-[15px] text-[var(--ink)] truncate">
|
||||
{item.title}
|
||||
</h4>
|
||||
<Badge
|
||||
variant="secondary"
|
||||
style={{
|
||||
color: item.isOwn
|
||||
? "oklch(0.60 0.18 45)"
|
||||
: "oklch(0.75 0.10 50)",
|
||||
borderColor:
|
||||
(item.isOwn
|
||||
? "oklch(0.60 0.18 45)"
|
||||
: "oklch(0.75 0.10 50)") + "44",
|
||||
backgroundColor:
|
||||
(item.isOwn
|
||||
? "oklch(0.60 0.18 45)"
|
||||
: "oklch(0.75 0.10 50)") + "11",
|
||||
}}
|
||||
className="border text-[10px]"
|
||||
>
|
||||
{item.isOwn ? "Mein Notdienst" : "Notdienst"}
|
||||
</Badge>
|
||||
</div>
|
||||
<p className="mt-1 text-sm text-[var(--ink-soft)]">
|
||||
Kind: {item.childName} (Familie: {item.familyName})
|
||||
</p>
|
||||
<p className="mt-1 text-xs text-[var(--ink-muted)] flex items-center gap-1">
|
||||
<Clock className="h-3.5 w-3.5" />
|
||||
{format(new Date(item.startDate), "dd.MM.yyyy")}
|
||||
</p>
|
||||
{isAdmin && (
|
||||
<div className="mt-3 flex gap-2">
|
||||
<a href="/dashboard/notdienst/plan">
|
||||
<Button size="sm" variant="outline" className="h-7 text-xs px-2.5">
|
||||
Im Planer bearbeiten
|
||||
</Button>
|
||||
</a>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex items-start gap-3">
|
||||
<div
|
||||
@@ -539,6 +605,10 @@ function MonthView({
|
||||
const color =
|
||||
item.kind === "duty"
|
||||
? "oklch(0.60 0.15 160)"
|
||||
: item.kind === "notdienst"
|
||||
? item.isOwn
|
||||
? "oklch(0.60 0.18 45)"
|
||||
: "oklch(0.75 0.10 50)"
|
||||
: getCategoryColor(item.type);
|
||||
return (
|
||||
<div
|
||||
@@ -632,8 +702,14 @@ function AgendaView({
|
||||
{/* Items stack on right */}
|
||||
<div className="space-y-3">
|
||||
{group.items.map((item) => {
|
||||
const isTermin = item.kind === "termin";
|
||||
const color = isTermin ? getCategoryColor(item.type) : "oklch(0.60 0.15 160)";
|
||||
const color =
|
||||
item.kind === "termin"
|
||||
? getCategoryColor(item.type)
|
||||
: item.kind === "notdienst"
|
||||
? item.isOwn
|
||||
? "oklch(0.60 0.18 45)"
|
||||
: "oklch(0.75 0.10 50)"
|
||||
: "oklch(0.60 0.15 160)";
|
||||
|
||||
return (
|
||||
<div
|
||||
@@ -650,7 +726,7 @@ function AgendaView({
|
||||
<h4 className="font-bold text-[15px] text-[var(--ink)] truncate">
|
||||
{item.title}
|
||||
</h4>
|
||||
{isTermin ? (
|
||||
{item.kind === "termin" ? (
|
||||
<span
|
||||
className="inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-[10px] font-bold border"
|
||||
style={{
|
||||
@@ -661,34 +737,52 @@ function AgendaView({
|
||||
>
|
||||
{getTypeLabel(item.type)}
|
||||
</span>
|
||||
) : item.kind === "notdienst" ? (
|
||||
<Badge
|
||||
variant="secondary"
|
||||
className="text-[10px]"
|
||||
style={{
|
||||
color,
|
||||
borderColor: color + "44",
|
||||
backgroundColor: color + "11",
|
||||
}}
|
||||
>
|
||||
{item.isOwn ? "Mein Notdienst" : "Notdienst"}
|
||||
</Badge>
|
||||
) : (
|
||||
<Badge variant="secondary" className="bg-[oklch(0.95_0.02_160)] text-[oklch(0.40_0.10_160)] text-[10px]">
|
||||
Elterndienst
|
||||
</Badge>
|
||||
)}
|
||||
{isTermin && item.status === TerminStatus.PENDING && (
|
||||
{item.kind === "termin" && item.status === TerminStatus.PENDING && (
|
||||
<Badge variant="warning" className="text-[10px]">Ausstehend</Badge>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<p className="mt-1 text-xs text-[var(--ink-muted)] flex items-center gap-1.5">
|
||||
<Clock className="h-3.5 w-3.5" />
|
||||
{isTermin
|
||||
{item.kind === "termin"
|
||||
? item.allDay
|
||||
? "Ganztägig"
|
||||
: `${format(new Date(item.startDate), "HH:mm")} - ${format(
|
||||
new Date(item.endDate),
|
||||
"HH:mm",
|
||||
)}`
|
||||
: item.kind === "notdienst"
|
||||
? `${format(new Date(item.startDate), "dd.MM.yyyy")} (ganztägig)`
|
||||
: `${format(new Date(item.startDate), "dd.MM.")} - ${format(
|
||||
new Date(item.endDate),
|
||||
"dd.MM.yyyy",
|
||||
)}`}
|
||||
{isTermin && <MapPin className="ml-1 h-3.5 w-3.5" />}
|
||||
{isTermin ? "Kita" : `Familie: ${item.familyName}`}
|
||||
{item.kind === "termin" && <MapPin className="ml-1 h-3.5 w-3.5" />}
|
||||
{item.kind === "termin"
|
||||
? "Kita"
|
||||
: item.kind === "notdienst"
|
||||
? `Kind: ${item.childName} · Familie: ${item.familyName}`
|
||||
: `Familie: ${item.familyName}`}
|
||||
</p>
|
||||
|
||||
{isTermin && item.description && (
|
||||
{item.kind === "termin" && item.description && (
|
||||
<p className="mt-2 text-sm text-[var(--ink-soft)] line-clamp-2 leading-relaxed">
|
||||
{item.description}
|
||||
</p>
|
||||
@@ -697,7 +791,7 @@ function AgendaView({
|
||||
</div>
|
||||
|
||||
{/* Actions for admins */}
|
||||
{isAdmin && isTermin && (
|
||||
{isAdmin && item.kind === "termin" && (
|
||||
<div className="flex gap-1 shrink-0 opacity-0 group-hover:opacity-100 transition-opacity">
|
||||
<AdminTerminModal
|
||||
existingTermin={item}
|
||||
|
||||
Reference in New Issue
Block a user