Co-authored-by: Camille Moussu <cmoussu@linagora.com>
This commit is contained in:
@@ -360,7 +360,7 @@ describe("calendar Availability search", () => {
|
|||||||
|
|
||||||
calendarApi.changeView("dayGridMonth");
|
calendarApi.changeView("dayGridMonth");
|
||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
expect(screen.queryAllByRole("columnheader").length).toBe(7);
|
expect(screen.queryAllByRole("columnheader").length).toBe(14);
|
||||||
});
|
});
|
||||||
|
|
||||||
const dayNumbers = screen.getAllByRole("columnheader");
|
const dayNumbers = screen.getAllByRole("columnheader");
|
||||||
@@ -394,8 +394,8 @@ describe("calendar Availability search", () => {
|
|||||||
calendarApi.changeView("dayGridMonth");
|
calendarApi.changeView("dayGridMonth");
|
||||||
fireEvent.click(screen.getByTestId("ChevronRightIcon"));
|
fireEvent.click(screen.getByTestId("ChevronRightIcon"));
|
||||||
|
|
||||||
expect(spy).toHaveBeenCalledTimes(2);
|
expect(spy).toHaveBeenCalledTimes(4);
|
||||||
const callArgs = spy.mock.calls[1][0];
|
const callArgs = spy.mock.calls[3][0];
|
||||||
expect(callArgs.calId).toBe("user1/cal1");
|
expect(callArgs.calId).toBe("user1/cal1");
|
||||||
|
|
||||||
const startDate = new Date(
|
const startDate = new Date(
|
||||||
|
|||||||
@@ -57,6 +57,6 @@ describe("MiniCalendar", () => {
|
|||||||
const dateTestId = `date-${today.getFullYear()}-${today.getMonth()}-${today.getDate()}`;
|
const dateTestId = `date-${today.getFullYear()}-${today.getMonth()}-${today.getDate()}`;
|
||||||
|
|
||||||
const todayTile = screen.getByTestId(dateTestId);
|
const todayTile = screen.getByTestId(dateTestId);
|
||||||
expect(todayTile?.parentElement).toHaveClass("today");
|
expect(todayTile).toHaveClass("today");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Generated
+116
-80
@@ -19,6 +19,7 @@
|
|||||||
"@fullcalendar/timegrid": "^6.1.17",
|
"@fullcalendar/timegrid": "^6.1.17",
|
||||||
"@mui/icons-material": "^7.1.2",
|
"@mui/icons-material": "^7.1.2",
|
||||||
"@mui/material": "^7.1.2",
|
"@mui/material": "^7.1.2",
|
||||||
|
"@mui/x-date-pickers": "^8.14.0",
|
||||||
"@reduxjs/toolkit": "^2.8.2",
|
"@reduxjs/toolkit": "^2.8.2",
|
||||||
"@types/node": "^16.18.126",
|
"@types/node": "^16.18.126",
|
||||||
"@types/react": "^19.1.8",
|
"@types/react": "^19.1.8",
|
||||||
@@ -30,7 +31,6 @@
|
|||||||
"moment-timezone": "^0.5.48",
|
"moment-timezone": "^0.5.48",
|
||||||
"openid-client": "^6.5.3",
|
"openid-client": "^6.5.3",
|
||||||
"react": "^19.1.0",
|
"react": "^19.1.0",
|
||||||
"react-calendar": "^6.0.0",
|
|
||||||
"react-dom": "^19.1.0",
|
"react-dom": "^19.1.0",
|
||||||
"react-i18next": "^13.5.0",
|
"react-i18next": "^13.5.0",
|
||||||
"react-redux": "^9.2.0",
|
"react-redux": "^9.2.0",
|
||||||
@@ -1908,7 +1908,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/runtime": {
|
"node_modules/@babel/runtime": {
|
||||||
"version": "7.27.6",
|
"version": "7.28.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz",
|
||||||
|
"integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
@@ -3261,10 +3263,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@mui/types": {
|
"node_modules/@mui/types": {
|
||||||
"version": "7.4.4",
|
"version": "7.4.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/@mui/types/-/types-7.4.7.tgz",
|
||||||
|
"integrity": "sha512-8vVje9rdEr1rY8oIkYgP+Su5Kwl6ik7O3jQ0wl78JGSmiZhRHV+vkjooGdKD8pbtZbutXFVTWQYshu2b3sG9zw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.27.6"
|
"@babel/runtime": "^7.28.4"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0"
|
"@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||||
@@ -3276,15 +3280,17 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@mui/utils": {
|
"node_modules/@mui/utils": {
|
||||||
"version": "7.2.0",
|
"version": "7.3.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@mui/utils/-/utils-7.3.3.tgz",
|
||||||
|
"integrity": "sha512-kwNAUh7bLZ7mRz9JZ+6qfRnnxbE4Zuc+RzXnhSpRSxjTlSTj7b4JxRLXpG+MVtPVtqks5k/XC8No1Vs3x4Z2gg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.27.6",
|
"@babel/runtime": "^7.28.4",
|
||||||
"@mui/types": "^7.4.4",
|
"@mui/types": "^7.4.7",
|
||||||
"@types/prop-types": "^15.7.15",
|
"@types/prop-types": "^15.7.15",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"prop-types": "^15.8.1",
|
"prop-types": "^15.8.1",
|
||||||
"react-is": "^19.1.0"
|
"react-is": "^19.1.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=14.0.0"
|
"node": ">=14.0.0"
|
||||||
@@ -3303,6 +3309,94 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@mui/x-date-pickers": {
|
||||||
|
"version": "8.14.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@mui/x-date-pickers/-/x-date-pickers-8.14.0.tgz",
|
||||||
|
"integrity": "sha512-fz8z1hoi1tbG1QUcZAkQdiO3GsCOpUeRfyANXDDzDN88L4VqwNEyrv0wmzmCfIX2sgur4gWwWJzMuCvauMgXRw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.28.4",
|
||||||
|
"@mui/utils": "^7.3.3",
|
||||||
|
"@mui/x-internals": "8.14.0",
|
||||||
|
"@types/react-transition-group": "^4.4.12",
|
||||||
|
"clsx": "^2.1.1",
|
||||||
|
"prop-types": "^15.8.1",
|
||||||
|
"react-transition-group": "^4.4.5"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/mui-org"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@emotion/react": "^11.9.0",
|
||||||
|
"@emotion/styled": "^11.8.1",
|
||||||
|
"@mui/material": "^5.15.14 || ^6.0.0 || ^7.0.0",
|
||||||
|
"@mui/system": "^5.15.14 || ^6.0.0 || ^7.0.0",
|
||||||
|
"date-fns": "^2.25.0 || ^3.2.0 || ^4.0.0",
|
||||||
|
"date-fns-jalali": "^2.13.0-0 || ^3.2.0-0 || ^4.0.0-0",
|
||||||
|
"dayjs": "^1.10.7",
|
||||||
|
"luxon": "^3.0.2",
|
||||||
|
"moment": "^2.29.4",
|
||||||
|
"moment-hijri": "^2.1.2 || ^3.0.0",
|
||||||
|
"moment-jalaali": "^0.7.4 || ^0.8.0 || ^0.9.0 || ^0.10.0",
|
||||||
|
"react": "^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||||
|
"react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@emotion/react": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@emotion/styled": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"date-fns": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"date-fns-jalali": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"dayjs": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"luxon": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"moment": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"moment-hijri": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"moment-jalaali": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@mui/x-internals": {
|
||||||
|
"version": "8.14.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@mui/x-internals/-/x-internals-8.14.0.tgz",
|
||||||
|
"integrity": "sha512-esYyl61nuuFXiN631TWuPh2tqdoyTdBI/4UXgwH3rytF8jiWvy6prPBPRHEH1nvW3fgw9FoBI48FlOO+yEI8xg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.28.4",
|
||||||
|
"@mui/utils": "^7.3.3",
|
||||||
|
"reselect": "^5.1.1",
|
||||||
|
"use-sync-external-store": "^1.6.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/mui-org"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@napi-rs/wasm-runtime": {
|
"node_modules/@napi-rs/wasm-runtime": {
|
||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.0.3.tgz",
|
||||||
@@ -5115,13 +5209,6 @@
|
|||||||
"linux"
|
"linux"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@wojtekmaj/date-utils": {
|
|
||||||
"version": "2.0.2",
|
|
||||||
"license": "MIT",
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/wojtekmaj/date-utils?sponsor=1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/acorn": {
|
"node_modules/acorn": {
|
||||||
"version": "8.15.0",
|
"version": "8.15.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@@ -6408,6 +6495,14 @@
|
|||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/dayjs": {
|
||||||
|
"version": "1.11.18",
|
||||||
|
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.18.tgz",
|
||||||
|
"integrity": "sha512-zFBQ7WFRvVRhKcWoUh+ZA1g2HVgUbsZm9sbddh8EC5iv93sui8DVVz1Npvz+r6meo9VKfa8NyLWBsQK1VvIKPA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"peer": true
|
||||||
|
},
|
||||||
"node_modules/debug": {
|
"node_modules/debug": {
|
||||||
"version": "4.4.1",
|
"version": "4.4.1",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@@ -8203,16 +8298,6 @@
|
|||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/get-user-locale": {
|
|
||||||
"version": "3.0.0",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"memoize": "^10.0.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/wojtekmaj/get-user-locale?sponsor=1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/glob": {
|
"node_modules/glob": {
|
||||||
"version": "7.2.3",
|
"version": "7.2.3",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
@@ -10752,19 +10837,6 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "CC0-1.0"
|
"license": "CC0-1.0"
|
||||||
},
|
},
|
||||||
"node_modules/memoize": {
|
|
||||||
"version": "10.1.0",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"mimic-function": "^5.0.1"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sindresorhus/memoize?sponsor=1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/merge": {
|
"node_modules/merge": {
|
||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
@@ -10803,16 +10875,6 @@
|
|||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/mimic-function": {
|
|
||||||
"version": "5.0.1",
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/min-indent": {
|
"node_modules/min-indent": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
@@ -11733,29 +11795,6 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/react-calendar": {
|
|
||||||
"version": "6.0.0",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@wojtekmaj/date-utils": "^2.0.2",
|
|
||||||
"clsx": "^2.0.0",
|
|
||||||
"get-user-locale": "^3.0.0",
|
|
||||||
"warning": "^4.0.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/wojtekmaj/react-calendar?sponsor=1"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
|
|
||||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
|
|
||||||
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
|
||||||
},
|
|
||||||
"peerDependenciesMeta": {
|
|
||||||
"@types/react": {
|
|
||||||
"optional": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/react-dom": {
|
"node_modules/react-dom": {
|
||||||
"version": "19.1.0",
|
"version": "19.1.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@@ -11787,7 +11826,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/react-is": {
|
"node_modules/react-is": {
|
||||||
"version": "19.1.0",
|
"version": "19.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.0.tgz",
|
||||||
|
"integrity": "sha512-x3Ax3kNSMIIkyVYhWPyO09bu0uttcAIoecO/um/rKGQ4EltYWVYtyiGkS/3xMynrbVQdS69Jhlv8FXUEZehlzA==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/react-redux": {
|
"node_modules/react-redux": {
|
||||||
@@ -13485,7 +13526,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/use-sync-external-store": {
|
"node_modules/use-sync-external-store": {
|
||||||
"version": "1.5.0",
|
"version": "1.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz",
|
||||||
|
"integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||||
@@ -13547,13 +13590,6 @@
|
|||||||
"makeerror": "1.0.12"
|
"makeerror": "1.0.12"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/warning": {
|
|
||||||
"version": "4.0.3",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"loose-envify": "^1.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/web-vitals": {
|
"node_modules/web-vitals": {
|
||||||
"version": "2.1.4",
|
"version": "2.1.4",
|
||||||
"license": "Apache-2.0"
|
"license": "Apache-2.0"
|
||||||
|
|||||||
+1
-2
@@ -14,6 +14,7 @@
|
|||||||
"@fullcalendar/timegrid": "^6.1.17",
|
"@fullcalendar/timegrid": "^6.1.17",
|
||||||
"@mui/icons-material": "^7.1.2",
|
"@mui/icons-material": "^7.1.2",
|
||||||
"@mui/material": "^7.1.2",
|
"@mui/material": "^7.1.2",
|
||||||
|
"@mui/x-date-pickers": "^8.14.0",
|
||||||
"@reduxjs/toolkit": "^2.8.2",
|
"@reduxjs/toolkit": "^2.8.2",
|
||||||
"@types/node": "^16.18.126",
|
"@types/node": "^16.18.126",
|
||||||
"@types/react": "^19.1.8",
|
"@types/react": "^19.1.8",
|
||||||
@@ -23,10 +24,8 @@
|
|||||||
"ky": "^1.8.1",
|
"ky": "^1.8.1",
|
||||||
"moment": "^2.30.1",
|
"moment": "^2.30.1",
|
||||||
"moment-timezone": "^0.5.48",
|
"moment-timezone": "^0.5.48",
|
||||||
"moment": "^2.30.1",
|
|
||||||
"openid-client": "^6.5.3",
|
"openid-client": "^6.5.3",
|
||||||
"react": "^19.1.0",
|
"react": "^19.1.0",
|
||||||
"react-calendar": "^6.0.0",
|
|
||||||
"react-dom": "^19.1.0",
|
"react-dom": "^19.1.0",
|
||||||
"react-i18next": "^13.5.0",
|
"react-i18next": "^13.5.0",
|
||||||
"react-redux": "^9.2.0",
|
"react-redux": "^9.2.0",
|
||||||
|
|||||||
@@ -23,8 +23,9 @@
|
|||||||
|
|
||||||
.sidebar
|
.sidebar
|
||||||
border-right 2px solid #f3f4f6
|
border-right 2px solid #f3f4f6
|
||||||
width 330px
|
width 350px
|
||||||
padding 16px 25px
|
padding-top 16px
|
||||||
|
padding-left 5px
|
||||||
height 90vh
|
height 90vh
|
||||||
flex-direction column
|
flex-direction column
|
||||||
overflow auto
|
overflow auto
|
||||||
@@ -71,32 +72,8 @@
|
|||||||
font-family "Segoe UI", Tahoma, Geneva, Verdana, sans-serif
|
font-family "Segoe UI", Tahoma, Geneva, Verdana, sans-serif
|
||||||
|
|
||||||
/* mini calendar style */
|
/* mini calendar style */
|
||||||
.react-calendar
|
.MuiDayCalendar-weekContainer:has(.selectedWeek)
|
||||||
border none
|
background-color lightgray !important
|
||||||
font-size 14px
|
|
||||||
width 100%
|
|
||||||
user-select none
|
|
||||||
|
|
||||||
/* selected day hover */
|
|
||||||
.react-calendar__tile
|
|
||||||
transition background-color 0.3s ease, color 0.3s ease
|
|
||||||
border none
|
|
||||||
background-color white
|
|
||||||
width 12px
|
|
||||||
height 37.52px
|
|
||||||
|
|
||||||
.react-calendar__tile--active
|
|
||||||
background-color rgb(255, 255, 255)
|
|
||||||
|
|
||||||
.today
|
|
||||||
background orange !important
|
|
||||||
color white
|
|
||||||
|
|
||||||
.selectedWeek
|
|
||||||
background-color lightgrey
|
|
||||||
|
|
||||||
.react-calendar__month-view__days__day--neighboringMonth
|
|
||||||
color gray
|
|
||||||
|
|
||||||
/* sidebar header */
|
/* sidebar header */
|
||||||
.sidebar-calendar h2
|
.sidebar-calendar h2
|
||||||
|
|||||||
@@ -41,6 +41,13 @@ import { EventErrorHandler } from "../Error/EventErrorHandler";
|
|||||||
import { EventErrorSnackbar } from "../Error/ErrorSnackbar";
|
import { EventErrorSnackbar } from "../Error/ErrorSnackbar";
|
||||||
import momentTimezonePlugin from "@fullcalendar/moment-timezone";
|
import momentTimezonePlugin from "@fullcalendar/moment-timezone";
|
||||||
import { TimezoneSelector } from "./TimezoneSelector";
|
import { TimezoneSelector } from "./TimezoneSelector";
|
||||||
|
import { DateCalendar } from "@mui/x-date-pickers/DateCalendar";
|
||||||
|
import { LocalizationProvider } from "@mui/x-date-pickers/LocalizationProvider";
|
||||||
|
import { AdapterMoment } from "@mui/x-date-pickers/AdapterMoment";
|
||||||
|
import moment from "moment";
|
||||||
|
import { DayCalendarSkeleton } from "@mui/x-date-pickers/DayCalendarSkeleton";
|
||||||
|
import { PickersDay } from "@mui/x-date-pickers/PickersDay";
|
||||||
|
import { MiniCalendar } from "./MiniCalendar";
|
||||||
|
|
||||||
interface CalendarAppProps {
|
interface CalendarAppProps {
|
||||||
calendarRef: React.RefObject<CalendarApi | null>;
|
calendarRef: React.RefObject<CalendarApi | null>;
|
||||||
@@ -242,14 +249,6 @@ export default function CalendarApp({
|
|||||||
errorHandler: errorHandler.current,
|
errorHandler: errorHandler.current,
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleMonthUp = () => {
|
|
||||||
eventHandlers.handleMonthUp(selectedMiniDate, setSelectedMiniDate);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleMonthDown = () => {
|
|
||||||
eventHandlers.handleMonthDown(selectedMiniDate, setSelectedMiniDate);
|
|
||||||
};
|
|
||||||
|
|
||||||
if (process.env.NODE_ENV === "test") {
|
if (process.env.NODE_ENV === "test") {
|
||||||
(window as any).__calendarRef = calendarRef;
|
(window as any).__calendarRef = calendarRef;
|
||||||
}
|
}
|
||||||
@@ -265,87 +264,13 @@ export default function CalendarApp({
|
|||||||
>
|
>
|
||||||
<AddIcon /> <p>Create Event</p>
|
<AddIcon /> <p>Create Event</p>
|
||||||
</Button>
|
</Button>
|
||||||
<div className="calendar-label">
|
|
||||||
<div className="calendar-label">
|
|
||||||
<span title="mini calendar month">
|
|
||||||
{selectedMiniDate.toLocaleDateString("en-us", {
|
|
||||||
month: "long",
|
|
||||||
year: "numeric",
|
|
||||||
})}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<button onClick={handleMonthUp}><</button>
|
|
||||||
<button onClick={handleMonthDown}>></button>
|
|
||||||
</div>
|
|
||||||
<ReactCalendar
|
|
||||||
key={selectedMiniDate.toDateString()}
|
|
||||||
calendarType="iso8601"
|
|
||||||
formatShortWeekday={(locale, date) =>
|
|
||||||
date.toLocaleDateString(locale, { weekday: "narrow" })
|
|
||||||
}
|
|
||||||
value={selectedMiniDate}
|
|
||||||
onClickDay={(date) => {
|
|
||||||
setSelectedDate(date);
|
|
||||||
setSelectedMiniDate(date);
|
|
||||||
calendarRef.current?.gotoDate(date);
|
|
||||||
}}
|
|
||||||
prevLabel={null}
|
|
||||||
showNeighboringMonth={true}
|
|
||||||
nextLabel={null}
|
|
||||||
showNavigation={false}
|
|
||||||
tileClassName={({ date }) => {
|
|
||||||
const classNames: string[] = [];
|
|
||||||
|
|
||||||
const today = new Date().setHours(0, 0, 0, 0);
|
<MiniCalendar
|
||||||
if (date.getTime() === today) {
|
calendarRef={calendarRef}
|
||||||
classNames.push("today");
|
selectedDate={selectedMiniDate}
|
||||||
}
|
setSelectedDate={setSelectedDate}
|
||||||
const selected = new Date(selectedDate);
|
setSelectedMiniDate={setSelectedMiniDate}
|
||||||
selected.setHours(0, 0, 0, 0);
|
dottedEvents={dottedEvents}
|
||||||
if (
|
|
||||||
calendarRef.current?.view.type === "timeGridWeek" ||
|
|
||||||
calendarRef.current?.view.type === undefined
|
|
||||||
) {
|
|
||||||
const startOfWeek = computeStartOfTheWeek(selected);
|
|
||||||
|
|
||||||
const endOfWeek = new Date(startOfWeek);
|
|
||||||
endOfWeek.setDate(startOfWeek.getDate() + 6); // Sunday
|
|
||||||
endOfWeek.setHours(23, 59, 59, 999);
|
|
||||||
|
|
||||||
if (date <= endOfWeek && date >= startOfWeek) {
|
|
||||||
classNames.push("selectedWeek");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
calendarRef.current?.view.type === "timeGridDay" &&
|
|
||||||
date.getTime() === selected.getTime()
|
|
||||||
) {
|
|
||||||
classNames.push("selectedWeek");
|
|
||||||
}
|
|
||||||
return classNames;
|
|
||||||
}}
|
|
||||||
tileContent={({ date }) => {
|
|
||||||
const classNames: string[] = [];
|
|
||||||
const hasEvents = dottedEvents.some((event) => {
|
|
||||||
const eventDate = new Date(event.start);
|
|
||||||
return (
|
|
||||||
eventDate.getFullYear() === date.getFullYear() &&
|
|
||||||
eventDate.getMonth() === date.getMonth() &&
|
|
||||||
eventDate.getDate() === date.getDate() &&
|
|
||||||
event.status !== "CANCELLED"
|
|
||||||
);
|
|
||||||
});
|
|
||||||
if (hasEvents) {
|
|
||||||
classNames.push("event-dot");
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className={classNames.join(" ")}
|
|
||||||
data-testid={`date-${date.getFullYear()}-${date.getMonth()}-${date.getDate()}`}
|
|
||||||
></div>
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
<TempCalendarsInput
|
<TempCalendarsInput
|
||||||
setAnchorEl={setAnchorEl}
|
setAnchorEl={setAnchorEl}
|
||||||
|
|||||||
@@ -0,0 +1,146 @@
|
|||||||
|
import { LocalizationProvider } from "@mui/x-date-pickers/LocalizationProvider";
|
||||||
|
import { AdapterMoment } from "@mui/x-date-pickers/AdapterMoment";
|
||||||
|
import { DateCalendar, PickersDay } from "@mui/x-date-pickers";
|
||||||
|
import { DayCalendarSkeleton } from "@mui/x-date-pickers/DayCalendarSkeleton";
|
||||||
|
import moment from "moment";
|
||||||
|
import {
|
||||||
|
computeStartOfTheWeek,
|
||||||
|
formatDateToYYYYMMDDTHHMMSS,
|
||||||
|
getCalendarRange,
|
||||||
|
} from "../../utils/dateUtils";
|
||||||
|
import { useAppDispatch, useAppSelector } from "../../app/hooks";
|
||||||
|
import { refreshCalendars } from "../Event/utils/eventUtils";
|
||||||
|
import { getCalendarDetailAsync } from "../../features/Calendars/CalendarSlice";
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
|
||||||
|
export function MiniCalendar({
|
||||||
|
calendarRef,
|
||||||
|
selectedDate,
|
||||||
|
setSelectedDate,
|
||||||
|
setSelectedMiniDate,
|
||||||
|
dottedEvents,
|
||||||
|
}: {
|
||||||
|
calendarRef: any;
|
||||||
|
selectedDate: Date;
|
||||||
|
setSelectedDate: (d: Date) => void;
|
||||||
|
setSelectedMiniDate: (d: Date) => void;
|
||||||
|
dottedEvents: any[];
|
||||||
|
}) {
|
||||||
|
const dispatch = useAppDispatch();
|
||||||
|
const calendars = useAppSelector((state) => state.calendars);
|
||||||
|
const [visibleDate, setVisibleDate] = useState(selectedDate);
|
||||||
|
|
||||||
|
useEffect(() => setVisibleDate(selectedDate), [selectedDate]);
|
||||||
|
return (
|
||||||
|
<LocalizationProvider dateAdapter={AdapterMoment} adapterLocale="en-gb">
|
||||||
|
<DateCalendar
|
||||||
|
value={moment(visibleDate)}
|
||||||
|
onChange={(dateMoment) => {
|
||||||
|
if (!dateMoment) return;
|
||||||
|
const date = dateMoment.toDate();
|
||||||
|
setSelectedDate(date);
|
||||||
|
setSelectedMiniDate(date);
|
||||||
|
calendarRef.current?.gotoDate(date);
|
||||||
|
}}
|
||||||
|
showDaysOutsideCurrentMonth
|
||||||
|
onMonthChange={(month) => {
|
||||||
|
const calendarRange = getCalendarRange(month.toDate());
|
||||||
|
setVisibleDate(month.toDate());
|
||||||
|
Object.values(calendars.list).forEach((cal) =>
|
||||||
|
dispatch(
|
||||||
|
getCalendarDetailAsync({
|
||||||
|
calId: cal.id,
|
||||||
|
match: {
|
||||||
|
start: formatDateToYYYYMMDDTHHMMSS(calendarRange.start),
|
||||||
|
end: formatDateToYYYYMMDDTHHMMSS(calendarRange.end),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
views={["month", "day"]}
|
||||||
|
slotProps={{
|
||||||
|
day: (ownerState) => {
|
||||||
|
const date = ownerState.day.toDate();
|
||||||
|
const today = new Date();
|
||||||
|
today.setHours(0, 0, 0, 0);
|
||||||
|
const selected = new Date(selectedDate);
|
||||||
|
selected.setHours(0, 0, 0, 0);
|
||||||
|
|
||||||
|
const isToday = date.getTime() === today.getTime();
|
||||||
|
const isSelectedDay =
|
||||||
|
calendarRef.current?.view.type === "timeGridDay" &&
|
||||||
|
date.getTime() === selected.getTime();
|
||||||
|
|
||||||
|
const isInSelectedWeek =
|
||||||
|
calendarRef.current?.view.type === "timeGridWeek" ||
|
||||||
|
calendarRef.current?.view.type === undefined
|
||||||
|
? (() => {
|
||||||
|
const startOfWeek = computeStartOfTheWeek(selected);
|
||||||
|
const endOfWeek = new Date(startOfWeek);
|
||||||
|
endOfWeek.setDate(startOfWeek.getDate() + 6);
|
||||||
|
endOfWeek.setHours(23, 59, 59, 999);
|
||||||
|
return date >= startOfWeek && date <= endOfWeek;
|
||||||
|
})()
|
||||||
|
: false;
|
||||||
|
|
||||||
|
const hasEvents = dottedEvents.some((event) => {
|
||||||
|
const eventDate = new Date(event.start);
|
||||||
|
return (
|
||||||
|
eventDate.getFullYear() === date.getFullYear() &&
|
||||||
|
eventDate.getMonth() === date.getMonth() &&
|
||||||
|
eventDate.getDate() === date.getDate() &&
|
||||||
|
event.status !== "CANCELLED"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
const classNames = [
|
||||||
|
isToday ? "today" : "",
|
||||||
|
isSelectedDay ? "selectedDay" : "",
|
||||||
|
isInSelectedWeek ? "selectedWeek" : "",
|
||||||
|
hasEvents ? "event-dot" : "",
|
||||||
|
].join(" ");
|
||||||
|
|
||||||
|
return {
|
||||||
|
className: classNames,
|
||||||
|
selected: classNames.includes("selectedWeek"),
|
||||||
|
outsideCurrentMonth: ownerState.isDayOutsideMonth,
|
||||||
|
disableMargin: false,
|
||||||
|
onClick: () => {
|
||||||
|
setSelectedDate(date);
|
||||||
|
setSelectedMiniDate(date);
|
||||||
|
calendarRef.current?.gotoDate(date);
|
||||||
|
},
|
||||||
|
style: {
|
||||||
|
backgroundColor: "transparent",
|
||||||
|
position: "relative",
|
||||||
|
flexDirection: "column",
|
||||||
|
border: 0,
|
||||||
|
},
|
||||||
|
sx: {
|
||||||
|
"&.Mui-selected": {
|
||||||
|
color: "inherit !important",
|
||||||
|
fontWeight: "inherit !important",
|
||||||
|
},
|
||||||
|
"&.selectedDay": {
|
||||||
|
backgroundColor: "lightgray !important",
|
||||||
|
},
|
||||||
|
"&.today": {
|
||||||
|
background: "orange !important",
|
||||||
|
color: "white !important",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"data-testid": `date-${date.getFullYear()}-${date.getMonth()}-${date.getDate()}`,
|
||||||
|
children: (
|
||||||
|
<>
|
||||||
|
{ownerState.day.date()}
|
||||||
|
{hasEvents && <div className="event-dot" />}
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</LocalizationProvider>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -89,24 +89,6 @@ export const createEventHandlers = (props: EventHandlersProps) => {
|
|||||||
setOpenEventDisplay(false);
|
setOpenEventDisplay(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleMonthUp = (
|
|
||||||
selectedMiniDate: Date,
|
|
||||||
setSelectedMiniDate: (date: Date) => void
|
|
||||||
) => {
|
|
||||||
setSelectedMiniDate(
|
|
||||||
new Date(selectedMiniDate.getFullYear(), selectedMiniDate.getMonth() - 1)
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleMonthDown = (
|
|
||||||
selectedMiniDate: Date,
|
|
||||||
setSelectedMiniDate: (date: Date) => void
|
|
||||||
) => {
|
|
||||||
setSelectedMiniDate(
|
|
||||||
new Date(selectedMiniDate.getFullYear(), selectedMiniDate.getMonth() + 1)
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleEventClick = (info: any) => {
|
const handleEventClick = (info: any) => {
|
||||||
info.jsEvent.preventDefault();
|
info.jsEvent.preventDefault();
|
||||||
|
|
||||||
@@ -255,8 +237,6 @@ export const createEventHandlers = (props: EventHandlersProps) => {
|
|||||||
handleDateSelect,
|
handleDateSelect,
|
||||||
handleClosePopover,
|
handleClosePopover,
|
||||||
handleCloseEventDisplay,
|
handleCloseEventDisplay,
|
||||||
handleMonthUp,
|
|
||||||
handleMonthDown,
|
|
||||||
handleEventClick,
|
handleEventClick,
|
||||||
handleEventAllow,
|
handleEventAllow,
|
||||||
handleEventDrop,
|
handleEventDrop,
|
||||||
|
|||||||
@@ -25,8 +25,6 @@ export const useCalendarEventHandlers = (props: EventHandlersProps) => {
|
|||||||
eventHandlers.handleCloseEventDisplay,
|
eventHandlers.handleCloseEventDisplay,
|
||||||
[props.setOpenEventDisplay]
|
[props.setOpenEventDisplay]
|
||||||
),
|
),
|
||||||
handleMonthUp: useCallback(eventHandlers.handleMonthUp, []),
|
|
||||||
handleMonthDown: useCallback(eventHandlers.handleMonthDown, []),
|
|
||||||
handleEventClick: useCallback(eventHandlers.handleEventClick, [
|
handleEventClick: useCallback(eventHandlers.handleEventClick, [
|
||||||
props.setOpenEventDisplay,
|
props.setOpenEventDisplay,
|
||||||
props.setEventDisplayedId,
|
props.setEventDisplayedId,
|
||||||
|
|||||||
Reference in New Issue
Block a user