# Resource Scheduler Panel URL: /docs/web/components/resource-scheduler-panel Resource Scheduler Panel component. **Demo:** ```tsx 'use client'; import { useCallback, useState } from 'react'; import { format } from 'date-fns'; import { type SchedulerEvent, ResourceSchedulerPanel } from '@docyrus/ui/components/resource-scheduler-panel'; import { useSchedulerDemoData } from '@/data/resource-scheduler-panel-data'; export function ResourceSchedulerPanelDemo() { const { resources, events: initialEvents } = useSchedulerDemoData(); const [events, setEvents] = useState>(initialEvents); const [logs, setLogs] = useState>([]); const addLog = useCallback((message: string) => { setLogs(prev => [{ id: `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`, message }, ...prev].slice(0, 5)); }, []); const handleEventClick = useCallback((event: SchedulerEvent) => { addLog(`Clicked "${event.title}"`); }, [addLog]); const handleEventMove = useCallback(( event: SchedulerEvent, newStart: Date, newEnd: Date, newResourceId?: string ) => { setEvents(prev => prev.map(e => e.id === event.id ? { ...e, startDate: newStart, endDate: newEnd, resourceId: newResourceId ?? e.resourceId } : e)); const target = newResourceId ? resources.find(r => r.id === newResourceId)?.name : undefined; addLog( `Moved "${event.title}" → ${format(newStart, 'MMM d, HH:mm')}${target ? ` (→ ${target})` : ''}` ); }, [addLog, resources]); const handleEventResize = useCallback(( event: SchedulerEvent, newStart: Date, newEnd: Date ) => { setEvents(prev => prev.map(e => e.id === event.id ? { ...e, startDate: newStart, endDate: newEnd } : e)); addLog( `Resized "${event.title}" → ${format(newStart, 'MMM d, HH:mm')} – ${format(newEnd, 'MMM d, HH:mm')}` ); }, [addLog]); const handleSlotClick = useCallback((resourceId: string, date: Date) => { const resource = resources.find(r => r.id === resourceId); addLog(`Slot click: ${resource?.name} at ${format(date, 'MMM d, HH:mm')}`); }, [addLog, resources]); return (
{logs.length > 0 && (
{logs.map((log, i) => (
0 ? 'opacity-50' : ''}> {log.message}
))}
)}
); } ``` ## Installation ```bash pnpm dlx @docyrus/cli add @docyrus/ui-resource-scheduler-panel ``` **Dependencies:** - [date-fns](https://www.npmjs.com/package/date-fns) - [@dnd-kit/core](https://www.npmjs.com/package/@dnd-kit/core) - [@dnd-kit/modifiers](https://www.npmjs.com/package/@dnd-kit/modifiers) - [class-variance-authority](https://www.npmjs.com/package/class-variance-authority) - [lucide-react](https://www.npmjs.com/package/lucide-react) - [@tanstack/react-table](https://www.npmjs.com/package/@tanstack/react-table) ## Usage ```tsx import { ResourceSchedulerPanel } from "@docyrus/ui/components/resource-scheduler-panel"; import type { ResourceSchedulerPanelProps, SchedulerEvent, SchedulerResource, TimelinePreset, TimelinePresetConfig, TimeUnit, TimelineColumn, TimelineGroupHeader } from "@docyrus/ui/components/resource-scheduler-panel"; ``` ## API Reference | Prop | Type | Default | |------|------|---------| | `className` | `string` | — | ## Components | Component | Description | |-----------|-------------| | `ResourceSchedulerPanel` | Public export | | `ResourceSchedulerProvider` | Internal — `resource-scheduler-context.tsx` | | `ResourceSchedulerDraggableEvent` | Internal — `resource-scheduler-draggable-event.tsx` | | `ResourceSchedulerEventBar` | Internal — `resource-scheduler-event-bar.tsx` | | `ResourceSchedulerEventPopover` | Internal — `resource-scheduler-event-popover.tsx` | | `ResourceSchedulerEventRow` | Internal — `resource-scheduler-event-row.tsx` | | `ResourceSchedulerHeader` | Internal — `resource-scheduler-header.tsx` | | `ResourceSchedulerResourceList` | Internal — `resource-scheduler-resource-list.tsx` | | `ResourceSchedulerTimelineHeader` | Internal — `resource-scheduler-timeline-header.tsx` | | `ResourceSchedulerTimeline` | Internal — `resource-scheduler-timeline.tsx` | | `ResourceSchedulerToday` | Internal — `resource-scheduler-today.tsx` | ## Type Exports | Type | Description | |------|-------------| | `ResourceSchedulerPanelProps` | — | | `SchedulerEvent` | — | | `SchedulerResource` | — | | `TimelinePreset` | — | | `TimelinePresetConfig` | — | | `TimeUnit` | — | | `TimelineColumn` | — | | `TimelineGroupHeader` | — | ## Type Reference ### ResourceSchedulerPanelProps | Field | Type | Description | |-------|------|-------------| | `resources` | `Array` | — | | `events` | `Array` | — | | `presets` | `Array` | — | | `defaultPresetId` | `string` | — | | `startDate` | `Date` | — | | `endDate` | `Date` | — | | `resourceColumns` | `Array>` | — | | `onEventClick` | `(event: SchedulerEvent) => void` | — | | `onEventMove` | `(event: SchedulerEvent, newStart: Date, newEnd: Date, newResourceId?: string) => void` | — | | `onEventResize` | `(event: SchedulerEvent, newStart: Date, newEnd: Date) => void` | — | | `onSlotClick` | `(resourceId: string, date: Date) => void` | — | | `onDateRangeChange` | `(start: Date, end: Date) => void` | — | | `onPresetChange` | `(presetId: string) => void` | — | | `isLoading` | `boolean` | — | | `readOnly` | `boolean` | — | | `showTodayIndicator` | `boolean` | — | | `showResourceCount` | `boolean` | — | | `height` | `number \| 'auto'` | — | | `resourcePanelWidth` | `number` | — | | `rowHeight` | `number` | — | | `className` | `string` | — | | `locale` | `string` | — | ### SchedulerEvent | Field | Type | Description | |-------|------|-------------| | `id` | `string` | — | | `resourceId` | `string` | — | | `title` | `string` | — | | `startDate` | `Date` | — | | `endDate` | `Date` | — | | `color` | `string` | — | | `variant` | `'solid' \| 'outlined' \| 'subtle'` | — | | `icon` | `ReactNode` | — | | `description` | `string` | — | | `location` | `string` | — | | `metadata` | `Record` | — | ### SchedulerResource | Field | Type | Description | |-------|------|-------------| | `id` | `string` | — | | `name` | `string` | — | | `avatar` | `string` | — | | `subtitle` | `string` | — | | `group` | `string` | — | ### TimelinePreset | Field | Type | Description | |-------|------|-------------| | `unitWidth` | `number` | — | | `interval` | `{ unit: TimeUnit; format: string }` | — | | `groups` | `Array<{ unit: TimeUnit; format: string }>` | — | ### TimelinePresetConfig | Field | Type | Description | |-------|------|-------------| | `unitWidth` | `number` | — | | `interval` | `{ unit: TimeUnit; format: string }` | — | | `groups` | `Array<{ unit: TimeUnit; format: string }>` | — | ### TimeUnit `"hour"` | `"day"` | `"week"` | `"month"` | `"year"` ### TimelineColumn | Field | Type | Description | |-------|------|-------------| | `start` | `Date` | — | | `end` | `Date` | — | | `label` | `string` | — | | `index` | `number` | — | ### TimelineGroupHeader | Field | Type | Description | |-------|------|-------------| | `start` | `Date` | — | | `end` | `Date` | — | | `label` | `string` | — | | `spanCount` | `number` | — |