Skip to content

[WC-2892]: Calendar improvements #1628

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 18 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
3160d9a
feat(calendar-web): add hour scope for the day view
rahmanunver Jun 13, 2025
9057ee4
feat(calendar-web): add showAllEvents prop for month view
rahmanunver Jun 13, 2025
5ce767f
feat(calendar-web): add custom week day selection
rahmanunver Jun 17, 2025
67d05b4
feat(calendar-web): split standard and custom config
rahmanunver Jun 17, 2025
0e9b5b0
feat(calendar-web): editorconfig edits
rahmanunver Jun 17, 2025
5a44d1f
test(calendar-web): update snapshot
rahmanunver Jun 19, 2025
0afeb64
fix: small text changes
samuelreichert Jun 24, 2025
6e511a8
feat(calendar-web): create CustomWeekController to handle CustomWeek …
samuelreichert Jun 24, 2025
4e1d68b
feat(calendar-web): create CalendarPropsBuilder
samuelreichert Jun 24, 2025
9389087
chore(calendar-web): update calendar-utils to have only functions nee…
samuelreichert Jun 24, 2025
2f5ac79
feat(calendar-web): use the new CalendarPropsBuilder
samuelreichert Jun 24, 2025
0e24def
refactor(calendar-web): convert event handlers to arrow functions and…
samuelreichert Jun 25, 2025
4b9f54f
test(calendar-web): update Calendar snapshot to reflect recent changes
samuelreichert Jun 25, 2025
fd98076
feat(calendar-web): add buildFormats method to customize event displa…
samuelreichert Jun 27, 2025
b790681
feat(calendar-web): add time format property to Calendar widget
samuelreichert Jun 27, 2025
4fc334a
feat(calendar-web): add custom formats handling in CalendarPropsBuilder
samuelreichert Jun 27, 2025
43fa770
test(calendar-web): update test with timezone set to UTC
rahmanunver Jul 4, 2025
9d05f32
Revert "test(calendar-web): update test with timezone set to UTC"
rahmanunver Jul 4, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,23 @@ export function getProperties(values: CalendarPreviewProps, defaultProperties: P
hidePropertiesIn(defaultProperties, values, ["maxHeight", "overflowY"]);
}

// Hide custom week range properties when the view is set to 'standard'
if (values.view === "standard") {
hidePropertiesIn(defaultProperties, values, [
"defaultViewCustom",
"showSunday",
"showMonday",
"showTuesday",
"showWednesday",
"showThursday",
"showFriday",
"showSaturday",
"customViewCaption"
]);
} else {
hidePropertyIn(defaultProperties, values, "defaultViewStandard");
}

