Welcome to the Mina Scheduler Library, a customizable and flexible calendar component for React that allows you to manage and display events in day, week, or month views. This library uses Next UI components for its user interface, so to ensure a consistent UI experience, make sure to use it inside a Next UI project.
- Day, Week, Month Views: Switch between different calendar views with ease.
- Event Management: Add, update, and delete events with built-in form validation.
- Customizable UI: Easily customize the look and feel of the calendar, including buttons, tabs, and event modals.
- Mobile-Friendly: Responsive design optimized for mobile devices.
- Framer Motion Animations: Smooth transitions between views.
- Zod Validation: Schema validation for ensuring valid event data.
- Next UI Integration: Leverages Next UI for a seamless user interface.
Live Demo : https://mina-scheduler.vercel.app/
To install the library, run:
npm install mina-scheduler
https://github.com/Mina-Massoud/next-ui-full-calendar
Since this library is built using Next UI components, it's recommended to use it within a Next UI project to maintain the same UI experience.
To include the styles from the mina-scheduler
package in your Tailwind CSS setup, add the following line to the content
array in your tailwind.config.js
:
content: [
"./node_modules/mina-scheduler/**/*.{js,ts,jsx,tsx}",
// other paths...
],
This line ensures that Tailwind scans all JavaScript and TypeScript files in the mina-scheduler
package for class names. Make sure to include any other relevant paths in the content
array as needed.
Here’s how you can get started using the SchedulerProvider and SchedularView components in your React project with minimal setup:
"use client";
import { SchedulerProvider, SchedularView } from "mina-scheduler";
export default function Home() {
return (
<section className="flex w-full flex-col items-center justify-center gap-4 py-8 md:py-10">
<SchedulerProvider>
<SchedularView />
</SchedulerProvider>
</section>
);
}
The SchedulerProvider
and useScheduler
hook allow you to manage and set initial events in the scheduler. Here’s a guide to set up initial events and integrate them into your scheduling component.
Ensure you Event types and your necessary modules:
"use client";
import { Event } from "@/dist";
To simulate initial events, create an array of events, each structured as an Event
type. In this example, endDate
is set to one hour after startDate
.
const events = [
{
id: "1d4c5c73-b5fa-4f67-bb6e-1d5d66cbd57d",
title: "Kickoff Meeting.",
description: "Initial project kickoff with stakeholders.",
startDate: new Date(), // today's date
endDate: new Date(new Date().getTime() + 60 * 60 * 1000), // one hour later
variant: "primary",
},
] as Event[];
Wrap your main content in SchedulerProvider
, passing initialState
and any other props like weekStartsOn
:
<SchedulerProvider initialState={events} weekStartsOn="monday">
<SchedulerWrapper
classNames={{
tabs: {
panel: "pt-3",
},
}}
/>
</SchedulerProvider>
The useScheduler
hook provides access to the dispatch
function, allowing you to set events dynamically after the component mounts. However, it’s not recommended to use useScheduler
at the top level of the component. If you use it, ensure that SchedulerProvider
is applied at a higher level in the component tree to provide the necessary context.
const { dispatch } = useScheduler();
useEffect(() => {
dispatch({ type: "SET_EVENTS", payload: events });
}, []);
You can customize the calendar by passing custom views, buttons, and event modals using the SchedularView
and SchedulerProvider
props:
"use client";
import { SchedulerProvider, SchedularView } from "mina-scheduler";
export default function Home() {
return (
<section className="flex w-full flex-col items-center justify-center gap-4 py-8 md:py-10">
<SchedulerProvider>
<SchedularView
classNames={{
buttons: {
addEvent: "bg-red-500",
next: "bg-blue-500",
prev: "bg-green-500",
},
}}
views={{ views: ["day", "month", "week"], mobileViews: ["day"] }}
CustomComponents={{
CustomEventModal: {
CustomAddEventModal: {
title: "Custom Add Event",
CustomForm: MyCustomForm,
},
},
}}
/>
</SchedulerProvider>
</section>
);
}
const MyCustomForm: React.FC<{ register: any; errors: any }> = ({
register,
errors,
}) => (
<>
<input
{...register("title")}
placeholder="Custom Event Name"
className={`input ${errors.title ? "input-error" : ""}`}
/>
{errors.title && (
<span className="error-message">{errors.title.message}</span>
)}
<textarea
{...register("description")}
placeholder="Custom Description"
className="textarea"
/>
<input
{...register("startDate")}
type="date"
className={`input ${errors.startDate ? "input-error" : ""}`}
/>
<input
{...register("endDate")}
type="date"
className={`input ${errors.endDate ? "input-error" : ""}`}
/>
<button type="submit" className="btn">
Submit
</button>
</>
);
The SchedulerProvider
component wraps the calendar and provides necessary context and state management for the events and calendar views.
- onAddEvent
(optional)
:(event: Event) => void
– Callback triggered when an event is added. - onUpdateEvent
(optional)
:(event: Event) => void
– Callback triggered when an event is updated. - onDeleteEvent
(optional)
:(id: string) => void
– Callback triggered when an event is deleted. - weekStartsOn
(optional)
:"sunday"
|"monday"
– Specifies the starting day of the week. Defaults to"sunday"
. - children:
ReactNode
– The children components to render within the provider.
This component is the main calendar view. It supports day, week, and month views, as well as custom components for event modals and buttons.
-
views
(optional)
:Views
– Specify which views (day, week, month) are available and which are shown on mobile.- views:
("day" | "week" | "month")[]
– The available views for desktop. - mobileViews:
("day" | "week" | "month")[]
– The available views for mobile devices.
- views:
-
CustomComponents
(optional)
:CustomComponents
– Customize components such as event modals, buttons, and tabs.- CustomEventModal: Customize event modals, such as the Add Event form.
- customTabs: Customize the tabs for Day, Week, and Month.
-
classNames
(optional)
:ClassNames
– Customize the styling of buttons, tabs, and other elements.
Here’s how you can structure the documentation for the useScheduler
hook in your library README, making it suitable for users looking to understand how to use the hook effectively.
The useScheduler
hook is a custom React hook that provides access to the SchedulerContext
. It allows components to access the current state of the scheduler, various utility functions (getters), and functions for modifying the state (handlers).
To use the useScheduler
hook, import it into your component and call it to access the scheduler's state, dispatch function, getters, and handlers.
import { useScheduler } from "mina-scheduler";
const MyComponent = () => {
const { events, dispatch, getters, handlers } = useScheduler();
// Example of using the dispatch to add an event
const addEvent = (event) => {
dispatch({ type: "ADD_EVENT", payload: event });
};
return (
<div>
{/* Render events */}
{events.map((event) => (
<div key={event.id}>{event.title}</div>
))}
</div>
);
};
The useScheduler
hook returns an object containing the following properties:
-
events
:- Type:
SchedulerState
- Description: Contains the current state of the scheduler, including an array of events.
- Type:
-
dispatch
:- Type:
Dispatch<Action>
- Description: A function to modify the scheduler state. Use it to send actions to the reducer.
The shape of the dispatch call is as follows:
dispatch({ type: "ADD_EVENT", // or "REMOVE_EVENT" or "UPDATE_EVENT" payload: { /* Event object */ } // required for "ADD_EVENT" and "UPDATE_EVENT" });
Action Types:
ADD_EVENT
: Adds a new event to the scheduler. Use this action when you want to create a new event.REMOVE_EVENT
: Removes an event based on itsid
. Use this action to delete an existing event.UPDATE_EVENT
: Updates an existing event. Use this action when you need to modify the details of an event.
- Type:
-
getters
:- Type:
Getters
- Description: An object containing utility functions to retrieve information from the scheduler state.
getDaysInMonth(month: number, year: number)
: Returns an array of objects representing each day in the specified month, each containing a list of events for that day.getEventsForDay(day: number, currentDate: Date)
: Retrieves all events for a specific day.getDaysInWeek(week: number, year: number)
: Returns an array of Date objects for the specified week.getWeekNumber(date: Date)
: Returns the week number for the given date.getDayName(day: number)
: Returns the name of the day for a given index (0 for Sunday, 6 for Saturday).
- Type:
-
handlers
:- Type:
Handlers
- Description: An object containing functions to handle specific actions related to events.
handleEventStyling(event: Event, dayEvents: Event[])
: Returns styling properties for rendering an event based on its position among other events on the same day.handleAddEvent(event: Event)
: Adds a new event to the scheduler. You can call this function to handle event creation logic.handleUpdateEvent(event: Event, id: string)
: Updates an existing event by itsid
. Use this function to modify event details.handleDeleteEvent(id: string)
: Deletes an event by itsid
. Call this function to remove events from the scheduler.
- Type:
Here’s a simple example of how to use the useScheduler
hook in a component:
import React from "react";
import { useScheduler } from "@/path/to/SchedulerContext";
const EventList = () => {
const { events, dispatch, handlers } = useScheduler();
const removeEvent = (id) => {
handlers.handleDeleteEvent(id);
};
return (
<div>
{events.events.map((event) => (
<div key={event.id}>
<h3>{event.title}</h3>
<button onClick={() => removeEvent(event.id)}>Delete</button>
</div>
))}
</div>
);
};
The library uses Zod for form validation, and React Hook Form for handling form data. Here's the event schema and how it's used in the form.
The eventSchema
defines the structure and validation rules for event forms using Zod.
export const eventSchema = z.object({
title: z.string().nonempty("Event name is required"),
description: z.string().optional(),
startDate: z.date(),
endDate: z.date(),
variant: z.enum(["primary", "danger", "success", "warning", "default"]),
color: z.string().nonempty("Color selection is required"),
});
The form data is handled through the EventFormData
interface, which corresponds to the schema's structure.
export type EventFormData = z.infer<typeof eventSchema>;
The SelectDate
component helps with selecting a date range and times for an event.
- data
(optional)
:{ startDate: Date; endDate: Date; time: Time }
– The initial data for start and end dates and times. - setValue:
UseFormSetValue<EventFormData>
– Function from React Hook Form to set form values.
import { UseFormSetValue } from "react-hook-form";
import SelectDate from "@/components/schedule/_components/add-event-components/select-date";
<SelectDate data={data} setValue={setValue} />
Represents an individual event on the calendar.
export interface Event {
id: string;
title: string;
description?: string;
startDate: Date;
endDate: Date;
variant?: Variant;
}
Defines the style variant of an event, which can be one of the following:
"success"
"primary"
"default"
"warning"
"danger"
Defines the available views for mobile and desktop.
export type Views = {
mobileViews?: string[];
views?: string[];
};
Specifies the starting day of the week, either "sunday"
or "monday"
.
export type startOfWeek = "sunday" | "monday";
Represents customization options for the event modal, including the form and title.
export interface CustomEventModal {
CustomAddEventModal?: {
title?: string;
CustomForm?: React.FC<{ register: any; errors: any }>;
};
}
Defines customizable components such as buttons, tabs, and event modals.
export interface CustomComponents {
customButtons?: {
CustomAddEventButton?: React.ReactNode;
CustomPrevButton?: React.ReactNode;
CustomNextButton?: React.ReactNode;
};
customTabs?: {
CustomDayTab?: React.ReactNode;
CustomWeekTab?: React.ReactNode;
CustomMonthTab?: React.ReactNode;
};
CustomEventComponent?: React.FC<Event>; // Using custom event type
CustomEventModal?: CustomEventModal;
}
Groups class names for buttons, tabs, and views.
export interface ClassNames {
event?: string;
buttons?: ButtonClassNames;
tabs?: TabsClassNames;
views?: ViewClassNames;
}
Specifies class names for previous, next, and add event buttons.
export interface ButtonClassNames {
prev?: string;
next?: string;
addEvent?: string;
}
Specifies class names for various parts of the tab interface.
export interface TabsClassNames {
cursor?: string;
panel?: string;
tab?: string;
tabContent?: string;
tabList?: string;
wrapper?: string;
}
Specifies class names for day, week, and month views.
export interface ViewClassNames {
dayView?: string;
weekView?: string;
monthView?: string;
}
This library is licensed under the MIT License.
Thank you, feel free to follow me on linkedIn : https://www.linkedin.com/in/mina-melad/ contact with me and discover my portfolio : https://mina-massoud.onrender.com/