Files
smoothschedule/frontend/src/components/Timeline/ResourceRow.tsx
poduck 2e111364a2 Initial commit: SmoothSchedule multi-tenant scheduling platform
This commit includes:
- Django backend with multi-tenancy (django-tenants)
- React + TypeScript frontend with Vite
- Platform administration API with role-based access control
- Authentication system with token-based auth
- Quick login dev tools for testing different user roles
- CORS and CSRF configuration for local development
- Docker development environment setup

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-27 01:43:20 -05:00

100 lines
3.4 KiB
TypeScript

import React, { useMemo } from 'react';
import { useDroppable } from '@dnd-kit/core';
import { clsx } from 'clsx';
import { differenceInHours } from 'date-fns';
import { calculateLayout, Event } from '../../lib/layoutAlgorithm';
import { DraggableEvent } from './DraggableEvent';
import { getPosition } from '../../lib/timelineUtils';
interface ResourceRowProps {
resourceId: number;
resourceName: string;
events: Event[];
startTime: Date;
endTime: Date;
hourWidth: number;
eventHeight: number;
onResizeStart: (e: React.MouseEvent, direction: 'left' | 'right', id: number) => void;
}
const ResourceRow: React.FC<ResourceRowProps> = ({
resourceId,
resourceName,
events,
startTime,
endTime,
hourWidth,
eventHeight,
onResizeStart,
}) => {
const { setNodeRef, isOver } = useDroppable({
id: `resource-${resourceId}`,
data: { resourceId },
});
const eventsWithLanes = useMemo(() => calculateLayout(events), [events]);
const maxLane = Math.max(0, ...eventsWithLanes.map(e => e.laneIndex || 0));
const rowHeight = (maxLane + 1) * eventHeight + 20;
const totalWidth = getPosition(endTime, startTime, hourWidth);
// Calculate total hours for grid lines
const totalHours = Math.ceil(differenceInHours(endTime, startTime));
return (
<div className="flex border-b border-gray-200 group">
<div
className="w-48 flex-shrink-0 p-4 border-r border-gray-200 bg-gray-50 font-medium flex items-center sticky left-0 z-10 group-hover:bg-gray-100 transition-colors"
style={{ height: rowHeight }}
>
{resourceName}
</div>
<div
ref={setNodeRef}
className={clsx(
"relative flex-grow transition-colors",
isOver ? "bg-blue-50" : ""
)}
style={{ height: rowHeight, width: totalWidth }}
>
{/* Grid Lines */}
<div className="absolute inset-0 pointer-events-none flex">
{Array.from({ length: totalHours }).map((_, i) => (
<div
key={i}
className="border-r border-gray-100 h-full"
style={{ width: hourWidth }}
/>
))}
</div>
{/* Events */}
{eventsWithLanes.map((event) => {
const left = getPosition(event.start, startTime, hourWidth);
const width = getPosition(event.end, startTime, hourWidth) - left;
const top = (event.laneIndex || 0) * eventHeight + 10;
return (
<DraggableEvent
key={event.id}
id={event.id}
title={event.title}
start={event.start}
end={event.end}
laneIndex={event.laneIndex || 0}
height={eventHeight - 4}
left={left}
width={width}
top={top}
onResizeStart={onResizeStart}
/>
);
})}
</div>
</div>
);
};
export default ResourceRow;