Replace luxon with dayjs

This commit is contained in:
adam-skowronek 2022-12-30 21:39:58 +01:00
parent 111f63e395
commit b98cfcfeb9
10 changed files with 479 additions and 82 deletions

View File

@ -18,7 +18,7 @@
"axios": "^0.27.2", "axios": "^0.27.2",
"classnames": "^2.3.1", "classnames": "^2.3.1",
"daisyui": "^2.15.2", "daisyui": "^2.15.2",
"luxon": "^3.0.4", "dayjs": "^1.11.7",
"react": "^18.1.0", "react": "^18.1.0",
"react-big-calendar": "^1.5.0", "react-big-calendar": "^1.5.0",
"react-date-picker": "^9.1.0", "react-date-picker": "^9.1.0",
@ -34,7 +34,6 @@
"web-vitals": "^2.1.4" "web-vitals": "^2.1.4"
}, },
"devDependencies": { "devDependencies": {
"@types/luxon": "^3.0.2",
"@types/react-big-calendar": "^0.38.2", "@types/react-big-calendar": "^0.38.2",
"@types/react-modal": "^3.13.1", "@types/react-modal": "^3.13.1",
"autoprefixer": "^10.4.7", "autoprefixer": "^10.4.7",
@ -3823,12 +3822,6 @@
"resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
"integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==" "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": { "node_modules/@types/mime": {
"version": "1.3.2", "version": "1.3.2",
"resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", "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", "resolved": "https://registry.npmjs.org/date-arithmetic/-/date-arithmetic-4.1.0.tgz",
"integrity": "sha512-QWxYLR5P/6GStZcdem+V1xoto6DMadYWpMXU82ES3/RfR3Wdwr3D0+be7mgOJ+Ov0G9D5Dmb9T17sNLQYj9XOg==" "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": { "node_modules/debug": {
"version": "4.3.4", "version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
@ -11565,14 +11563,6 @@
"node": ">=10" "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": { "node_modules/lz-string": {
"version": "1.4.4", "version": "1.4.4",
"resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.4.4.tgz", "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", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
"integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==" "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": { "@types/mime": {
"version": "1.3.2", "version": "1.3.2",
"resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", "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", "resolved": "https://registry.npmjs.org/date-arithmetic/-/date-arithmetic-4.1.0.tgz",
"integrity": "sha512-QWxYLR5P/6GStZcdem+V1xoto6DMadYWpMXU82ES3/RfR3Wdwr3D0+be7mgOJ+Ov0G9D5Dmb9T17sNLQYj9XOg==" "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": { "debug": {
"version": "4.3.4", "version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
@ -25438,11 +25427,6 @@
"yallist": "^4.0.0" "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": { "lz-string": {
"version": "1.4.4", "version": "1.4.4",
"resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.4.4.tgz", "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.4.4.tgz",

View File

@ -13,7 +13,7 @@
"axios": "^0.27.2", "axios": "^0.27.2",
"classnames": "^2.3.1", "classnames": "^2.3.1",
"daisyui": "^2.15.2", "daisyui": "^2.15.2",
"luxon": "^3.0.4", "dayjs": "^1.11.7",
"react": "^18.1.0", "react": "^18.1.0",
"react-big-calendar": "^1.5.0", "react-big-calendar": "^1.5.0",
"react-date-picker": "^9.1.0", "react-date-picker": "^9.1.0",
@ -53,7 +53,6 @@
] ]
}, },
"devDependencies": { "devDependencies": {
"@types/luxon": "^3.0.2",
"@types/react-big-calendar": "^0.38.2", "@types/react-big-calendar": "^0.38.2",
"@types/react-modal": "^3.13.1", "@types/react-modal": "^3.13.1",
"autoprefixer": "^10.4.7", "autoprefixer": "^10.4.7",

View File

@ -26,6 +26,10 @@ import SupervisorAvailabilities from './views/coordinator/SupervisorAvailabiliti
import AvailabilitySchedule from './views/coordinator/AvailabilitySchedule' import AvailabilitySchedule from './views/coordinator/AvailabilitySchedule'
import GradeCard from './views/GradeCard' import GradeCard from './views/GradeCard'
import Group from './views/coordinator/Group' import Group from './views/coordinator/Group'
import dayjs from 'dayjs'
require('dayjs/locale/pl')
dayjs.locale('pl')
const queryClient = new QueryClient({ const queryClient = new QueryClient({
defaultOptions: { defaultOptions: {

View File

@ -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,
})
}

View File

@ -1,5 +1,4 @@
import { Calendar, luxonLocalizer, Views } from 'react-big-calendar' import { Calendar, Views } from 'react-big-calendar'
import { DateTime, Settings } from 'luxon'
import { useCallback, useState } from 'react' import { useCallback, useState } from 'react'
import { useMutation, useQuery } from 'react-query' import { useMutation, useQuery } from 'react-query'
import { useParams } from 'react-router-dom' import { useParams } from 'react-router-dom'
@ -9,11 +8,12 @@ import {
generateTermsOfDefence, generateTermsOfDefence,
getAvailabilityForCoordinator, getAvailabilityForCoordinator,
} from '../../api/schedule' } from '../../api/schedule'
import dayjs from 'dayjs'
import dayjsLocalizer from '../../utils/dayjsLocalizer'
const localizer = dayjsLocalizer(dayjs)
const SupervisorSchedule = () => { const SupervisorSchedule = () => {
Settings.defaultZone = DateTime.local().zoneName
Settings.defaultLocale = 'pl'
const { id } = useParams<{ id: string }>() const { id } = useParams<{ id: string }>()
const [yearGroupId] = useLocalStorageState('yearGroupId') const [yearGroupId] = useLocalStorageState('yearGroupId')
const [supervisorId] = useLocalStorageState('userId') const [supervisorId] = useLocalStorageState('userId')
@ -61,15 +61,15 @@ const SupervisorSchedule = () => {
Generuj harmonogram Generuj harmonogram
</button> </button>
<Calendar <Calendar
localizer={luxonLocalizer(DateTime)} localizer={localizer}
startAccessor="start" startAccessor="start"
endAccessor="end" endAccessor="end"
style={{ height: '80vh' }} style={{ height: '80vh' }}
events={events} events={events}
onView={onView} onView={onView}
view={view} view={view}
min={DateTime.fromObject({ hour: 8, minute: 0 }).toJSDate()} min={dayjs().set('hour', 8).set('minute', 0).toDate()}
max={DateTime.fromObject({ hour: 16, minute: 0 }).toJSDate()} max={dayjs().set('hour', 16).set('minute', 0).toDate()}
messages={bigCalendarTranslations} messages={bigCalendarTranslations}
/> />
</div> </div>

View File

@ -1,4 +1,4 @@
import { DateTime } from 'luxon' import dayjs from 'dayjs'
import { useState } from 'react' import { useState } from 'react'
import { Controller, NestedValue, useForm } from 'react-hook-form' import { Controller, NestedValue, useForm } from 'react-hook-form'
import { useMutation, useQuery } from 'react-query' import { useMutation, useQuery } from 'react-query'
@ -72,8 +72,8 @@ const EditSchedule = ({
<form className="w-full flex flex-col " onSubmit={handleSubmit(onSubmit)}> <form className="w-full flex flex-col " onSubmit={handleSubmit(onSubmit)}>
<h3> Termin </h3> <h3> Termin </h3>
<p className="mb-2"> <p className="mb-2">
{DateTime.fromJSDate(eventData.start).toFormat('yyyy-LL-dd HH:mm:ss')}{' '} {dayjs(eventData.start).format('YYYY-MM-DD HH:mm:ss')} -{' '}
- {DateTime.fromJSDate(eventData.end).toFormat('yyyy-LL-dd HH:mm:ss')} {dayjs(eventData.end).format('YYYY-MM-DD HH:mm:ss')}
</p> </p>
{eventData.resource?.members_of_committee?.length ? ( {eventData.resource?.members_of_committee?.length ? (
<> <>

View File

@ -1,5 +1,4 @@
import { Calendar, luxonLocalizer, Views } from 'react-big-calendar' import { Calendar, Views } from 'react-big-calendar'
import { DateTime, Settings } from 'luxon'
import { useCallback, useEffect, useState } from 'react' import { useCallback, useEffect, useState } from 'react'
import { useMutation, useQuery } from 'react-query' import { useMutation, useQuery } from 'react-query'
import { import {
@ -18,6 +17,8 @@ import { getLeaders } from '../../api/leaders'
import useLocalStorageState from 'use-local-storage-state' import useLocalStorageState from 'use-local-storage-state'
import bigCalendarTranslations from '../../utils/bigCalendarTranslations' import bigCalendarTranslations from '../../utils/bigCalendarTranslations'
import DatePicker from 'react-date-picker' import DatePicker from 'react-date-picker'
import dayjs from 'dayjs'
import dayjsLocalizer from '../../utils/dayjsLocalizer'
const customStyles = { const customStyles = {
content: { content: {
@ -34,10 +35,9 @@ type SelectValue = {
label: string label: string
} }
const Schedule = () => { const localizer = dayjsLocalizer(dayjs)
Settings.defaultZone = DateTime.local().zoneName
Settings.defaultLocale = 'pl'
const Schedule = () => {
const { id } = useParams<{ id: string }>() const { id } = useParams<{ id: string }>()
const [yearGroupId] = useLocalStorageState('yearGroupId') const [yearGroupId] = useLocalStorageState('yearGroupId')
const [events, setEvents] = useState< const [events, setEvents] = useState<
@ -184,10 +184,10 @@ const Schedule = () => {
} else { } else {
// await mutateCreateEvent({ // await mutateCreateEvent({
// start_date: DateTime.fromJSDate(event.start).toFormat( // 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( // end_date: DateTime.fromJSDate(event.end).toFormat(
// 'yyyy-LL-dd HH:mm:ss', // 'YYYY-MM-DD HH:mm:ss',
// ), // ),
// scheduleId: Number(id), // scheduleId: Number(id),
// }) // })
@ -217,12 +217,14 @@ const Schedule = () => {
const from = data.from.split(':') const from = data.from.split(':')
const to = data.to.split(':') const to = data.to.split(':')
await mutateCreateEvent({ await mutateCreateEvent({
start_date: DateTime.fromJSDate(selectedDate.start) start_date: dayjs(selectedDate.start)
.set({ hour: from[0], minute: from[1] }) .set('hour', from[0])
.toFormat('yyyy-LL-dd HH:mm:ss'), .set('minute', from[1])
end_date: DateTime.fromJSDate(selectedDate.start) .format('YYYY-MM-DD HH:mm:ss'),
.set({ hour: to[0], minute: to[1] }) end_date: dayjs(selectedDate.start)
.toFormat('yyyy-LL-dd HH:mm:ss'), .set('hour', to[0])
.set('minute', to[1])
.format('YYYY-MM-DD HH:mm:ss'),
scheduleId: Number(id), scheduleId: Number(id),
project_supervisors: data?.project_supervisors, project_supervisors: data?.project_supervisors,
}) })
@ -309,7 +311,7 @@ const Schedule = () => {
Eksportuj harmonogram Eksportuj harmonogram
</button> </button>
<Calendar <Calendar
localizer={luxonLocalizer(DateTime)} localizer={localizer}
startAccessor="start" startAccessor="start"
endAccessor="end" endAccessor="end"
style={{ height: '85vh' }} style={{ height: '85vh' }}
@ -320,8 +322,8 @@ const Schedule = () => {
onView={onView} onView={onView}
view={view} view={view}
eventPropGetter={eventGetter} eventPropGetter={eventGetter}
min={DateTime.fromObject({ hour: 8, minute: 0 }).toJSDate()} min={dayjs().set('hour', 8).set('minute', 0).toDate()}
max={DateTime.fromObject({ hour: 16, minute: 0 }).toJSDate()} max={dayjs().set('hour', 16).set('minute', 0).toDate()}
messages={bigCalendarTranslations} messages={bigCalendarTranslations}
/> />

View File

@ -1,4 +1,4 @@
import { DateTime } from 'luxon' import dayjs from 'dayjs'
import React, { useState } from 'react' import React, { useState } from 'react'
import { useForm } from 'react-hook-form' import { useForm } from 'react-hook-form'
import { useMutation } from 'react-query' import { useMutation } from 'react-query'
@ -51,9 +51,8 @@ const ScheduleAddGroup = ({
<div> <div>
<form className="w-full flex flex-col " onSubmit={handleSubmit(onSubmit)}> <form className="w-full flex flex-col " onSubmit={handleSubmit(onSubmit)}>
<h3> <h3>
Termin{' '} Termin {dayjs(eventData.start).format('YYYY-MM-DD HH:mm:ss')} -{' '}
{DateTime.fromJSDate(eventData.start).toFormat('yyyy-LL-dd HH:mm:ss')}{' '} {dayjs(eventData.end).format('YYYY-MM-DD HH:mm:ss')}
- {DateTime.fromJSDate(eventData.end).toFormat('yyyy-LL-dd HH:mm:ss')}
</h3> </h3>
{eventData.resource?.members_of_committee?.length > 0 && ( {eventData.resource?.members_of_committee?.length > 0 && (
<> <>

View File

@ -1,5 +1,4 @@
import { Calendar, luxonLocalizer, Views } from 'react-big-calendar' import { Calendar, Views } from 'react-big-calendar'
import { DateTime, Settings } from 'luxon'
import { useCallback, useState } from 'react' import { useCallback, useState } from 'react'
import { useQuery } from 'react-query' import { useQuery } from 'react-query'
import { getStudentsTermsOfDefences } from '../../api/schedule' import { getStudentsTermsOfDefences } from '../../api/schedule'
@ -9,6 +8,8 @@ import { useForm } from 'react-hook-form'
import ScheduleAddGroup from './ScheduleAddGroup' import ScheduleAddGroup from './ScheduleAddGroup'
import bigCalendarTranslations from '../../utils/bigCalendarTranslations' import bigCalendarTranslations from '../../utils/bigCalendarTranslations'
import useLocalStorageState from 'use-local-storage-state' import useLocalStorageState from 'use-local-storage-state'
import dayjs from 'dayjs'
import dayjsLocalizer from '../../utils/dayjsLocalizer'
const customStyles = { const customStyles = {
content: { content: {
@ -20,11 +21,9 @@ const customStyles = {
transform: 'translate(-50%, -50%)', transform: 'translate(-50%, -50%)',
}, },
} }
const localizer = dayjsLocalizer(dayjs)
const StudentSchedule = () => { const StudentSchedule = () => {
Settings.defaultZone = DateTime.local().zoneName
Settings.defaultLocale = 'pl'
const [studentId] = useLocalStorageState('userId') const [studentId] = useLocalStorageState('userId')
const { id } = useParams<{ id: string }>() const { id } = useParams<{ id: string }>()
const [events, setEvents] = useState< const [events, setEvents] = useState<
@ -131,7 +130,7 @@ const StudentSchedule = () => {
Wybierz i zatwierdź termin obrony dla swojej grupy Wybierz i zatwierdź termin obrony dla swojej grupy
</h1> </h1>
<Calendar <Calendar
localizer={luxonLocalizer(DateTime)} localizer={localizer}
startAccessor="start" startAccessor="start"
endAccessor="end" endAccessor="end"
style={{ height: '85vh' }} style={{ height: '85vh' }}
@ -141,8 +140,8 @@ const StudentSchedule = () => {
onView={onView} onView={onView}
view={view} view={view}
eventPropGetter={eventGetter} eventPropGetter={eventGetter}
min={DateTime.fromObject({ hour: 8, minute: 0 }).toJSDate()} min={dayjs().set('hour', 8).set('minute', 0).toDate()}
max={DateTime.fromObject({ hour: 16, minute: 0 }).toJSDate()} max={dayjs().set('hour', 16).set('minute', 0).toDate()}
messages={bigCalendarTranslations} messages={bigCalendarTranslations}
/> />

View File

@ -1,5 +1,4 @@
import { Calendar, luxonLocalizer, Views } from 'react-big-calendar' import { Calendar, Views } from 'react-big-calendar'
import { DateTime, Settings } from 'luxon'
import { useCallback, useState } from 'react' import { useCallback, useState } from 'react'
import { useMutation, useQuery } from 'react-query' import { useMutation, useQuery } from 'react-query'
import { import {
@ -13,6 +12,8 @@ import { useForm } from 'react-hook-form'
import EditSchedule from '../coordinator/EditSchedule' import EditSchedule from '../coordinator/EditSchedule'
import useLocalStorageState from 'use-local-storage-state' import useLocalStorageState from 'use-local-storage-state'
import bigCalendarTranslations from '../../utils/bigCalendarTranslations' import bigCalendarTranslations from '../../utils/bigCalendarTranslations'
import dayjs from 'dayjs'
import dayjsLocalizer from '../../utils/dayjsLocalizer'
const customStyles = { const customStyles = {
content: { content: {
@ -28,11 +29,9 @@ type SelectValue = {
value: string | number value: string | number
label: string label: string
} }
const localizer = dayjsLocalizer(dayjs)
const SupervisorSchedule = () => { const SupervisorSchedule = () => {
Settings.defaultZone = DateTime.local().zoneName
Settings.defaultLocale = 'pl'
const { id } = useParams<{ id: string }>() const { id } = useParams<{ id: string }>()
const [yearGroupId] = useLocalStorageState('yearGroupId') const [yearGroupId] = useLocalStorageState('yearGroupId')
const [supervisorId] = useLocalStorageState('userId') const [supervisorId] = useLocalStorageState('userId')
@ -155,12 +154,14 @@ const SupervisorSchedule = () => {
const from = data.from.split(':') const from = data.from.split(':')
const to = data.to.split(':') const to = data.to.split(':')
await mutateAddAvailability({ await mutateAddAvailability({
start_date: DateTime.fromJSDate(selectedDate.start) start_date: dayjs(selectedDate.start)
.set({ hour: from[0], minute: from[1] }) .set('hour', from[0])
.toFormat('yyyy-LL-dd HH:mm:ss'), .set('minute', from[1])
end_date: DateTime.fromJSDate(selectedDate.start) .format('YYYY-MM-DD HH:mm:ss'),
.set({ hour: to[0], minute: to[1] }) end_date: dayjs(selectedDate.start)
.toFormat('yyyy-LL-dd HH:mm:ss'), .set('hour', to[0])
.set('minute', to[1])
.format('YYYY-MM-DD HH:mm:ss'),
scheduleId: Number(id), scheduleId: Number(id),
project_supervisor_id: Number(supervisorId), project_supervisor_id: Number(supervisorId),
}) })
@ -189,7 +190,7 @@ const SupervisorSchedule = () => {
return ( return (
<div className="flex flex-col"> <div className="flex flex-col">
<Calendar <Calendar
localizer={luxonLocalizer(DateTime)} localizer={localizer}
startAccessor="start" startAccessor="start"
endAccessor="end" endAccessor="end"
selectable selectable
@ -200,8 +201,8 @@ const SupervisorSchedule = () => {
onView={onView} onView={onView}
view={view} view={view}
eventPropGetter={eventGetter} eventPropGetter={eventGetter}
min={DateTime.fromObject({ hour: 8, minute: 0 }).toJSDate()} min={dayjs().set('hour', 8).set('minute', 0).toDate()}
max={DateTime.fromObject({ hour: 16, minute: 0 }).toJSDate()} max={dayjs().set('hour', 16).set('minute', 0).toDate()}
messages={bigCalendarTranslations} messages={bigCalendarTranslations}
/> />