diff --git a/Jenkinsfile b/Jenkinsfile index c5a436d..d10cdcb 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -26,6 +26,11 @@ pipeline { sh 'npm run test' } } + stage('Check Formatting') { + steps { + sh 'npx prettier --check .' + } + } stage('Deploy docker images') { when { anyOf { diff --git a/README.md b/README.md index a6babdb..709d8bd 100644 --- a/README.md +++ b/README.md @@ -8,11 +8,20 @@ This project aims at service a Single Page Application allowing a user to intera This frontend-only application will interact with: - - [esn-sabre](https://github.com/linagora/esn-sabre/) CalDAV + CardDAV server, tailor made for LINAGORA needs. - - [Twake Calendar side service](https://github.com/linagora/twake-calendar-side-service) that delivers additional backend features for Sabre. +- [esn-sabre](https://github.com/linagora/esn-sabre/) CalDAV + CardDAV server, tailor made for LINAGORA needs. +- [Twake Calendar side service](https://github.com/linagora/twake-calendar-side-service) that delivers additional backend features for Sabre. It is meant as a drop in replacement of [esn-frontend-calendar](https://github.com/linagora/esn-frontend-calendar). +## Contributing + +### Formating + +We use [Prettier](https://prettier.io/) to keep code style consistent. +A `.prettierrc` file is already included in the repo, so formatting rules are predefined. + +Before committing, make sure you format your files either using your IDE Prettier extension or Prettier CLI. + ## Running it Requirement: node 24+ @@ -77,7 +86,7 @@ And then visit [https://localhost:5000](https://localhost:5000). ### App grid -An applist is configurable in the public folder to setup the grid of app accessible within Twake Calendar. +An applist is configurable in the public folder to setup the grid of app accessible within Twake Calendar. Each app has three fields: @@ -89,7 +98,11 @@ Example: ```js var appList = [ - { name: "My App", icon: "https://myapp.com/myapp.png", link: "https://myapp.com" }, + { + name: "My App", + icon: "https://myapp.com/myapp.png", + link: "https://myapp.com", + }, ]; ``` diff --git a/__test__/components/EventModifications.test.tsx b/__test__/components/EventModifications.test.tsx index 8b8eda0..f8a8825 100644 --- a/__test__/components/EventModifications.test.tsx +++ b/__test__/components/EventModifications.test.tsx @@ -111,7 +111,7 @@ describe("CalendarApp integration", () => { openpaasId: "667037022b752d0026472254", }, tokens: { - accessToken: "token" + accessToken: "token", }, }, calendars: { @@ -133,14 +133,16 @@ describe("CalendarApp integration", () => { cn: "Alice", cal_address: "alice@example.com", }, - attendee: [{ - cn: "Alice", - partstat: "ACCEPTED", - rsvp: "TRUE", - role: "REQ-PARTICIPANT", - cutype: "INDIVIDUAL", - cal_address: "alice@example.com", - }, ], + attendee: [ + { + cn: "Alice", + partstat: "ACCEPTED", + rsvp: "TRUE", + role: "REQ-PARTICIPANT", + cutype: "INDIVIDUAL", + cal_address: "alice@example.com", + }, + ], ...eventProps, }, }, diff --git a/__test__/components/MiniCalendarColor.test.tsx b/__test__/components/MiniCalendarColor.test.tsx index 3a2daee..97bb000 100644 --- a/__test__/components/MiniCalendarColor.test.tsx +++ b/__test__/components/MiniCalendarColor.test.tsx @@ -57,33 +57,34 @@ describe("MiniCalendar", () => { }); it.each([ - { today: new Date(2025, 8, 1), label: "Monday 1 Sept 2025" }, - { today: new Date(2025, 8, 3), label: "Wednesday 3 Sept 2025" }, - { today: new Date(2025, 8, 7), label: "Sunday 7 Sept 2025" }, + { today: new Date(2025, 8, 1), label: "Monday 1 Sept 2025" }, + { today: new Date(2025, 8, 3), label: "Wednesday 3 Sept 2025" }, + { today: new Date(2025, 8, 7), label: "Sunday 7 Sept 2025" }, ])( - "renders mini calendar with the week in gray (except for today) when today is $label", - ({ today }) => { - jest.useFakeTimers(); - jest.setSystemTime(today); + "renders mini calendar with the week in gray (except for today) when today is $label", + ({ today }) => { + jest.useFakeTimers(); + jest.setSystemTime(today); - renderCalendar(); + renderCalendar(); - const monday = new Date(2025, 8, 1); // Monday Sept 1 + const monday = new Date(2025, 8, 1); // Monday Sept 1 - for (let i = 0; i < 7; i++) { - const date = new Date(monday); - date.setDate(monday.getDate() + i); - const dateTestId = `date-${date.getFullYear()}-${date.getMonth()}-${date.getDate()}`; - - const tile = screen.getByTestId(dateTestId); + for (let i = 0; i < 7; i++) { + const date = new Date(monday); + date.setDate(monday.getDate() + i); + const dateTestId = `date-${date.getFullYear()}-${date.getMonth()}-${date.getDate()}`; - if (date.getTime() !== today.setHours(0, 0, 0, 0)) { - expect(tile?.parentElement).toHaveClass("selectedWeek"); + const tile = screen.getByTestId(dateTestId); + + if (date.getTime() !== today.setHours(0, 0, 0, 0)) { + expect(tile?.parentElement).toHaveClass("selectedWeek"); + } } - } - jest.useRealTimers(); - }); + jest.useRealTimers(); + } + ); it("renders mini calendar with the day in gray (except for today) when full calendar in day view", async () => { renderCalendar(); diff --git a/__test__/features/Events/EventDisplay.test.tsx b/__test__/features/Events/EventDisplay.test.tsx index 0fee032..d857a0d 100644 --- a/__test__/features/Events/EventDisplay.test.tsx +++ b/__test__/features/Events/EventDisplay.test.tsx @@ -95,15 +95,13 @@ describe("Event Preview Display", () => { }; it("renders correctly event data", () => { - jest - .spyOn(Date.prototype, "toLocaleString") - .mockImplementation(function ( - this: Date, - locales?: Intl.LocalesArgument, - options?: Intl.DateTimeFormatOptions | undefined - ): string { - return RealDateToLocaleString.call(this, "en-UK", options); - }); + jest.spyOn(Date.prototype, "toLocaleString").mockImplementation(function ( + this: Date, + locales?: Intl.LocalesArgument, + options?: Intl.DateTimeFormatOptions | undefined + ): string { + return RealDateToLocaleString.call(this, "en-UK", options); + }); renderWithProviders( + diff --git a/src/Intl.d.ts b/src/Intl.d.ts index 914990e..c5edc51 100644 --- a/src/Intl.d.ts +++ b/src/Intl.d.ts @@ -1,5 +1,11 @@ declare namespace Intl { - type Key = 'calendar' | 'collation' | 'currency' | 'numberingSystem' | 'timeZone' | 'unit'; + type Key = + | "calendar" + | "collation" + | "currency" + | "numberingSystem" + | "timeZone" + | "unit"; function supportedValuesOf(input: Key): string[]; -} \ No newline at end of file +} diff --git a/src/app/hooks.ts b/src/app/hooks.ts index f6736a7..964f36d 100644 --- a/src/app/hooks.ts +++ b/src/app/hooks.ts @@ -1,5 +1,5 @@ -import { useDispatch, useSelector } from 'react-redux' -import type { RootState, AppDispatch } from './store' +import { useDispatch, useSelector } from "react-redux"; +import type { RootState, AppDispatch } from "./store"; -export const useAppDispatch = useDispatch.withTypes() -export const useAppSelector = useSelector.withTypes() \ No newline at end of file +export const useAppDispatch = useDispatch.withTypes(); +export const useAppSelector = useSelector.withTypes(); diff --git a/src/components/Calendar/Calendar.css b/src/components/Calendar/Calendar.css index 998ca87..13e7531 100644 --- a/src/components/Calendar/Calendar.css +++ b/src/components/Calendar/Calendar.css @@ -133,7 +133,9 @@ main { /* selected day hover */ .react-calendar__tile { - transition: background-color 0.3s ease, color 0.3s ease; + transition: + background-color 0.3s ease, + color 0.3s ease; border: none; background-color: white; width: 12px; diff --git a/src/components/Calendar/Calendar.tsx b/src/components/Calendar/Calendar.tsx index 7011f89..a3edbbb 100644 --- a/src/components/Calendar/Calendar.tsx +++ b/src/components/Calendar/Calendar.tsx @@ -31,13 +31,13 @@ import { createSelector } from "@reduxjs/toolkit"; import HelpOutlineIcon from "@mui/icons-material/HelpOutline"; import ClearIcon from "@mui/icons-material/Clear"; import AccessTimeIcon from "@mui/icons-material/AccessTime"; -import LockIcon from '@mui/icons-material/Lock'; +import LockIcon from "@mui/icons-material/Lock"; import { userAttendee } from "../../features/User/userDataTypes"; const computeStartOfTheWeek = (date: Date): Date => { const startOfWeek = new Date(date); startOfWeek.setDate(date.getDate() - ((date.getDay() + 6) % 7)); // Monday - startOfWeek.setHours(0, 0, 0, 0); + startOfWeek.setHours(0, 0, 0, 0); return startOfWeek; }; @@ -204,7 +204,6 @@ export default function CalendarApp() { calendarRef.current?.view.type === "timeGridWeek" || calendarRef.current?.view.type === undefined ) { - const startOfWeek = computeStartOfTheWeek(selected); const endOfWeek = new Date(startOfWeek); @@ -430,7 +429,9 @@ export default function CalendarApp() { if (!calendars[arg.event._def.extendedProps.calId]) return; const attendees = event._def.extendedProps.attendee || []; - const isPrivate = event._def.extendedProps.class === "PRIVATE" || event._def.extendedProps.class === "CONFIDENTIAL"; + const isPrivate = + event._def.extendedProps.class === "PRIVATE" || + event._def.extendedProps.class === "CONFIDENTIAL"; let Icon = null; let titleStyle: React.CSSProperties = {}; const ownerEmails = new Set( @@ -461,9 +462,17 @@ export default function CalendarApp() { } return ( -
- {isPrivate && } - {Icon && } +
+ {isPrivate && ( + + )} + {Icon && ( + + )} {event.title}
); diff --git a/src/features/Calendars/CalendarModal.tsx b/src/features/Calendars/CalendarModal.tsx index a87e9de..10c7360 100644 --- a/src/features/Calendars/CalendarModal.tsx +++ b/src/features/Calendars/CalendarModal.tsx @@ -28,7 +28,6 @@ function CalendarPopover({ const [timeZone, setTimeZone] = useState(""); const timezones = Intl.supportedValuesOf?.("timeZone") ?? []; const handleSave = () => { - dispatch(createCalendar({ name, description, color })); onClose({}, "backdropClick"); @@ -64,7 +63,11 @@ function CalendarPopover({ }} > - + Create a Calendar { - if (onPerfEntry && onPerfEntry instanceof Function) { - import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { - getCLS(onPerfEntry); - getFID(onPerfEntry); - getFCP(onPerfEntry); - getLCP(onPerfEntry); - getTTFB(onPerfEntry); - }); - } -}; - -export default reportWebVitals;