โก Calendar Component - Quick Reference
Cheatsheet untuk penggunaan cepat Calendar Component.
๐ฆ Installationโ
npm install react-big-calendar date-fns dayjs @tanstack/react-query
๐ Basic Usageโ
import { GenericOptimizedCalendar } from '@/components/Calendar/GenericCalendar';
<GenericOptimizedCalendar
onFetchEvents={async (start, end) => {
const res = await fetch(`/api/events?start=${start}&end=${end}`);
return res.json();
}}
/>
๐ Common Propsโ
| Prop | Type | Example |
|---|---|---|
onFetchEvents | Function | async (start, end) => fetch(...) |
defaultView | String | 'month' | 'week' | 'day' | 'agenda' |
timeWindow | Object/Function | { start: '08:00', end: '17:00' } |
workingDays | Array | [1, 2, 3, 4, 5] (Mon-Fri) |
preventOverlap | Boolean | true |
allowBackDate | Boolean | false (disable past dates) |
getEventColor | Function | (e) => e.color |
isEventDisabled | Function | (e) => e.isPast |
๐จ Event Object Structureโ
{
id: string; // Required
title: string; // Required
start: Date | string; // Required
end: Date | string; // Required
color?: string; // Optional
desc?: string; // Optional
disabled?: boolean; // Optional
allDay?: boolean; // Optional
}
๐ง Common Patternsโ
Fetch dari APIโ
const fetchEvents = async (start: Date, end: Date) => {
const res = await axios.get('/api/events', {
params: {
start: start.toISOString(),
end: end.toISOString()
}
});
return res.data;
};
Working Hours (08:00 - 17:00)โ
<GenericOptimizedCalendar
onFetchEvents={fetchEvents}
timeWindow={{ start: '08:00', end: '17:00' }}
restrictVisibleHours={true}
/>
Working Days (Senin - Jumat)โ
<GenericOptimizedCalendar
onFetchEvents={fetchEvents}
workingDays={[1, 2, 3, 4, 5]}
/>
Prevent Overlapโ
<GenericOptimizedCalendar
onFetchEvents={fetchEvents}
preventOverlap={true}
onSelectSlotDenied={(reason) => {
if (reason === 'overlap') {
alert('Slot sudah terisi!');
}
}}
/>
Custom Colorsโ
<GenericOptimizedCalendar
onFetchEvents={fetchEvents}
getEventColor={(event) => {
if (event.status === 'approved') return '#4caf50';
if (event.status === 'pending') return '#ff9800';
return '#f44336';
}}
/>
Disable Past Eventsโ
<GenericOptimizedCalendar
onFetchEvents={fetchEvents}
allowBackDate={false}
isEventDisabled={(event) => {
return dayjs(event.start).isBefore(dayjs(), 'day');
}}
/>
Handle Event Clickโ
<GenericOptimizedCalendar
onFetchEvents={fetchEvents}
onSelectEventSimple={(event) => {
console.log('Clicked:', event);
// Open modal/detail
}}
/>
Handle Slot Clickโ
<GenericOptimizedCalendar
onFetchEvents={fetchEvents}
onSelectSlot={(slotInfo) => {
console.log('Selected:', slotInfo.start, slotInfo.end);
// Open form to create event
}}
/>
With Ref (Manual Refresh)โ
const calendarRef = useRef<GenericCalendarRef>(null);
const handleRefresh = () => {
calendarRef.current?.refresh();
};
<GenericOptimizedCalendar
ref={calendarRef}
onFetchEvents={fetchEvents}
/>
Dynamic Time Windowโ
const getTimeWindow = (date: Date) => {
const isWeekend = date.getDay() === 0 || date.getDay() === 6;
return isWeekend
? { start: '09:00', end: '14:00' }
: { start: '08:00', end: '17:00' };
};
<GenericOptimizedCalendar
onFetchEvents={fetchEvents}
timeWindow={getTimeWindow}
/>
With Query Paramsโ
<GenericOptimizedCalendar
onFetchEvents={fetchEvents}
queryParams={{
userId: '123',
status: 'active',
category: 'meeting'
}}
/>
Custom Loading Stateโ
<GenericOptimizedCalendar
onFetchEvents={fetchEvents}
renderLoading={
<div className="loading">
<Spinner />
<p>Loading events...</p>
</div>
}
/>
Responsive (Mobile)โ
const isMobile = useMediaQuery('(max-width: 768px)');
<GenericOptimizedCalendar
onFetchEvents={fetchEvents}
defaultView={isMobile ? 'day' : 'month'}
/>
๐ฏ Event Handlersโ
onSelectSlotโ
Triggered saat user select/click slot kosong:
onSelectSlot={(slotInfo) => {
// slotInfo: { start: Date, end: Date, action: string, ... }
console.log(slotInfo.start, slotInfo.end);
}}
onSelectEventโ
Triggered saat user click event (RBC default):
onSelectEvent={(event, e) => {
// event: your event object
// e: SyntheticEvent
console.log(event);
}}
onSelectEventSimpleโ
Simplified version (1 parameter):
onSelectEventSimple={(event) => {
console.log(event);
}}
onSelectSlotDeniedโ
Triggered saat slot denied (restrictions):
onSelectSlotDenied={(reason) => {
// reason: 'outside-working-days' | 'outside-time-window' |
// 'outside-global-bounds' | 'overlap'
console.log(reason);
}}
๐จ Stylingโ
Override Default Stylesโ
/* Custom event */
.rbc-event {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-radius: 8px;
border: none;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
}
.rbc-event:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
}
/* Today highlight */
.rbc-today {
background-color: rgba(33, 150, 243, 0.08);
}
/* Selected slot */
.rbc-selected-cell {
background-color: rgba(33, 150, 243, 0.15);
}
/* Disabled slot */
.disabledSlot {
background: repeating-linear-gradient(
45deg,
#f5f5f5,
#f5f5f5 10px,
#e0e0e0 10px,
#e0e0e0 20px
);
cursor: not-allowed;
}
Custom Slot Styleโ
<GenericOptimizedCalendar
onFetchEvents={fetchEvents}
disabledSlotStyle={{
backgroundColor: '#ffe6e6',
border: '1px dashed #ff0000',
opacity: 0.5,
}}
/>
๐ง React Query Configurationโ
Stale Timeโ
<GenericOptimizedCalendar
onFetchEvents={fetchEvents}
staleTimeMs={5 * 60 * 1000} // 5 minutes
/>
Custom Query Optionsโ
<GenericOptimizedCalendar
onFetchEvents={fetchEvents}
queryOptions={{
cacheTime: 10 * 60 * 1000, // 10 minutes
refetchOnMount: false,
refetchOnWindowFocus: false,
retry: 3,
retryDelay: 1000,
}}
/>
๐ Localizationโ
Default (Bahasa Indonesia)โ
Built-in, no config needed.
Englishโ
import { enUS } from 'date-fns/locale';
import { dateFnsLocalizer } from 'react-big-calendar';
const enLocalizer = dateFnsLocalizer({
format: (date, formatStr) =>
dfFormat(date, formatStr, { locale: enUS }),
// ... other config
});
<GenericOptimizedCalendar
localizer={enLocalizer}
culture="en-US"
onFetchEvents={fetchEvents}
/>
๐ Troubleshootingโ
Calendar tidak tampilโ
// โ Wrong
<GenericOptimizedCalendar onFetchEvents={fetchEvents} />
// โ
Correct - add explicit height
<div style={{ height: '600px' }}>
<GenericOptimizedCalendar onFetchEvents={fetchEvents} />
</div>
Events tidak munculโ
// Pastikan return array dengan format correct
const fetchEvents = async (start, end) => {
return [
{
id: '1', // โ
Required
title: 'Meeting', // โ
Required
start: new Date(), // โ
Required (Date or ISO string)
end: new Date(), // โ
Required
}
];
};
Timezone issuesโ
// API return: '2025-12-05T09:00:00Z'
// Component auto-convert ke local time
// Jika ingin keep UTC, handle manually
๐ฆ Dependencies Versionโ
Recommended versions:
{
"react-big-calendar": "^1.8.5",
"date-fns": "^3.0.0",
"dayjs": "^1.11.10",
"@tanstack/react-query": "^5.0.0",
"react": "^18.2.0"
}
๐ Useful Linksโ
๐ก Tipsโ
- Always set explicit height - Calendar requires container height
- Use React Query cache - Set appropriate staleTime
- Validate date inputs - Check bounds before create/update
- Handle errors gracefully - Don't let calendar crash
- Test on mobile - Use responsive props
- Memoize callbacks - Optimize re-renders
- Use TypeScript - Better type safety
- Monitor performance - Use React DevTools Profiler
๐ฑ Mobile Quick Setupโ
const isMobile = useMediaQuery('(max-width: 768px)');
<div style={{
height: isMobile ? 'calc(100vh - 60px)' : '600px',
padding: isMobile ? '8px' : '20px'
}}>
<GenericOptimizedCalendar
onFetchEvents={fetchEvents}
defaultView={isMobile ? 'day' : 'month'}
/>
</div>
๐งช Quick Testโ
const mockFetchEvents = async () => {
return [
{
id: '1',
title: 'Test Event',
start: new Date(),
end: new Date(Date.now() + 3600000), // +1 hour
color: '#3174ad',
}
];
};
<GenericOptimizedCalendar onFetchEvents={mockFetchEvents} />
โก Performance Tipsโ
// 1. Memoize functions
const getEventColor = useMemo(() => (e) => e.color, []);
const isEventDisabled = useMemo(() => (e) => e.disabled, []);
// 2. Optimize query
<GenericOptimizedCalendar
staleTimeMs={5 * 60 * 1000}
queryOptions={{ refetchOnWindowFocus: false }}
/>
// 3. Lazy load
const Calendar = lazy(() => import('./Calendar'));
<Suspense fallback={<Loading />}>
<Calendar />
</Suspense>
๐ TypeScript Typesโ
import { GenericCalendarRef } from '@/components/Calendar/GenericCalendar';
import { CalendarEvent } from '@/components/Calendar/types';
import { SlotInfo, View } from 'react-big-calendar';
// Ref
const calendarRef = useRef<GenericCalendarRef>(null);
// Event
interface MyEvent extends CalendarEvent {
customField: string;
}
// Slot
const handleSelectSlot = (slotInfo: SlotInfo) => {
const { start, end, action } = slotInfo;
};
Print this page untuk quick reference! ๐จ๏ธ
Last updated: December 5, 2025