From b98cfcfeb90e1e2ffde08923514937ae9f8a79bd Mon Sep 17 00:00:00 2001 From: adam-skowronek Date: Fri, 30 Dec 2022 21:39:58 +0100 Subject: [PATCH] Replace luxon with dayjs --- frontend/package-lock.json | 38 +- frontend/package.json | 3 +- frontend/src/App.tsx | 4 + frontend/src/utils/dayjsLocalizer.js | 409 ++++++++++++++++++ .../coordinator/AvailabilitySchedule.tsx | 16 +- .../src/views/coordinator/EditSchedule.tsx | 6 +- frontend/src/views/coordinator/Schedule.tsx | 34 +- .../src/views/student/ScheduleAddGroup.tsx | 7 +- .../src/views/student/StudentSchedule.tsx | 15 +- .../views/supervisor/SupervisorSchedule.tsx | 29 +- 10 files changed, 479 insertions(+), 82 deletions(-) create mode 100644 frontend/src/utils/dayjsLocalizer.js diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 8ba7c30..1aa6d6b 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -18,7 +18,7 @@ "axios": "^0.27.2", "classnames": "^2.3.1", "daisyui": "^2.15.2", - "luxon": "^3.0.4", + "dayjs": "^1.11.7", "react": "^18.1.0", "react-big-calendar": "^1.5.0", "react-date-picker": "^9.1.0", @@ -34,7 +34,6 @@ "web-vitals": "^2.1.4" }, "devDependencies": { - "@types/luxon": "^3.0.2", "@types/react-big-calendar": "^0.38.2", "@types/react-modal": "^3.13.1", "autoprefixer": "^10.4.7", @@ -3823,12 +3822,6 @@ "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==" }, - "node_modules/@types/luxon": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.0.2.tgz", - "integrity": "sha512-HM2OVWckUMmXbWYZufmWT2XMURGDZ6XbyNyQ+Lx+gCFGFqbZaIjsz7b+AGeGP/AuVYHBiuGY+wXfweP1RremnA==", - "dev": true - }, "node_modules/@types/mime": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", @@ -6310,6 +6303,11 @@ "resolved": "https://registry.npmjs.org/date-arithmetic/-/date-arithmetic-4.1.0.tgz", "integrity": "sha512-QWxYLR5P/6GStZcdem+V1xoto6DMadYWpMXU82ES3/RfR3Wdwr3D0+be7mgOJ+Ov0G9D5Dmb9T17sNLQYj9XOg==" }, + "node_modules/dayjs": { + "version": "1.11.7", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.7.tgz", + "integrity": "sha512-+Yw9U6YO5TQohxLcIkrXBeY73WP3ejHWVvx8XCk3gxvQDCTEmS48ZrSZCKciI7Bhl/uCMyxYtE9UqRILmFphkQ==" + }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -11565,14 +11563,6 @@ "node": ">=10" } }, - "node_modules/luxon": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.0.4.tgz", - "integrity": "sha512-aV48rGUwP/Vydn8HT+5cdr26YYQiUZ42NM6ToMoaGKwYfWbfLeRkEu1wXWMHBZT6+KyLfcbbtVcoQFCbbPjKlw==", - "engines": { - "node": ">=12" - } - }, "node_modules/lz-string": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.4.4.tgz", @@ -19744,12 +19734,6 @@ "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==" }, - "@types/luxon": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.0.2.tgz", - "integrity": "sha512-HM2OVWckUMmXbWYZufmWT2XMURGDZ6XbyNyQ+Lx+gCFGFqbZaIjsz7b+AGeGP/AuVYHBiuGY+wXfweP1RremnA==", - "dev": true - }, "@types/mime": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", @@ -21612,6 +21596,11 @@ "resolved": "https://registry.npmjs.org/date-arithmetic/-/date-arithmetic-4.1.0.tgz", "integrity": "sha512-QWxYLR5P/6GStZcdem+V1xoto6DMadYWpMXU82ES3/RfR3Wdwr3D0+be7mgOJ+Ov0G9D5Dmb9T17sNLQYj9XOg==" }, + "dayjs": { + "version": "1.11.7", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.7.tgz", + "integrity": "sha512-+Yw9U6YO5TQohxLcIkrXBeY73WP3ejHWVvx8XCk3gxvQDCTEmS48ZrSZCKciI7Bhl/uCMyxYtE9UqRILmFphkQ==" + }, "debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -25438,11 +25427,6 @@ "yallist": "^4.0.0" } }, - "luxon": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.0.4.tgz", - "integrity": "sha512-aV48rGUwP/Vydn8HT+5cdr26YYQiUZ42NM6ToMoaGKwYfWbfLeRkEu1wXWMHBZT6+KyLfcbbtVcoQFCbbPjKlw==" - }, "lz-string": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.4.4.tgz", diff --git a/frontend/package.json b/frontend/package.json index 3bc328d..bc6bc78 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -13,7 +13,7 @@ "axios": "^0.27.2", "classnames": "^2.3.1", "daisyui": "^2.15.2", - "luxon": "^3.0.4", + "dayjs": "^1.11.7", "react": "^18.1.0", "react-big-calendar": "^1.5.0", "react-date-picker": "^9.1.0", @@ -53,7 +53,6 @@ ] }, "devDependencies": { - "@types/luxon": "^3.0.2", "@types/react-big-calendar": "^0.38.2", "@types/react-modal": "^3.13.1", "autoprefixer": "^10.4.7", diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index cf024cd..208c869 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -26,6 +26,10 @@ import SupervisorAvailabilities from './views/coordinator/SupervisorAvailabiliti import AvailabilitySchedule from './views/coordinator/AvailabilitySchedule' import GradeCard from './views/GradeCard' import Group from './views/coordinator/Group' +import dayjs from 'dayjs' + +require('dayjs/locale/pl') +dayjs.locale('pl') const queryClient = new QueryClient({ defaultOptions: { diff --git a/frontend/src/utils/dayjsLocalizer.js b/frontend/src/utils/dayjsLocalizer.js new file mode 100644 index 0000000..212c92e --- /dev/null +++ b/frontend/src/utils/dayjsLocalizer.js @@ -0,0 +1,409 @@ +import { DateLocalizer } from 'react-big-calendar' + +// import dayjs plugins +// Note that the timezone plugin is not imported here +// this plugin can be optionally loaded by the user +import isBetween from 'dayjs/plugin/isBetween' +import isSameOrAfter from 'dayjs/plugin/isSameOrAfter' +import isSameOrBefore from 'dayjs/plugin/isSameOrBefore' +import localeData from 'dayjs/plugin/localeData' +import localizedFormat from 'dayjs/plugin/localizedFormat' +import minMax from 'dayjs/plugin/minMax' +import utc from 'dayjs/plugin/utc' + +const weekRangeFormat = ({ start, end }, culture, local) => + local.format(start, 'MMMM DD', culture) + + ' – ' + + // updated to use this localizer 'eq()' method + local.format(end, local.eq(start, end, 'month') ? 'DD' : 'MMMM DD', culture) + +const dateRangeFormat = ({ start, end }, culture, local) => + local.format(start, 'L', culture) + ' – ' + local.format(end, 'L', culture) + +const timeRangeFormat = ({ start, end }, culture, local) => + local.format(start, 'LT', culture) + ' – ' + local.format(end, 'LT', culture) + +const timeRangeStartFormat = ({ start }, culture, local) => + local.format(start, 'LT', culture) + ' – ' + +const timeRangeEndFormat = ({ end }, culture, local) => + ' – ' + local.format(end, 'LT', culture) + +export const formats = { + dateFormat: 'DD', + dayFormat: 'DD ddd', + weekdayFormat: 'ddd', + + selectRangeFormat: timeRangeFormat, + eventTimeRangeFormat: timeRangeFormat, + eventTimeRangeStartFormat: timeRangeStartFormat, + eventTimeRangeEndFormat: timeRangeEndFormat, + + timeGutterFormat: 'LT', + + monthHeaderFormat: 'MMMM YYYY', + dayHeaderFormat: 'dddd MMM DD', + dayRangeHeaderFormat: weekRangeFormat, + agendaHeaderFormat: dateRangeFormat, + + agendaDateFormat: 'ddd MMM DD', + agendaTimeFormat: 'LT', + agendaTimeRangeFormat: timeRangeFormat, +} + +function fixUnit(unit) { + let datePart = unit ? unit.toLowerCase() : unit + if (datePart === 'FullYear') { + datePart = 'year' + } else if (!datePart) { + datePart = undefined + } + return datePart +} + +export default function (dayjsLib) { + // load dayjs plugins + dayjsLib.extend(isBetween) + dayjsLib.extend(isSameOrAfter) + dayjsLib.extend(isSameOrBefore) + dayjsLib.extend(localeData) + dayjsLib.extend(localizedFormat) + dayjsLib.extend(minMax) + dayjsLib.extend(utc) + + const locale = (dj, c) => (c ? dj.locale(c) : dj) + + // if the timezone plugin is loaded, + // then use the timezone aware version + const dayjs = dayjsLib.tz ? dayjsLib.tz : dayjsLib + + function getTimezoneOffset(date) { + // ensures this gets cast to timezone + return dayjs(date).toDate().getTimezoneOffset() + } + + function getDstOffset(start, end) { + // convert to dayjs, in case + const st = dayjs(start) + const ed = dayjs(end) + // if not using the dayjs timezone plugin + if (!dayjs.tz) { + return st.toDate().getTimezoneOffset() - ed.toDate().getTimezoneOffset() + } + /** + * If a default timezone has been applied, then + * use this to get the proper timezone offset, otherwise default + * the timezone to the browser local + */ + const tzName = st.tz().$x.$timezone ?? dayjsLib.tz.guess() + // invert offsets to be inline with moment.js + const startOffset = -dayjs.tz(+st, tzName).utcOffset() + const endOffset = -dayjs.tz(+ed, tzName).utcOffset() + return startOffset - endOffset + } + + function getDayStartDstOffset(start) { + const dayStart = dayjs(start).startOf('day') + return getDstOffset(dayStart, start) + } + + /*** BEGIN localized date arithmetic methods with dayjs ***/ + function defineComparators(a, b, unit) { + const datePart = fixUnit(unit) + const dtA = datePart ? dayjs(a).startOf(datePart) : dayjs(a) + const dtB = datePart ? dayjs(b).startOf(datePart) : dayjs(b) + return [dtA, dtB, datePart] + } + + function startOf(date = null, unit) { + const datePart = fixUnit(unit) + if (datePart) { + return dayjs(date).startOf(datePart).toDate() + } + return dayjs(date).toDate() + } + + function endOf(date = null, unit) { + const datePart = fixUnit(unit) + if (datePart) { + return dayjs(date).endOf(datePart).toDate() + } + return dayjs(date).toDate() + } + + // dayjs comparison operations *always* convert both sides to dayjs objects + // prior to running the comparisons + function eq(a, b, unit) { + const [dtA, dtB, datePart] = defineComparators(a, b, unit) + return dtA.isSame(dtB, datePart) + } + + function neq(a, b, unit) { + return !eq(a, b, unit) + } + + function gt(a, b, unit) { + const [dtA, dtB, datePart] = defineComparators(a, b, unit) + return dtA.isAfter(dtB, datePart) + } + + function lt(a, b, unit) { + const [dtA, dtB, datePart] = defineComparators(a, b, unit) + return dtA.isBefore(dtB, datePart) + } + + function gte(a, b, unit) { + const [dtA, dtB, datePart] = defineComparators(a, b, unit) + return dtA.isSameOrBefore(dtB, datePart) + } + + function lte(a, b, unit) { + const [dtA, dtB, datePart] = defineComparators(a, b, unit) + return dtA.isSameOrBefore(dtB, datePart) + } + + function inRange(day, min, max, unit = 'day') { + const datePart = fixUnit(unit) + const djDay = dayjs(day) + const djMin = dayjs(min) + const djMax = dayjs(max) + return djDay.isBetween(djMin, djMax, datePart, '[]') + } + + function min(dateA, dateB) { + const dtA = dayjs(dateA) + const dtB = dayjs(dateB) + const minDt = dayjsLib.min(dtA, dtB) + return minDt.toDate() + } + + function max(dateA, dateB) { + const dtA = dayjs(dateA) + const dtB = dayjs(dateB) + const maxDt = dayjsLib.max(dtA, dtB) + return maxDt.toDate() + } + + function merge(date, time) { + if (!date && !time) return null + + const tm = dayjs(time).format('HH:mm:ss') + const dt = dayjs(date).startOf('day').format('MM/DD/YYYY') + // We do it this way to avoid issues when timezone switching + return dayjsLib(`${dt} ${tm}`, 'MM/DD/YYYY HH:mm:ss').toDate() + } + + function add(date, adder, unit) { + const datePart = fixUnit(unit) + return dayjs(date).add(adder, datePart).toDate() + } + + function range(start, end, unit = 'day') { + const datePart = fixUnit(unit) + // because the add method will put these in tz, we have to start that way + let current = dayjs(start).toDate() + const days = [] + + while (lte(current, end)) { + days.push(current) + current = add(current, 1, datePart) + } + + return days + } + + function ceil(date, unit) { + const datePart = fixUnit(unit) + const floor = startOf(date, datePart) + + return eq(floor, date) ? floor : add(floor, 1, datePart) + } + + function diff(a, b, unit = 'day') { + const datePart = fixUnit(unit) + // don't use 'defineComparators' here, as we don't want to mutate the values + const dtA = dayjs(a) + const dtB = dayjs(b) + return dtB.diff(dtA, datePart) + } + + function minutes(date) { + const dt = dayjs(date) + return dt.minutes() + } + + function firstOfWeek(culture) { + const data = culture ? dayjsLib.localeData(culture) : dayjsLib.localeData() + return data ? data.firstDayOfWeek() : 0 + } + + function firstVisibleDay(date) { + return dayjs(date).startOf('month').startOf('week').toDate() + } + + function lastVisibleDay(date) { + return dayjs(date).endOf('month').endOf('week').toDate() + } + + function visibleDays(date) { + let current = firstVisibleDay(date) + const last = lastVisibleDay(date) + const days = [] + + while (lte(current, last)) { + days.push(current) + current = add(current, 1, 'd') + } + + return days + } + /*** END localized date arithmetic methods with dayjs ***/ + + /** + * Moved from TimeSlots.js, this method overrides the method of the same name + * in the localizer.js, using dayjs to construct the js Date + * @param {Date} dt - date to start with + * @param {Number} minutesFromMidnight + * @param {Number} offset + * @returns {Date} + */ + function getSlotDate(dt, minutesFromMidnight, offset) { + return dayjs(dt) + .startOf('day') + .minute(minutesFromMidnight + offset) + .toDate() + } + + // dayjs will automatically handle DST differences in it's calculations + function getTotalMin(start, end) { + return diff(start, end, 'minutes') + } + + function getMinutesFromMidnight(start) { + const dayStart = dayjs(start).startOf('day') + const day = dayjs(start) + return day.diff(dayStart, 'minutes') + getDayStartDstOffset(start) + } + + // These two are used by DateSlotMetrics + function continuesPrior(start, first) { + const djStart = dayjs(start) + const djFirst = dayjs(first) + return djStart.isBefore(djFirst, 'day') + } + + function continuesAfter(start, end, last) { + const djEnd = dayjs(end) + const djLast = dayjs(last) + return djEnd.isSameOrAfter(djLast, 'minutes') + } + + // These two are used by eventLevels + function sortEvents({ + evtA: { start: aStart, end: aEnd, allDay: aAllDay }, + evtB: { start: bStart, end: bEnd, allDay: bAllDay }, + }) { + const startSort = +startOf(aStart, 'day') - +startOf(bStart, 'day') + + const durA = diff(aStart, ceil(aEnd, 'day'), 'day') + + const durB = diff(bStart, ceil(bEnd, 'day'), 'day') + + return ( + startSort || // sort by start Day first + Math.max(durB, 1) - Math.max(durA, 1) || // events spanning multiple days go first + !!bAllDay - !!aAllDay || // then allDay single day events + +aStart - +bStart || // then sort by start time *don't need dayjs conversion here + +aEnd - +bEnd // then sort by end time *don't need dayjs conversion here either + ) + } + + function inEventRange({ + event: { start, end }, + range: { start: rangeStart, end: rangeEnd }, + }) { + const startOfDay = dayjs(start).startOf('day') + const eEnd = dayjs(end) + const rStart = dayjs(rangeStart) + const rEnd = dayjs(rangeEnd) + + const startsBeforeEnd = startOfDay.isSameOrBefore(rEnd, 'day') + // when the event is zero duration we need to handle a bit differently + const sameMin = !startOfDay.isSame(eEnd, 'minutes') + const endsAfterStart = sameMin + ? eEnd.isAfter(rStart, 'minutes') + : eEnd.isSameOrAfter(rStart, 'minutes') + + return startsBeforeEnd && endsAfterStart + } + + function isSameDate(date1, date2) { + const dt = dayjs(date1) + const dt2 = dayjs(date2) + return dt.isSame(dt2, 'day') + } + + /** + * This method, called once in the localizer constructor, is used by eventLevels + * 'eventSegments()' to assist in determining the 'span' of the event in the display, + * specifically when using a timezone that is greater than the browser native timezone. + * @returns number + */ + function browserTZOffset() { + /** + * Date.prototype.getTimezoneOffset horrifically flips the positive/negative from + * what you see in it's string, so we have to jump through some hoops to get a value + * we can actually compare. + */ + const dt = new Date() + const neg = /-/.test(dt.toString()) ? '-' : '' + const dtOffset = dt.getTimezoneOffset() + const comparator = Number(`${neg}${Math.abs(dtOffset)}`) + // dayjs correctly provides positive/negative offset, as expected + const mtOffset = dayjs().utcOffset() + return mtOffset > comparator ? 1 : 0 + } + + return new DateLocalizer({ + formats, + + firstOfWeek, + firstVisibleDay, + lastVisibleDay, + visibleDays, + + format(value, format, culture) { + return locale(dayjs(value), culture).format(format) + }, + + lt, + lte, + gt, + gte, + eq, + neq, + merge, + inRange, + startOf, + endOf, + range, + add, + diff, + ceil, + min, + max, + minutes, + + getSlotDate, + getTimezoneOffset, + getDstOffset, + getTotalMin, + getMinutesFromMidnight, + continuesPrior, + continuesAfter, + sortEvents, + inEventRange, + isSameDate, + browserTZOffset, + }) +} diff --git a/frontend/src/views/coordinator/AvailabilitySchedule.tsx b/frontend/src/views/coordinator/AvailabilitySchedule.tsx index 75dfbe3..99593bc 100644 --- a/frontend/src/views/coordinator/AvailabilitySchedule.tsx +++ b/frontend/src/views/coordinator/AvailabilitySchedule.tsx @@ -1,5 +1,4 @@ -import { Calendar, luxonLocalizer, Views } from 'react-big-calendar' -import { DateTime, Settings } from 'luxon' +import { Calendar, Views } from 'react-big-calendar' import { useCallback, useState } from 'react' import { useMutation, useQuery } from 'react-query' import { useParams } from 'react-router-dom' @@ -9,11 +8,12 @@ import { generateTermsOfDefence, getAvailabilityForCoordinator, } from '../../api/schedule' +import dayjs from 'dayjs' +import dayjsLocalizer from '../../utils/dayjsLocalizer' + +const localizer = dayjsLocalizer(dayjs) const SupervisorSchedule = () => { - Settings.defaultZone = DateTime.local().zoneName - Settings.defaultLocale = 'pl' - const { id } = useParams<{ id: string }>() const [yearGroupId] = useLocalStorageState('yearGroupId') const [supervisorId] = useLocalStorageState('userId') @@ -61,15 +61,15 @@ const SupervisorSchedule = () => { Generuj harmonogram diff --git a/frontend/src/views/coordinator/EditSchedule.tsx b/frontend/src/views/coordinator/EditSchedule.tsx index ac2d546..0d01fad 100644 --- a/frontend/src/views/coordinator/EditSchedule.tsx +++ b/frontend/src/views/coordinator/EditSchedule.tsx @@ -1,4 +1,4 @@ -import { DateTime } from 'luxon' +import dayjs from 'dayjs' import { useState } from 'react' import { Controller, NestedValue, useForm } from 'react-hook-form' import { useMutation, useQuery } from 'react-query' @@ -72,8 +72,8 @@ const EditSchedule = ({