// Show/hide title properties based on selection
if (values.titleType === "attribute") {
hidePropertyIn(defaultProperties, values, "titleExpression");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import classnames from "classnames";
import * as dateFns from "date-fns";
import { ReactElement, createElement } from "react";
import { Calendar, dateFnsLocalizer } from "react-big-calendar";
import { Calendar, dateFnsLocalizer, EventPropGetter } from "react-big-calendar";
import { CalendarPreviewProps } from "../typings/CalendarProps";
import { CustomToolbar } from "./components/Toolbar";
import { constructWrapperStyle, WrapperStyleProps } from "./utils/style-utils";
Expand Down Expand Up @@ -73,15 +73,19 @@ export function preview(props: CalendarPreviewProps): ReactElement {
const { class: className } = props;
const wrapperStyle = constructWrapperStyle(props as WrapperStyleProps);

// Cast eventPropGetter to satisfy preview Calendar generic
const previewEventPropGetter = eventPropGetter as unknown as EventPropGetter<(typeof events)[0]>;

return (
<div className={classnames("widget-events-preview", "widget-calendar", className)} style={wrapperStyle}>
<Calendar
components={{ toolbar: CustomToolbar }}
defaultView={props.defaultView}
defaultView={props.defaultViewStandard}
events={events}
localizer={localizer}
views={["day", "week", "month"]}
eventPropGetter={eventPropGetter}
messages={{ ...localizer.messages, work_week: "Custom" }}
views={["day", "week", "month", "work_week"]}
eventPropGetter={previewEventPropGetter}
/>
</div>
);
Expand Down
5 changes: 3 additions & 2 deletions packages/pluggableWidgets/calendar-web/src/Calendar.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import classnames from "classnames";
import { ReactElement, createElement } from "react";
import { DnDCalendar, extractCalendarProps } from "./utils/calendar-utils";
import { CalendarContainerProps } from "../typings/CalendarProps";
import { CalendarPropsBuilder } from "./helpers/CalendarPropsBuilder";
import { DnDCalendar } from "./utils/calendar-utils";
import { constructWrapperStyle } from "./utils/style-utils";
import "./ui/Calendar.scss";

export default function MxCalendar(props: CalendarContainerProps): ReactElement {
const { class: className } = props;
const wrapperStyle = constructWrapperStyle(props);
const calendarProps = extractCalendarProps(props);
const calendarProps = new CalendarPropsBuilder(props).build();

return (
<div className={classnames("widget-calendar", className)} style={wrapperStyle}>
Expand Down
77 changes: 70 additions & 7 deletions packages/pluggableWidgets/calendar-web/src/Calendar.xml
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
</property>
<property key="eventColor" type="attribute" dataSource="databaseDataSource" required="false">
<caption>Color attribute</caption>
<description>Attribute containing a valid html color eg: red #FF0000 rgb(250,10,20) rgba(10,10,10, 0.5)</description>
<description>Attribute containing a valid HTML color eg: red #FF0000 rgb(250,10,20) rgba(10,10,10, 0.5)</description>
<attributeTypes>
<attributeType name="Enum" />
<attributeType name="String" />
Expand Down Expand Up @@ -87,15 +87,24 @@
<caption>Show event date range</caption>
<description>Show the start and end date of the event</description>
</property>
<property key="defaultView" type="enumeration" defaultValue="month">
<property key="defaultViewCustom" type="enumeration" defaultValue="month">
<caption>Initial selected view</caption>
<description>Work week and agenda are only available in custom views</description>
<description>The default view showed when the calendar is loaded</description>
<enumerationValues>
<enumerationValue key="day">Day</enumerationValue>
<enumerationValue key="week">Week</enumerationValue>
<enumerationValue key="month">Month</enumerationValue>
<enumerationValue key="work_week">Custom</enumerationValue>
<enumerationValue key="agenda">Agenda</enumerationValue>
</enumerationValues>
</property>
<property key="defaultViewStandard" type="enumeration" defaultValue="month">
<caption>Initial selected view</caption>
<description>The default view showed when the calendar is loaded</description>
<enumerationValues>
<enumerationValue key="day">Day</enumerationValue>
<enumerationValue key="week">Week</enumerationValue>
<enumerationValue key="month">Month</enumerationValue>
<enumerationValue key="work_week">(Work week)</enumerationValue>
<enumerationValue key="agenda">(Agenda)</enumerationValue>
</enumerationValues>
</property>
<property key="startDateAttribute" type="attribute" required="false">
Expand All @@ -105,6 +114,56 @@
<attributeType name="DateTime" />
</attributeTypes>
</property>
<property key="timeFormat" type="textTemplate" required="false">
<caption>Time format</caption>
<description>Default time format is "hh:mm a"</description>
</property>
<property key="minHour" type="integer" defaultValue="0">
<caption>Day start hour</caption>
<description>The hour at which the day view starts (0–23)</description>
</property>
<property key="maxHour" type="integer" defaultValue="24">
<caption>Day end hour</caption>
<description>The hour at which the day view ends (1–24)</description>
</property>
<!-- Custom week caption -->
<property key="customViewCaption" type="textTemplate" required="false">
<caption>Custom view caption</caption>
<description>Label used for the custom work-week button and title. Defaults to "Custom".</description>
<translations>
<translation lang="en_US">Custom</translation>
</translations>
</property>
</propertyGroup>
<propertyGroup caption="Visible days">
<property key="showMonday" type="boolean" defaultValue="true">
<caption>Monday</caption>
<description>Show Monday in the custom work-week view</description>
</property>
<property key="showTuesday" type="boolean" defaultValue="true">
<caption>Tuesday</caption>
<description>Show Tuesday in the custom work-week view</description>
</property>
<property key="showWednesday" type="boolean" defaultValue="true">
<caption>Wednesday</caption>
<description>Show Wednesday in the custom work-week view</description>
</property>
<property key="showThursday" type="boolean" defaultValue="true">
<caption>Thursday</caption>
<description>Show Thursday in the custom work-week view</description>
</property>
<property key="showFriday" type="boolean" defaultValue="true">
<caption>Friday</caption>
<description>Show Friday in the custom work-week view</description>
</property>
<property key="showSunday" type="boolean" defaultValue="false">
<caption>Sunday</caption>
<description>Show Sunday in the custom work-week view</description>
</property>
<property key="showSaturday" type="boolean" defaultValue="false">
<caption>Saturday</caption>
<description>Show Saturday in the custom work-week view</description>
</property>
</propertyGroup>
</propertyGroup>
<propertyGroup caption="Events">
Expand All @@ -115,7 +174,7 @@
<attributeType name="String" />
</attributeTypes>
</property>
<property key="onClickEvent" type="action" required="false">
<property key="onClickEvent" type="action" required="false" dataSource="databaseDataSource">
<caption>On click action</caption>
<description />
<actionVariables>
Expand All @@ -134,7 +193,7 @@
<actionVariable key="allDay" type="Boolean" caption="All day flag" />
</actionVariables>
</property>
<property key="onChange" type="action" required="false">
<property key="onChange" type="action" required="false" dataSource="databaseDataSource">
<caption>On change action</caption>
<description>The change event is triggered on moving/dragging an item or changing the start or end time of by resizing an item</description>
<actionVariables>
Expand Down Expand Up @@ -218,6 +277,10 @@
<enumerationValue key="hidden">Hidden</enumerationValue>
</enumerationValues>
</property>
<property key="showAllEvents" type="boolean" defaultValue="true">
<caption>Show all events</caption>
<description>Auto-adjust calendar height to display all events without "more" links</description>
</property>
</propertyGroup>
</properties>
</widget>
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,42 @@ import { ListValueBuilder } from "@mendix/widget-plugin-test-utils";

import Calendar from "../Calendar";
import { CalendarContainerProps } from "../../typings/CalendarProps";
const defaultProps: CalendarContainerProps = {
const customViewProps: CalendarContainerProps = {
name: "calendar-test",
class: "calendar-class",
tabIndex: 0,
databaseDataSource: new ListValueBuilder().withItems([]).build(),
titleType: "attribute",
view: "standard",
defaultView: "month",
view: "custom",
defaultViewStandard: "month",
defaultViewCustom: "work_week",
editable: "default",
enableCreate: true,
widthUnit: "percentage",
width: 100,
heightUnit: "pixels",
height: 400,
minHour: 0,
maxHour: 24,
minHeightUnit: "pixels",
minHeight: 400,
maxHeightUnit: "none",
maxHeight: 400,
overflowY: "auto",
showEventDate: true
showEventDate: true,
showSunday: false,
showMonday: true,
showTuesday: true,
showWednesday: true,
showThursday: true,
showFriday: true,
showSaturday: false,
showAllEvents: true
};

const standardViewProps: CalendarContainerProps = {
...customViewProps,
view: "standard"
};

beforeAll(() => {
Expand All @@ -37,13 +53,18 @@ afterAll(() => {

describe("Calendar", () => {
it("renders correctly with basic props", () => {
const calendar = render(<Calendar {...defaultProps} />);
const calendar = render(<Calendar {...customViewProps} />);
expect(calendar).toMatchSnapshot();
});

it("renders with correct class name", () => {
const { container } = render(<Calendar {...defaultProps} />);
const { container } = render(<Calendar {...customViewProps} />);
expect(container.querySelector(".widget-calendar")).toBeTruthy();
expect(container.querySelector(".calendar-class")).toBeTruthy();
});

it("does not render custom view button in standard view", () => {
const { queryByText } = render(<Calendar {...standardViewProps} />);
expect(queryByText("Custom")).toBeNull();
});
});
Loading
Loading