Files
calendar/frontend(experimental)/newchat/components/sidebar.tsx
T
ben bf601846db new frontend
ik ben zo cool
2026-08-19 09:33:48 +02:00

221 lines
7.6 KiB
TypeScript

"use client"
import { useState } from "react"
import {
ChevronLeft,
ChevronRight,
Plus,
LogOut,
Users,
DoorOpen,
Layers,
Crown,
Shield,
} from "lucide-react"
import type { Room } from "@/lib/types"
import type { User } from "@/lib/types"
import { getRoomColor } from "@/lib/room-theme"
import { addDays, isSameDay, startOfWeek, formatMonthYear } from "@/lib/date-utils"
interface SidebarProps {
rooms: Room[]
activeRoomId: number | null
onSelectRoom: (id: number | null) => void
selectedDate: Date
onSelectDate: (d: Date) => void
onCreateEvent: () => void
onCreateRoom: () => void
onJoinRoom: () => void
user: User | null
onLogout: () => void
}
const WEEKDAY_MINI = ["S", "M", "T", "W", "T", "F", "S"]
function RoleBadge({ role }: { role: Room["role"] }) {
if (role === "owner")
return <Crown className="h-3.5 w-3.5 text-amber-300" aria-label="Owner" />
if (role === "admin")
return <Shield className="h-3.5 w-3.5 text-blue-200" aria-label="Admin" />
return null
}
export function Sidebar({
rooms,
activeRoomId,
onSelectRoom,
selectedDate,
onSelectDate,
onCreateEvent,
onCreateRoom,
onJoinRoom,
user,
onLogout,
}: SidebarProps) {
const [miniMonth, setMiniMonth] = useState(() => {
const d = new Date(selectedDate)
d.setDate(1)
return d
})
const weekStart = startOfWeek(selectedDate)
const weekEnd = addDays(weekStart, 6)
// Build mini-calendar grid for miniMonth.
const firstDay = new Date(miniMonth.getFullYear(), miniMonth.getMonth(), 1)
const offset = firstDay.getDay()
const daysInMonth = new Date(miniMonth.getFullYear(), miniMonth.getMonth() + 1, 0).getDate()
const cells: (Date | null)[] = []
for (let i = 0; i < offset; i++) cells.push(null)
for (let d = 1; d <= daysInMonth; d++) {
cells.push(new Date(miniMonth.getFullYear(), miniMonth.getMonth(), d))
}
const today = new Date()
const shiftMonth = (delta: number) => {
setMiniMonth((m) => new Date(m.getFullYear(), m.getMonth() + delta, 1))
}
const inSelectedWeek = (d: Date) => d >= weekStart && d <= weekEnd
return (
<div className="flex h-full w-64 flex-col justify-between rounded-tr-3xl border-r border-white/20 bg-white/10 p-4 shadow-xl backdrop-blur-lg">
<div className="flex min-h-0 flex-1 flex-col">
<button
onClick={onCreateEvent}
className="mb-6 flex items-center justify-center gap-2 rounded-full bg-blue-500 px-4 py-3 text-white transition-colors hover:bg-blue-600"
>
<Plus className="h-5 w-5" />
<span>Create event</span>
</button>
{/* Mini Calendar */}
<div className="mb-6">
<div className="mb-3 flex items-center justify-between">
<h3 className="font-medium text-white">{formatMonthYear(miniMonth)}</h3>
<div className="flex gap-1">
<button
onClick={() => shiftMonth(-1)}
className="rounded-full p-1 hover:bg-white/20"
aria-label="Previous month"
>
<ChevronLeft className="h-4 w-4 text-white" />
</button>
<button
onClick={() => shiftMonth(1)}
className="rounded-full p-1 hover:bg-white/20"
aria-label="Next month"
>
<ChevronRight className="h-4 w-4 text-white" />
</button>
</div>
</div>
<div className="grid grid-cols-7 gap-1 text-center">
{WEEKDAY_MINI.map((day, i) => (
<div key={i} className="py-1 text-xs font-medium text-white/70">
{day}
</div>
))}
{cells.map((date, i) => {
if (!date) return <div key={i} />
const selected = isSameDay(date, selectedDate)
const isToday = isSameDay(date, today)
const highlightWeek = inSelectedWeek(date) && !selected
return (
<button
key={i}
onClick={() => onSelectDate(date)}
className={`flex h-7 w-7 items-center justify-center rounded-full text-xs transition-colors ${
selected
? "bg-blue-500 font-semibold text-white"
: highlightWeek
? "bg-white/15 text-white"
: "text-white hover:bg-white/20"
} ${isToday && !selected ? "ring-1 ring-white/60" : ""}`}
>
{date.getDate()}
</button>
)
})}
</div>
</div>
{/* Rooms */}
<div className="mb-2 flex items-center justify-between">
<h3 className="font-medium text-white">Rooms</h3>
</div>
<div className="-mr-1 flex-1 space-y-1 overflow-y-auto pr-1">
<button
onClick={() => onSelectRoom(null)}
className={`flex w-full items-center gap-3 rounded-lg px-2 py-2 text-left text-sm transition-colors ${
activeRoomId === null ? "bg-white/25 text-white" : "text-white/90 hover:bg-white/15"
}`}
>
<Layers className="h-4 w-4 shrink-0" />
<span className="truncate">All rooms</span>
</button>
{rooms.map((room) => {
const color = getRoomColor(room.id)
const active = activeRoomId === room.id
return (
<button
key={room.id}
onClick={() => onSelectRoom(room.id)}
className={`flex w-full items-center gap-3 rounded-lg px-2 py-2 text-left text-sm transition-colors ${
active ? "bg-white/25 text-white" : "text-white/90 hover:bg-white/15"
}`}
>
<span className={`h-3 w-3 shrink-0 rounded-sm ${color.dot}`} />
<span className="flex-1 truncate">{room.name}</span>
<RoleBadge role={room.role} />
</button>
)
})}
{rooms.length === 0 && (
<p className="px-2 py-2 text-xs text-white/60">
No rooms yet. Create or join one to get started.
</p>
)}
</div>
<div className="mt-3 flex gap-2">
<button
onClick={onCreateRoom}
className="flex flex-1 items-center justify-center gap-1.5 rounded-lg border border-white/20 bg-white/10 px-2 py-2 text-xs text-white transition-colors hover:bg-white/20"
>
<Plus className="h-3.5 w-3.5" /> New
</button>
<button
onClick={onJoinRoom}
className="flex flex-1 items-center justify-center gap-1.5 rounded-lg border border-white/20 bg-white/10 px-2 py-2 text-xs text-white transition-colors hover:bg-white/20"
>
<DoorOpen className="h-3.5 w-3.5" /> Join
</button>
</div>
</div>
{/* User footer */}
<div className="mt-4 flex items-center gap-3 border-t border-white/20 pt-4">
<div className="flex h-9 w-9 items-center justify-center rounded-full bg-blue-500 font-bold text-white">
{user?.username?.charAt(0).toUpperCase() ?? "U"}
</div>
<div className="min-w-0 flex-1">
<p className="truncate text-sm font-medium text-white">{user?.username}</p>
<p className="truncate text-xs text-white/60">{user?.email}</p>
</div>
<button
onClick={onLogout}
className="rounded-lg p-2 text-white/80 transition-colors hover:bg-white/20 hover:text-white"
aria-label="Sign out"
>
<LogOut className="h-4 w-4" />
</button>
</div>
</div>
)
}