Termin

- {DateTime.fromJSDate(eventData.start).toFormat('yyyy-LL-dd HH:mm:ss')}{' '} - - {DateTime.fromJSDate(eventData.end).toFormat('yyyy-LL-dd HH:mm:ss')} + {dayjs(eventData.start).format('YYYY-MM-DD HH:mm:ss')} -{' '} + {dayjs(eventData.end).format('YYYY-MM-DD HH:mm:ss')}

{eventData.resource?.members_of_committee?.length ? ( <> diff --git a/frontend/src/views/coordinator/Schedule.tsx b/frontend/src/views/coordinator/Schedule.tsx index b2505be..3766c8d 100644 --- a/frontend/src/views/coordinator/Schedule.tsx +++ b/frontend/src/views/coordinator/Schedule.tsx @@ -1,5 +1,4 @@ -import { Calendar, luxonLocalizer, Views } from 'react-big-calendar' -import { DateTime, Settings } from 'luxon' +import { Calendar, Views } from 'react-big-calendar' import { useCallback, useEffect, useState } from 'react' import { useMutation, useQuery } from 'react-query' import { @@ -18,6 +17,8 @@ import { getLeaders } from '../../api/leaders' import useLocalStorageState from 'use-local-storage-state' import bigCalendarTranslations from '../../utils/bigCalendarTranslations' import DatePicker from 'react-date-picker' +import dayjs from 'dayjs' +import dayjsLocalizer from '../../utils/dayjsLocalizer' const customStyles = { content: { @@ -34,10 +35,9 @@ type SelectValue = { label: string } -const Schedule = () => { - Settings.defaultZone = DateTime.local().zoneName - Settings.defaultLocale = 'pl' +const localizer = dayjsLocalizer(dayjs) +const Schedule = () => { const { id } = useParams<{ id: string }>() const [yearGroupId] = useLocalStorageState('yearGroupId') const [events, setEvents] = useState< @@ -184,10 +184,10 @@ const Schedule = () => { } else { // await mutateCreateEvent({ // start_date: DateTime.fromJSDate(event.start).toFormat( - // 'yyyy-LL-dd HH:mm:ss', + // 'YYYY-MM-DD HH:mm:ss', // ), // end_date: DateTime.fromJSDate(event.end).toFormat( - // 'yyyy-LL-dd HH:mm:ss', + // 'YYYY-MM-DD HH:mm:ss', // ), // scheduleId: Number(id), // }) @@ -217,12 +217,14 @@ const Schedule = () => { const from = data.from.split(':') const to = data.to.split(':') await mutateCreateEvent({ - start_date: DateTime.fromJSDate(selectedDate.start) - .set({ hour: from[0], minute: from[1] }) - .toFormat('yyyy-LL-dd HH:mm:ss'), - end_date: DateTime.fromJSDate(selectedDate.start) - .set({ hour: to[0], minute: to[1] }) - .toFormat('yyyy-LL-dd HH:mm:ss'), + start_date: dayjs(selectedDate.start) + .set('hour', from[0]) + .set('minute', from[1]) + .format('YYYY-MM-DD HH:mm:ss'), + end_date: dayjs(selectedDate.start) + .set('hour', to[0]) + .set('minute', to[1]) + .format('YYYY-MM-DD HH:mm:ss'), scheduleId: Number(id), project_supervisors: data?.project_supervisors, }) @@ -309,7 +311,7 @@ const Schedule = () => { Eksportuj harmonogram { onView={onView} view={view} eventPropGetter={eventGetter} - min={DateTime.fromObject({ hour: 8, minute: 0 }).toJSDate()} - max={DateTime.fromObject({ hour: 16, minute: 0 }).toJSDate()} + min={dayjs().set('hour', 8).set('minute', 0).toDate()} + max={dayjs().set('hour', 16).set('minute', 0).toDate()} messages={bigCalendarTranslations} /> diff --git a/frontend/src/views/student/ScheduleAddGroup.tsx b/frontend/src/views/student/ScheduleAddGroup.tsx index e612cc4..252f1a2 100644 --- a/frontend/src/views/student/ScheduleAddGroup.tsx +++ b/frontend/src/views/student/ScheduleAddGroup.tsx @@ -1,4 +1,4 @@ -import { DateTime } from 'luxon' +import dayjs from 'dayjs' import React, { useState } from 'react' import { useForm } from 'react-hook-form' import { useMutation } from 'react-query' @@ -51,9 +51,8 @@ const ScheduleAddGroup = ({

- Termin{' '} - {DateTime.fromJSDate(eventData.start).toFormat('yyyy-LL-dd HH:mm:ss')}{' '} - - {DateTime.fromJSDate(eventData.end).toFormat('yyyy-LL-dd HH:mm:ss')} + Termin {dayjs(eventData.start).format('YYYY-MM-DD HH:mm:ss')} -{' '} + {dayjs(eventData.end).format('YYYY-MM-DD HH:mm:ss')}

{eventData.resource?.members_of_committee?.length > 0 && ( <> diff --git a/frontend/src/views/student/StudentSchedule.tsx b/frontend/src/views/student/StudentSchedule.tsx index 9710056..233d4b1 100644 --- a/frontend/src/views/student/StudentSchedule.tsx +++ b/frontend/src/views/student/StudentSchedule.tsx @@ -1,5 +1,4 @@ -import { Calendar, luxonLocalizer, Views } from 'react-big-calendar' -import { DateTime, Settings } from 'luxon' +import { Calendar, Views } from 'react-big-calendar' import { useCallback, useState } from 'react' import { useQuery } from 'react-query' import { getStudentsTermsOfDefences } from '../../api/schedule' @@ -9,6 +8,8 @@ import { useForm } from 'react-hook-form' import ScheduleAddGroup from './ScheduleAddGroup' import bigCalendarTranslations from '../../utils/bigCalendarTranslations' import useLocalStorageState from 'use-local-storage-state' +import dayjs from 'dayjs' +import dayjsLocalizer from '../../utils/dayjsLocalizer' const customStyles = { content: { @@ -20,11 +21,9 @@ const customStyles = { transform: 'translate(-50%, -50%)', }, } +const localizer = dayjsLocalizer(dayjs) const StudentSchedule = () => { - Settings.defaultZone = DateTime.local().zoneName - Settings.defaultLocale = 'pl' - const [studentId] = useLocalStorageState('userId') const { id } = useParams<{ id: string }>() const [events, setEvents] = useState< @@ -131,7 +130,7 @@ const StudentSchedule = () => { Wybierz i zatwierdź termin obrony dla swojej grupy { onView={onView} view={view} eventPropGetter={eventGetter} - min={DateTime.fromObject({ hour: 8, minute: 0 }).toJSDate()} - max={DateTime.fromObject({ hour: 16, minute: 0 }).toJSDate()} + min={dayjs().set('hour', 8).set('minute', 0).toDate()} + max={dayjs().set('hour', 16).set('minute', 0).toDate()} messages={bigCalendarTranslations} /> diff --git a/frontend/src/views/supervisor/SupervisorSchedule.tsx b/frontend/src/views/supervisor/SupervisorSchedule.tsx index c51c213..924baa1 100644 --- a/frontend/src/views/supervisor/SupervisorSchedule.tsx +++ b/frontend/src/views/supervisor/SupervisorSchedule.tsx @@ -1,5 +1,4 @@ -import { Calendar, luxonLocalizer, Views } from 'react-big-calendar' -import { DateTime, Settings } from 'luxon' +import { Calendar, Views } from 'react-big-calendar' import { useCallback, useState } from 'react' import { useMutation, useQuery } from 'react-query' import { @@ -13,6 +12,8 @@ import { useForm } from 'react-hook-form' import EditSchedule from '../coordinator/EditSchedule' import useLocalStorageState from 'use-local-storage-state' import bigCalendarTranslations from '../../utils/bigCalendarTranslations' +import dayjs from 'dayjs' +import dayjsLocalizer from '../../utils/dayjsLocalizer' const customStyles = { content: { @@ -28,11 +29,9 @@ type SelectValue = { value: string | number label: string } +const localizer = dayjsLocalizer(dayjs) const SupervisorSchedule = () => { - Settings.defaultZone = DateTime.local().zoneName - Settings.defaultLocale = 'pl' - const { id } = useParams<{ id: string }>() const [yearGroupId] = useLocalStorageState('yearGroupId') const [supervisorId] = useLocalStorageState('userId') @@ -155,12 +154,14 @@ const SupervisorSchedule = () => { const from = data.from.split(':') const to = data.to.split(':') await mutateAddAvailability({ - start_date: DateTime.fromJSDate(selectedDate.start) - .set({ hour: from[0], minute: from[1] }) - .toFormat('yyyy-LL-dd HH:mm:ss'), - end_date: DateTime.fromJSDate(selectedDate.start) - .set({ hour: to[0], minute: to[1] }) - .toFormat('yyyy-LL-dd HH:mm:ss'), + start_date: dayjs(selectedDate.start) + .set('hour', from[0]) + .set('minute', from[1]) + .format('YYYY-MM-DD HH:mm:ss'), + end_date: dayjs(selectedDate.start) + .set('hour', to[0]) + .set('minute', to[1]) + .format('YYYY-MM-DD HH:mm:ss'), scheduleId: Number(id), project_supervisor_id: Number(supervisorId), }) @@ -189,7 +190,7 @@ const SupervisorSchedule = () => { return (
{ onView={onView} view={view} eventPropGetter={eventGetter} - min={DateTime.fromObject({ hour: 8, minute: 0 }).toJSDate()} - max={DateTime.fromObject({ hour: 16, minute: 0 }).toJSDate()} + min={dayjs().set('hour', 8).set('minute', 0).toDate()} + max={dayjs().set('hour', 16).set('minute', 0).toDate()} messages={bigCalendarTranslations} />