@bernierllc/schedule-calendar-ui
v0.3.2
Published
Interactive schedule calendar with drag-and-drop and timeline views using React and Tamagui
Readme
@bernierllc/schedule-calendar-ui
Interactive schedule calendar with drag-and-drop and timeline views using React and Tamagui.
Features
- 📅 Multiple Views: Month, week, day, agenda, and timeline views
- 🖱️ Drag-and-Drop: Reschedule content by dragging events
- 🎨 Platform Visualization: Color-coded by platform using Tamagui themes
- ⚠️ Conflict Detection: Visual indicators for scheduling conflicts
- 🔍 Filtering: Filter by platform, author, type, and status
- 🌐 Timezone Support: Multi-timezone schedule display
- 🔄 Real-time Updates: Live schedule changes via NeverHub
- ✨ Bulk Operations: Multi-select and bulk actions
Installation
npm install @bernierllc/schedule-calendar-uiUsage
Basic Calendar
import { ScheduleCalendar } from '@bernierllc/schedule-calendar-ui';
import type { ScheduledContent } from '@bernierllc/schedule-calendar-ui';
function App() {
const schedules: ScheduledContent[] = [
{
id: '1',
contentId: 'post-123',
title: 'Morning Tweet',
scheduledDate: new Date('2025-01-15T10:00:00Z'),
platform: 'twitter',
type: 'post',
status: 'scheduled',
},
];
const handleReschedule = (contentId: string, newDate: Date) => {
console.log(`Reschedule ${contentId} to ${newDate}`);
};
return (
<ScheduleCalendar
schedules={schedules}
onReschedule={handleReschedule}
view="month"
/>
);
}With Filters and Conflict Detection
import { ScheduleCalendar } from '@bernierllc/schedule-calendar-ui';
function FilteredCalendar() {
const [filters, setFilters] = useState({
platforms: ['twitter', 'facebook'],
statuses: ['scheduled'],
});
return (
<ScheduleCalendar
schedules={schedules}
filters={filters}
enableConflictDetection
onContentClick={(content) => console.log('Clicked:', content)}
onDateClick={(date) => console.log('Date clicked:', date)}
/>
);
}Timeline View
import { TimelineView } from '@bernierllc/schedule-calendar-ui';
function Timeline() {
const dateRange = {
start: new Date('2025-01-01'),
end: new Date('2025-01-31'),
};
return (
<TimelineView
schedules={schedules}
dateRange={dateRange}
groupBy="platform"
showConflicts
/>
);
}Custom Views
import {
MonthView,
WeekView,
DayView,
AgendaView,
} from '@bernierllc/schedule-calendar-ui';
function CustomCalendar() {
const [view, setView] = useState('month');
const currentDate = new Date();
return (
<>
{view === 'month' && (
<MonthView
dateRange={getViewDateRange(currentDate, 'month')}
currentMonth={currentDate}
schedules={schedules}
/>
)}
{view === 'week' && (
<WeekView date={currentDate} schedules={schedules} />
)}
{view === 'day' && (
<DayView date={currentDate} schedules={schedules} />
)}
{view === 'agenda' && (
<AgendaView
dateRange={getViewDateRange(currentDate, 'agenda')}
schedules={schedules}
/>
)}
</>
);
}API Reference
ScheduleCalendar
Main calendar component with all features.
Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| schedules | ScheduledContent[] | Required | Array of scheduled content |
| view | CalendarView | 'month' | Initial view ('month' | 'week' | 'day' | 'agenda' | 'timeline') |
| timezone | string | User's timezone | Timezone for display |
| onReschedule | (contentId, newDate) => void | - | Called when event is rescheduled |
| onContentClick | (content) => void | - | Called when event is clicked |
| onDateClick | (date) => void | - | Called when date is clicked |
| filters | ScheduleFilters | - | Active filters |
| readOnly | boolean | false | Disable drag-and-drop |
| enableConflictDetection | boolean | true | Enable conflict detection |
| enableRealTimeUpdates | boolean | false | Enable NeverHub real-time updates |
TimelineView
Timeline visualization component.
Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| schedules | ScheduledContent[] | Required | Array of scheduled content |
| dateRange | DateRange | Required | Time range to display |
| onReschedule | (contentId, newDate) => void | - | Reschedule callback |
| groupBy | 'platform' \| 'author' \| 'type' | 'platform' | Grouping strategy |
| showConflicts | boolean | false | Show conflict indicators |
Hooks
useScheduleCalendar
Main hook for calendar state management.
const {
currentDate,
currentView,
dateRange,
goToToday,
goToPrevious,
goToNext,
setView,
filters,
setFilters,
filteredSchedules,
schedulesByDay,
conflicts,
} = useScheduleCalendar(schedules, {
initialView: 'month',
initialDate: new Date(),
enableConflictDetection: true,
});useScheduleFilters
Hook for managing schedule filters.
const {
filters,
setFilters,
togglePlatform,
toggleAuthor,
toggleType,
toggleStatus,
setSearchQuery,
clearFilters,
hasActiveFilters,
} = useScheduleFilters();useTimezone
Hook for timezone conversion.
const {
timezone,
setTimezone,
convertTo,
convertFrom,
getLocalTimezone,
} = useTimezone({ defaultTimezone: 'America/New_York' });Types
ScheduledContent
interface ScheduledContent {
id: string;
contentId: string;
title: string;
description?: string;
scheduledDate: Date;
platform: string;
author?: string;
type: ContentType;
status: ScheduleStatus;
timezone?: string;
metadata?: Record<string, unknown>;
}ScheduleFilters
interface ScheduleFilters {
platforms?: string[];
authors?: string[];
types?: ContentType[];
statuses?: ScheduleStatus[];
dateRange?: DateRange;
searchQuery?: string;
}ScheduleConflict
interface ScheduleConflict {
id: string;
schedules: ScheduledContent[];
reason: string;
severity: 'low' | 'medium' | 'high';
suggestedResolution?: string;
}Styling with Tamagui
All components use Tamagui for styling. Customize the theme:
import { TamaguiProvider, createTamagui } from 'tamagui';
import { config } from '@tamagui/config';
const tamaguiConfig = createTamagui({
...config,
themes: {
light: {
...config.themes.light,
blue8: '#0066CC', // Platform colors
},
},
});
function App() {
return (
<TamaguiProvider config={tamaguiConfig}>
<ScheduleCalendar schedules={schedules} />
</TamaguiProvider>
);
}Real-time Updates with NeverHub
Enable real-time schedule updates:
<ScheduleCalendar
schedules={schedules}
enableRealTimeUpdates
onReschedule={handleReschedule}
/>The component will automatically subscribe to NeverHub events:
calendar.schedule.updatedcalendar.view.changedcalendar.conflict.detected
Testing
npm test
npm run test:coverageLicense
Copyright (c) 2025 Bernier LLC
This file is licensed to the client under a limited-use license. The client may use and modify this code only within the scope of the project it was delivered for. Redistribution or use in other products or commercial offerings is not permitted without written consent from Bernier LLC.
