"use client";
import * as React from "react";
import { useState } from "react";
import { Slider } from "@/components/ui/slider";
import {
TimelineProvider,
Timeline,
TimelineGrid,
TimelineRow,
TimelineRowData,
TimelineSlot,
TimelineSlotData,
TimelineSlotLabel,
TimelineSlotContent,
TimelineHeader,
TimelineCurrentTime,
} from "@/components/ui/timeline";
import { Users, Clock } from "lucide-react";
import { cn } from "@/lib/utils";
const rows: TimelineRowData[] = [
{ id: "room-a", label: "Conference Room A", capacity: 12 },
{ id: "room-b", label: "Conference Room B", capacity: 8 },
{ id: "room-1", label: "Meeting Room 1", capacity: 6 },
{ id: "room-2", label: "Meeting Room 2", capacity: 4 },
{ id: "training", label: "Training Room", capacity: 20 },
];
const categoryConfig: Record<
string,
{ dot: string; border: string; text: string }
> = {
meeting: {
dot: "bg-blue-500",
border: "border-l-blue-500",
text: "text-blue-600 dark:text-blue-400",
},
workshop: {
dot: "bg-emerald-500",
border: "border-l-emerald-500",
text: "text-emerald-600 dark:text-emerald-400",
},
break: {
dot: "bg-purple-500",
border: "border-l-purple-500",
text: "text-purple-600 dark:text-purple-400",
},
review: {
dot: "bg-orange-500",
border: "border-l-orange-500",
text: "text-orange-600 dark:text-orange-400",
},
};
const initialSlots: (TimelineSlotData & {
title: string;
attendees: number;
category: string;
})[] = [
{
id: "1",
rowId: "room-a",
startTime: "09:30",
duration: 30,
title: "Team Standup",
attendees: 8,
category: "meeting",
},
{
id: "2",
rowId: "room-a",
startTime: "11:00",
duration: 60,
title: "Product Review",
attendees: 6,
category: "review",
},
{
id: "3",
rowId: "room-b",
startTime: "10:00",
duration: 90,
title: "Design Workshop",
attendees: 5,
category: "workshop",
},
{
id: "4",
rowId: "room-b",
startTime: "14:00",
duration: 30,
title: "Client Meeting",
attendees: 4,
category: "meeting",
},
{
id: "5",
rowId: "room-1",
startTime: "09:00",
duration: 30,
title: "Quick Sync",
attendees: 3,
category: "meeting",
},
{
id: "6",
rowId: "room-1",
startTime: "13:00",
duration: 30,
title: "Coffee Break",
attendees: 10,
category: "break",
},
{
id: "7",
rowId: "room-2",
startTime: "10:30",
duration: 60,
title: "Code Review",
attendees: 4,
category: "review",
},
{
id: "8",
rowId: "room-2",
startTime: "15:00",
duration: 30,
title: "1-on-1",
attendees: 2,
category: "meeting",
},
{
id: "9",
rowId: "training",
startTime: "09:00",
duration: 120,
title: "React Workshop",
attendees: 15,
category: "workshop",
},
{
id: "10",
rowId: "training",
startTime: "14:30",
duration: 90,
title: "Security Training",
attendees: 18,
category: "workshop",
},
];
export default function Page() {
const [slots, setSlots] = useState(initialSlots);
const [percentageInView, setPercentageInView] = useState(100);
const config = {
startHour: 9,
endHour: 18,
snapIntervalMinutes: 15,
columnWidth: 160,
};
const handlePositionChange = async (
slotId: string,
newTime: string,
newRowId: string,
) => {
setSlots((prev) =>
prev.map((s) =>
s.id === slotId ? { ...s, startTime: newTime, rowId: newRowId } : s,
),
);
await new Promise((resolve) => setTimeout(resolve, 100));
return true;
};
return (
<div className="w-full">
<div className="flex flex-col gap-2 mb-4 w-full">
<p className="text-sm font-medium leading-none">Zoom level</p>
<Slider
min={50}
max={100}
step={1}
value={[percentageInView]}
onValueChange={(value) => setPercentageInView(value[0])}
/>
</div>
<div className="flex flex-wrap gap-4 text-sm mb-4">
{[
["Meeting", "meeting"],
["Workshop", "workshop"],
["Break", "break"],
["Review", "review"],
].map(([label, key]) => (
<div key={key} className="flex items-center gap-1.5">
<span
className={cn(
"h-2.5 w-2.5 rounded-full",
categoryConfig[key].dot,
)}
/>
{label}
</div>
))}
</div>
<TimelineProvider
config={config}
percentageInView={percentageInView}
onSlotPositionChange={handlePositionChange}
>
<Timeline slots={slots} rows={rows}>
<TimelineGrid>
<TimelineHeader columnLabel="Rooms" />
{rows.map((row) => (
<TimelineRow
key={row.id}
row={row}
slots={slots}
renderRowHeader={(r) => (
<div className="px-4 py-1">
<div className="font-medium text-sm">{r.label}</div>
<div className="flex items-center gap-1 text-xs text-muted-foreground">
<Users className="h-3 w-3" /> {r.capacity}
</div>
</div>
)}
>
{(slot) => {
const s = slot as (typeof initialSlots)[number];
const cat = categoryConfig[s.category];
return (
<TimelineSlot
key={s.id}
slot={s}
className={cn("border-l-4 bg-card", cat.border)}
>
<div className="px-2 py-1">
<TimelineSlotLabel className={cat.text}>
{s.title}
</TimelineSlotLabel>
<TimelineSlotContent className="flex items-center gap-2 text-muted-foreground">
<span className="flex items-center gap-0.5">
<Clock className="h-3 w-3" />
{s.startTime}
</span>
<span className="flex items-center gap-0.5">
<Users className="h-3 w-3" />
{s.attendees}
</span>
</TimelineSlotContent>
</div>
</TimelineSlot>
);
}}
</TimelineRow>
))}
<TimelineCurrentTime />
</TimelineGrid>
</Timeline>
</TimelineProvider>
</div>
);
}