@inxee_npm/scheduler v0.1.8
Installation
# yarn
yarn add '@inxee_npm/scheduler'
# npm
npm install '@inxee_npm/scheduler'Example usage
- import required styles for scheduler
import "@inxee_npm/scheduler/dist/style.css";- Import Scheduler component into your project
import { Scheduler, SchedulerData } from "@inxee_npm/scheduler";
import dayjs from "dayjs";
default export function Component() {
const [filterButtonState, setFilterButtonState] = useState(0);
const [range, setRange] = useState({
startDate: new Date(),
endDate: new Date()
});
const handleRangeChange = useCallback((range) => {
setRange(range);
}, []);
const filteredMockedSchedulerData = mockedSchedulerData.map((person) => ({
...person,
data: person.data.filter(
(project) =>
// we use "dayjs" for date calculations, but feel free to use library of your choice
dayjs(project.startDate).isBetween(range.startDate, range.endDate) ||
dayjs(project.endDate).isBetween(range.startDate, range.endDate) ||
(dayjs(project.startDate).isBefore(range.startDate, "day") &&
dayjs(project.endDate).isAfter(range.endDate, "day"))
)
}))
return (
<section>
<Scheduler
data={filteredMockedSchedulerData}
isLoading={isLoading}
onRangeChange={handleRangeChange}
onTileClick={(clickedResource) => console.log(clickedResource)}
onItemClick={(item) => console.log(item)}
onFilterData={() => {
// Some filtering logic...
setFilterButtonState(1);
}}
onClearFilterData={() => {
// Some clearing filters logic...
setFilterButtonState(0)
}}
config={{
zoom: 0,
filterButtonState,
}}
/>
</section>
);
}
const mockedSchedulerData: SchedulerData = [
{
id: "070ac5b5-8369-4cd2-8ba2-0a209130cc60",
label: {
icon: "https://picsum.photos/24",
title: "Joe Doe",
subtitle: "Frontend Developer"
},
data: [
{
id: "8b71a8a5-33dd-4fc8-9caa-b4a584ba3762",
startDate: new Date("2023-04-13T15:31:24.272Z"),
endDate: new Date("2023-08-28T10:28:22.649Z"),
occupancy: 3600,
title: "Project A",
subtitle: "Subtitle A",
description: "array indexing Salad West Account",
bgColor: "rgb(254,165,177)"
},
{
id: "22fbe237-6344-4c8e-affb-64a1750f33bd",
startDate: new Date("2023-10-07T08:16:31.123Z"),
endDate: new Date("2023-11-15T21:55:23.582Z"),
occupancy: 2852,
title: "Project B",
subtitle: "Subtitle B",
description: "Tuna Home pascal IP drive",
bgColor: "rgb(254,165,177)"
},
{
id: "3601c1cd-f4b5-46bc-8564-8c983919e3f5",
startDate: new Date("2023-03-30T22:25:14.377Z"),
endDate: new Date("2023-09-01T07:20:50.526Z"),
occupancy: 1800,
title: "Project C",
subtitle: "Subtitle C",
bgColor: "rgb(254,165,177)"
},
{
id: "b088e4ac-9911-426f-aef3-843d75e714c2",
startDate: new Date("2023-10-28T10:08:22.986Z"),
endDate: new Date("2023-10-30T12:30:30.150Z"),
occupancy: 11111,
title: "Project D",
subtitle: "Subtitle D",
description: "Garden heavy an software Metal",
bgColor: "rgb(254,165,177)"
}
]
}
];- If some problems occur, please see our troubleshooting section below.
Scheduler API
Scheduler Component Props
| Property Name | Type | Arguments | Description |
|---|---|---|---|
| isLoading | boolean | - | shows loading indicators on scheduler |
| onRangeChange | function | updated startDate and endDate | runs whenever user reaches end of currently rendered canvas |
| onTileClick | function | clicked resource data | detects resource click |
| onItemClick | function | clicked left column item data | detects item click on left column |
| onFilterData | function | - | callback firing when filter button was clicked |
| onClearFilterData | function | - | callback firing when clear filters button was clicked (clearing button is visible only when filterButtonState is set to >0) |
| config | Config | - | object with scheduler config properties |
Scheduler Config Object
| Property Name | Type | Default | Description |
|---|---|---|---|
| zoom | 0 or 1 or 2 | 0 | 0 - display grid divided into weeks 1 - display grid divided into days 2 - display grid divided into hours |
| filterButtonState | number | 0 | < 0 - hides filter button, 0 - state for when filters were not set, > 0 - state for when some filters were set (allows to also handle onClearFilterData event) |
| maxRecordsPerPage | number | 50 | number of items from SchedulerData visible per page |
| lang | en, lt or pl | en | scheduler's language |
| includeTakenHoursOnWeekendsInDayView | boolean | false | show weekends as taken when given resource is longer than a week |
| showTooltip | boolean | true | show tooltip when hovering over tiles |
| translations | LocaleType[] | undefined | option to add specific langs translations |
| showThemeToggle | boolean | false | show toggle button to switch between light/dark mode |
| defaultTheme | light or dark | light | scheduler's default theme |
Translation object example
import enDayjsTranslations from "dayjs/locale/en";
const langs: LocaleType[] = [
{
id: "en",
lang: {
feelingEmpty: "I feel so empty...",
free: "Free",
loadNext: "Next",
loadPrevious: "Previous",
over: "over",
taken: "Taken",
topbar: {
filters: "Filters",
next: "next",
prev: "prev",
today: "Today",
view: "View"
},
search: "search",
week: "week"
},
translateCode: "en-EN",
dayjsTranslations: enDayjsTranslations
}
];
<Scheduler
// ... //
config={{
lang: "en",
translations: langs
}}
/>;Scheduler LocaleType Object
| Property Name | Type | Description |
|---|---|---|
| id | string | key is needed for selecting lang |
| lang | Translation | object with translations |
| translateCode | string | code that is saved in localStorage |
| dayjsTranslations | string ILocale undefined | object with translation from dayjs |
Scheduler Translation Object
| Property Name | Type |
|---|---|
| feelingEmpty | string |
| free | string |
| loadNext | string |
| loadPrevious | string |
| over | string |
| taken | string |
| search | string |
| week | string |
| topbar | Topbar |
Scheduler Topbar Object
| Property Name | Type |
|---|---|
| filters | string |
| next | string |
| prev | string |
| today | string |
| view | string |
Scheduler Data
array of chart rows with shape of
| Property Name | Type | Description |
| -------- | --------------------- | -------------------------------- |
| id | string | unique row id |
| label | SchedulerRowLabel | row's label, e.g person's name, surname, icon |
| data | Array<ResourceItem> | array of resources |
Left Colum Item Data
data that is accessible as argument of onItemClick callback
| Property Name | Type | Description |
| -------- | --------------------- | -------------------------------- |
| id | string | unique row id |
| label | SchedulerRowLabel | row's label, e.g person's name, surname, icon |
Resource Item
item that will be visible on the grid as tile and that will be accessible as argument of onTileClick event
| Property Name | Type | Description |
| ----------- | ----------------- | ------------------------------------------------------------------------------------------------------- |
| id | string | unique resource id |
| title | string | resource title that will be displayed on resource tile |
| subtitle | string (optional) | resource subtitle that will be displayed on resource tile |
| description | string (optional) | resource description that will be displayed on resource tile |
| startDate | Date | date for calculating start position for resource |
| endDate | Date | date for calculating end position for resource |
| occupancy | number | number of seconds resource takes up for given row that will be visible on resource tooltip when hovered |
| bgColor | string (optional) | tile color |
Troubleshooting
- For using Scheduler with RemixJS make sure to add
@bitnoi.se/react-schedulertoserverDependenciesToBundleinremix.config.jslike so:
// remix.config.js
/** @type {import('@remix-run/dev').AppConfig} */
module.exports = {
// ...
serverDependenciesToBundle: [..., "@bitnoi.se/react-scheduler"],
};- When using with NextJS (app router) Scheduler needs to be wrapped with component with
use client
"use client"
import { Scheduler, SchedulerProps } from "@bitnoi.se/react-scheduler";
default export function SchedulerClient(props: SchedulerProps) {
return <Scheduler {...props} />;
}- When using with NextJS (pages router) it needs to be imported using
dynamic:
import dynamic from "next/dynamic";
const Scheduler = dynamic(() => import("@bitnoi.se/react-scheduler").then((mod) => mod.Scheduler), {
ssr: false
});- How to customize Scheduler dimensions
Scheduler is position absolutely to take all available space. If you want to have fixed dimensions wrap Scheduler inside a div with position set to relative.
Example using styled components:
export const StyledSchedulerFrame = styled.div`
position: relative;
height: 40vh;
width: 40vw;
`;
<StyledSchedulerFrame>
<Scheduler {...}/>
</StyledSchedulerFrame>Known Issues
- No responsiveness
- Slower performance on Firefox when working with big set of data due to Firefox being slower working with canvas
License
MIT Licensed. Copyright (c) Inxee 2025.