import React from 'react';
import { useReservations } from './ReservationsProvider';
import { Reservation } from '@/types/types';
import TimeSlot from './TimeSlot';
import ReservationCard from './ReservationCard';
const HOUR_HEIGHT = 50;
const MIN_CARD_HEIGHT = 100;
const DAY_START = 10;
const TOTAL_HOURS = 14;
const TIMELINE_HEIGHT = TOTAL_HOURS * HOUR_HEIGHT;
interface ReservationLayout {
reservation: Reservation;
column: number;
columnSpan: number;
totalColumns: number;
}
const calculateReservationLayout = (
reservations: Reservation[]
): ReservationLayout[] => {
if (reservations.length === 0) return [];
const sorted = [...reservations].sort((a, b) => {
const startA = new Date(a.from_date).getTime();
const startB = new Date(b.from_date).getTime();
if (startA === startB) {
const durationA = new Date(a.to_date).getTime() - startA;
const durationB = new Date(b.to_date).getTime() - startB;
return durationB - durationA;
}
return startA - startB;
});
const layouts: ReservationLayout[] = [];
const columns: (number | null)[][] = [];
sorted.forEach((reservation) => {
const startTime = new Date(reservation.from_date).getTime();
const endTime = new Date(reservation.to_date).getTime();
let assignedColumn = -1;
for (let i = 0; i < columns.length; i++) {
const column = columns[i];
let canPlace = true;
for (let j = 0; j < column.length; j++) {
const existingEventEndTime = column[j];
if (existingEventEndTime !== null && startTime < existingEventEndTime) {
canPlace = false;
break;
}
}
if (canPlace) {
assignedColumn = i;
break;
}
}
if (assignedColumn === -1) {
assignedColumn = columns.length;
columns.push([]);
}
columns[assignedColumn].push(endTime);
layouts.push({
reservation,
column: assignedColumn,
columnSpan: 1,
totalColumns: columns.length
});
});
return layouts;
};
interface DayColumnProps {
date: Date;
reservations: Reservation[];
showHours?: 'left' | 'right';
onReservationClick: (reservation: Reservation) => void;
}
export default function DayColumn({
date,
reservations,
showHours,
onReservationClick
}: DayColumnProps) {
const { updateReservation, deleteReservation, view } = useReservations();
const reservationLayouts = calculateReservationLayout(reservations);
const handleDrop = (
reservation: Reservation,
startTime: Date,
endTime: Date
) => {
updateReservation(reservation.id, {
from_date: startTime.toISOString(),
to_date: endTime.toISOString()
});
};
return (
<div className="h-full">
<div className="text-center font-bold mb-2">
<div className="flex flex-col items-center">
<span className="text-gray-600 text-xs">{date.toLocaleDateString('bg-BG', { weekday: 'short' }).toLowerCase()}</span>
<span className="text-gray-900 text-sm">
{date.toLocaleDateString('bg-BG', { day: '2-digit', month: '2-digit' }).replace('/', '.')}
</span>
</div>
</div>
{view === 'grid' ? (
<div className="relative" style={{ height: TIMELINE_HEIGHT }}>
{Array.from({ length: TOTAL_HOURS }, (_, i) => (
<TimeSlot
key={i}
hour={i + DAY_START}
date={date}
showHour={showHours}
onDrop={handleDrop}
/>
))}
{reservationLayouts.map((layout) => (
<ReservationCard
key={layout.reservation.id}
variant="kanban"
reservation={layout.reservation}
style={{
position: 'absolute',
top: `${
((new Date(layout.reservation.from_date).getHours() -
DAY_START) *
60 +
new Date(layout.reservation.from_date).getMinutes()) *
(HOUR_HEIGHT / 60)
}px`,
height: `${Math.max(
((new Date(layout.reservation.to_date).getTime() -
new Date(layout.reservation.from_date).getTime()) /
(1000 * 60 * 60)) *
HOUR_HEIGHT,
MIN_CARD_HEIGHT
)}px`,
left: `${(layout.column * 100) / layout.totalColumns}%`,
width: `${(layout.columnSpan * 100) / layout.totalColumns}%`
}}
onClick={(e) => {
e.stopPropagation();
onReservationClick(layout.reservation);
}}
/>
))}
</div>
) : (
<div className="flex flex-col gap-2">
{reservations
.sort((a, b) => new Date(a.from_date).getTime() - new Date(b.from_date).getTime())
.map((reservation) => (
<ReservationCard
key={reservation.id}
variant="list"
reservation={reservation}
onEdit={onReservationClick}
onDelete={(id) => {
deleteReservation(id);
}}
onApprove={(id) => {
updateReservation(parseInt(id), { approved: true });
}}
onUnapprove={(id) => {
updateReservation(parseInt(id), { approved: false });
}}
/>
))}
{reservations.length === 0 && (
<div className="text-center text-gray-500 py-4">No reservations</div>
)}
</div>
)}
</div>
);
}