My App
CourseKitFrontend

Components

Pre-styled schedule components — TimetableGrid, EventCard, ConflictBadge, AvailabilityOverlay

TimetableGrid

A week/day grid view with configurable time axis and custom event rendering.

import { TimetableGrid } from '@hfu.digital/coursekit-react';

Props

interface TimetableGridProps {
    weekStart: string;
    startHour?: number;      // default: 8
    endHour?: number;        // default: 20
    days?: string[];         // default: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri']
    events?: TimetableGridEvent[];
    renderEvent?: (event: TimetableGridEvent) => ReactNode;
    hourHeight?: number;     // default: 60 (pixels per hour)
    className?: string;
}
PropTypeDefaultDescription
weekStartstringISO date of the first day (Monday)
startHournumber8First hour displayed on the time axis
endHournumber20Last hour displayed on the time axis
daysstring[]['Mon'..'Fri']Day labels for columns
eventsTimetableGridEvent[][]Events to render on the grid
renderEventfunctionCustom event renderer (overrides default block)
hourHeightnumber60Pixel height per hour row
classNamestringCSS class (disables built-in styles)

TimetableGridEvent

interface TimetableGridEvent {
    id: string;
    title: string;
    startTime: string;
    durationMin: number;
    dayIndex: number; // 0-based index into the days array
}

Example

<TimetableGrid
    weekStart="2026-03-02"
    startHour={8}
    endHour={18}
    events={[
        { id: '1', title: 'Math 101', startTime: '2026-03-02T09:00:00', durationMin: 90, dayIndex: 0 },
        { id: '2', title: 'Physics', startTime: '2026-03-03T14:00:00', durationMin: 60, dayIndex: 1 },
    ]}
/>

Custom Rendering

<TimetableGrid
    weekStart="2026-03-02"
    events={events}
    renderEvent={(event) => (
        <div className="my-event-card">
            <strong>{event.title}</strong>
            <span>{event.durationMin}min</span>
        </div>
    )}
/>

When className is provided, all built-in inline styles are disabled so you can style the grid entirely with CSS.


EventCard

Displays a single event with visual styling for exceptions.

import { EventCard } from '@hfu.digital/coursekit-react';

Props

interface EventCardProps {
    title: string;
    startTime: string;
    durationMin: number;
    room?: string | null;
    instructor?: string | null;
    isException?: boolean;
    exceptionType?: 'cancelled' | 'modified' | 'added' | null;
    className?: string;
    children?: ReactNode;
    onClick?: () => void;
}

Exception Styling

Exception TypeVisual Treatment
cancelledReduced opacity, strikethrough, red background
modifiedYellow background with amber border
addedGreen background with green border

Example

<EventCard
    title="Math 101"
    startTime="2026-03-02T09:00:00"
    durationMin={90}
    room="Room A1"
    instructor="Prof. Smith"
    isException={true}
    exceptionType="modified"
    onClick={() => console.log('Card clicked')}
/>

ConflictBadge

An inline badge that displays a conflict message with severity-based styling.

import { ConflictBadge } from '@hfu.digital/coursekit-react';

Props

interface ConflictBadgeProps {
    severity: 'error' | 'warning';
    message: string;
    type?: string;
    className?: string;
}
SeverityVisual Treatment
errorRed background, red text
warningYellow background, amber text

Example

<ConflictBadge
    severity="error"
    message="Room A1 has overlapping events"
    type="room-overlap"
/>

AvailabilityOverlay

Renders colored overlays on the timetable grid to show availability blocks.

import { AvailabilityOverlay } from '@hfu.digital/coursekit-react';

Props

interface AvailabilityOverlayProps {
    blocks: AvailabilityBlock[];
    startHour?: number;    // must match TimetableGrid (default: 8)
    hourHeight?: number;   // must match TimetableGrid (default: 60)
    dayCount?: number;     // must match TimetableGrid (default: 5)
    className?: string;
}

AvailabilityBlock

interface AvailabilityBlock {
    startTime: string;
    endTime: string;
    dayIndex: number;
    type: 'available' | 'blocked' | 'preferred';
    hardness: 'hard' | 'soft';
}

Color Scheme

Type + HardnessColor
blocked-hardStrong red overlay
blocked-softLight red overlay
available-hardGreen overlay
available-softLight green overlay
preferred-hardBlue overlay
preferred-softLight blue overlay

Example

<div style={{ position: 'relative' }}>
    <TimetableGrid weekStart="2026-03-02" />
    <AvailabilityOverlay
        blocks={[
            {
                startTime: '2026-03-02T12:00:00',
                endTime: '2026-03-02T13:00:00',
                dayIndex: 0,
                type: 'blocked',
                hardness: 'hard',
            },
        ]}
    />
</div>

The overlay is positioned absolutely and uses pointerEvents: 'none' so it doesn't interfere with click events on the grid.

On this page