diff --git a/components/wizard/calendar.tsx b/components/wizard/calendar.tsx
index 040043c..c89cb74 100644
--- a/components/wizard/calendar.tsx
+++ b/components/wizard/calendar.tsx
@@ -1,8 +1,8 @@
-import React, { useState } from 'react'
+import React from 'react'
import classnames from 'classnames'
+import { isPast } from 'date-fns'
import useSWR from 'swr'
-import moment, { Moment } from 'moment'
-import { Calendar } from 'react-calendar-component'
+import Calendar from 'react-calendar'
import { dateFormatBackend } from '../../helpers/date'
const fetcher = (path: string) => fetch(path).then((r) => r.json())
@@ -13,10 +13,17 @@ export default function MyCalendar() {
fetcher
)
- const [date, setDate] = useState(moment())
-
- function dayBooked(day: Date) {
- return daysBooked && daysBooked.includes(dateFormatBackend(day))
+ function tileClassName({ date, view }) {
+ const isMonthView = view === 'month'
+ const isDaysBookedLoaded = !!daysBooked
+ const isBooked = daysBooked?.includes(dateFormatBackend(date))
+ return classnames({
+ 'react-calendar__tile--past': isPast(date),
+ 'react-calendar__tile--booked':
+ isMonthView && isDaysBookedLoaded && isBooked,
+ 'react-calendar__tile--free':
+ isMonthView && isDaysBookedLoaded && !isBooked,
+ })
}
if (fetchBookedOnError) {
@@ -29,48 +36,9 @@ export default function MyCalendar() {
}
return (
-
+
Buchungsübersicht
-
) => setDate(date)}
- date={date}
- renderDay={({
- day,
- classNames,
- onPickDate,
- }: {
- day: Moment
- classNames: string
- onPickDate: any
- }) => (
- onPickDate(day)}
- >
- {day.format('D')}
-
- )}
- renderHeader={({ date, onPrevMonth, onNextMonth }) => (
-
-
-
- {date.format('MMMM YYYY')}
-
-
-
- )}
- onPickDate={() => {}}
- />
+
diff --git a/db/booking.ts b/db/booking.ts
index 954e5c3..943b6db 100644
--- a/db/booking.ts
+++ b/db/booking.ts
@@ -65,7 +65,10 @@ const BookingSchema = new mongoose.Schema
(
)
BookingSchema.virtual('days').get(function () {
- return getDays({ startDate: this.startDate, endDate: this.endDate })
+ return getDays({
+ startDate: new Date(this.startDate),
+ endDate: new Date(this.endDate),
+ })
})
BookingSchema.static('findBookedDays', async function (): Promise {
diff --git a/helpers/date.ts b/helpers/date.ts
index 1c56293..8169806 100644
--- a/helpers/date.ts
+++ b/helpers/date.ts
@@ -1,50 +1,49 @@
-import moment from 'moment'
+import { parse, format, addDays } from 'date-fns'
-const FRONTEND_FORMAT = 'DD.MM.YYYY'
-const BACKEND_FORMAT = 'YYYY-MM-DD'
+const FRONTEND_FORMAT = 'dd.MM.yyyy'
+const BACKEND_FORMAT = 'yyyy-MM-dd'
export function getDays({
startDate,
endDate,
}: {
- startDate: moment.MomentInput
- endDate: moment.MomentInput
+ startDate: Date
+ endDate: Date
}) {
- let currentDay = moment(startDate)
+ let currentDay = new Date(startDate.getTime())
const days = [dateFormatBackend(currentDay)]
if (!endDate) {
return days
}
- const end = moment(endDate)
- while (currentDay < end) {
- currentDay = currentDay.add(1, 'day')
+ while (currentDay < endDate) {
+ currentDay = addDays(currentDay, 1)
days.push(dateFormatBackend(currentDay))
}
return days
}
-function dateFormat(date: moment.MomentInput, format: string) {
+function dateFormat(date: Date, formatString: string) {
if (!date) {
return null
}
- return moment(date).format(format)
+ return format(date, formatString)
}
-export function dateFormatBackend(date: moment.MomentInput) {
+export function dateFormatBackend(date: Date) {
return dateFormat(date, BACKEND_FORMAT)
}
-export function dateFormatFrontend(date: moment.MomentInput) {
+export function dateFormatFrontend(date: Date) {
return dateFormat(date, FRONTEND_FORMAT)
}
-function dateParse(input: string, format: string) {
- const date = moment(input, format)
- if (date.isValid()) {
- return date.toDate()
+function dateParse(input: string, formatString: string) {
+ const date = parse(input, formatString, new Date())
+ if (date.getTime() !== NaN) {
+ return date
}
return null
diff --git a/package-lock.json b/package-lock.json
index c7a9ed8..edc10de 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1153,19 +1153,6 @@
"esutils": "^2.0.2"
}
},
- "@babel/preset-react": {
- "version": "7.9.4",
- "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.9.4.tgz",
- "integrity": "sha512-AxylVB3FXeOTQXNXyiuAQJSvss62FEotbX2Pzx3K/7c+MKJMdSg6Ose6QYllkdCFA8EInCJVw7M/o5QbLuA4ZQ==",
- "requires": {
- "@babel/helper-plugin-utils": "^7.8.3",
- "@babel/plugin-transform-react-display-name": "^7.8.3",
- "@babel/plugin-transform-react-jsx": "^7.9.4",
- "@babel/plugin-transform-react-jsx-development": "^7.9.0",
- "@babel/plugin-transform-react-jsx-self": "^7.9.0",
- "@babel/plugin-transform-react-jsx-source": "^7.9.0"
- }
- },
"@babel/preset-typescript": {
"version": "7.10.4",
"resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.10.4.tgz",
@@ -2151,6 +2138,11 @@
"csstype": "^3.0.2"
}
},
+ "@types/react-calendar": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/@types/react-calendar/-/react-calendar-3.1.1.tgz",
+ "integrity": "sha512-tjaxwYm/6R3N/vYq4q0+RJP6p6SlNrMbD4AZf9GQUu8nhN7Rkpu5YlrK0J/q77h1ikAlAyNWor8yqc7tGgfFQg=="
+ },
"@types/stack-utils": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz",
@@ -2335,6 +2327,11 @@
"@xtuc/long": "4.2.2"
}
},
+ "@wojtekmaj/date-utils": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@wojtekmaj/date-utils/-/date-utils-1.0.3.tgz",
+ "integrity": "sha512-1VPkkTBk07gMR1fjpBtse4G+oJqpmE+0gUFB0dg3VIL7qJmUVaBoD/vlzMm/jNeOPfvlmerl1lpnsZyBUFIRuw=="
+ },
"@xtuc/ieee754": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz",
@@ -3900,6 +3897,11 @@
"whatwg-url": "^8.0.0"
}
},
+ "date-fns": {
+ "version": "2.16.1",
+ "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.16.1.tgz",
+ "integrity": "sha512-sAJVKx/FqrLYHAQeN7VpJrPhagZc9R4ImZIWYRFZaaohR3KzmuK88touwsSwSVT8Qcbd4zoDsnGfX4GFB4imyQ=="
+ },
"dayjs": {
"version": "1.8.36",
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.8.36.tgz",
@@ -4793,6 +4795,14 @@
"pump": "^3.0.0"
}
},
+ "get-user-locale": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/get-user-locale/-/get-user-locale-1.4.0.tgz",
+ "integrity": "sha512-gQo03lP1OArHLKlnoglqrGGl7b04u2EP9Xutmp72cMdtrrSD7ZgIsCsUKZynYWLDkVJW33Cj3pliP7uP0UonHQ==",
+ "requires": {
+ "lodash.once": "^4.1.1"
+ }
+ },
"get-value": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz",
@@ -7109,6 +7119,11 @@
"integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=",
"dev": true
},
+ "lodash.once": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
+ "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w="
+ },
"lodash.sortby": {
"version": "4.7.0",
"resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz",
@@ -7217,6 +7232,11 @@
"integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==",
"optional": true
},
+ "merge-class-names": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/merge-class-names/-/merge-class-names-1.3.0.tgz",
+ "integrity": "sha512-k0Qaj36VBpKgdc8c188LEZvo6v/zzry/FUufwopWbMSp6/knfVFU/KIB55/hJjeIpg18IH2WskXJCRnM/1BrdQ=="
+ },
"merge-stream": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
@@ -7368,11 +7388,6 @@
"minimist": "^1.2.5"
}
},
- "moment": {
- "version": "2.28.0",
- "resolved": "https://registry.npmjs.org/moment/-/moment-2.28.0.tgz",
- "integrity": "sha512-Z5KOjYmnHyd/ukynmFd/WwyXHd7L4J9vTI/nn5Ap9AVUgaAE15VvQ9MOGmJJygEUklupqIrFnor/tjTwRU+tQw=="
- },
"mongodb": {
"version": "3.6.2",
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.6.2.tgz",
@@ -8983,15 +8998,15 @@
"prop-types": "^15.6.2"
}
},
- "react-calendar-component": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/react-calendar-component/-/react-calendar-component-3.0.0.tgz",
- "integrity": "sha512-vua/pu+hTeLD9SSc+NH79IwCLc3REvl4gL9C3dtUo/+cGhPiQo6CGC/Jm8AVgTBhO4CtNr21tEWAdlCVqIxBbA==",
+ "react-calendar": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/react-calendar/-/react-calendar-3.1.0.tgz",
+ "integrity": "sha512-xoKdRe6FrnZ30LD9pyr20fhet1uwSbc6srLGm1ib7G4b7tAXniZrwzrJ4YV/Hbmmwf/zAFGyXtBzLAIV1KNvuA==",
"requires": {
- "@babel/preset-react": "^7.0.0",
- "classnames": "^2.2.5",
- "moment": "^2.19.1",
- "prop-types": "^15.7.2"
+ "@wojtekmaj/date-utils": "^1.0.2",
+ "get-user-locale": "^1.2.0",
+ "merge-class-names": "^1.1.1",
+ "prop-types": "^15.6.0"
}
},
"react-dom": {
diff --git a/package.json b/package.json
index e04a3e6..175019f 100644
--- a/package.json
+++ b/package.json
@@ -10,12 +10,12 @@
"test:ci": "jest"
},
"dependencies": {
+ "date-fns": "^2.16.1",
"ics": "^2.24.0",
- "moment": "^2.28.0",
"mongoose": "^5.10.5",
"next": "^9.5.3",
"react": "16.13.1",
- "react-calendar-component": "^3.0.0",
+ "react-calendar": "^3.1.0",
"react-dom": "16.13.1",
"uuid": "^8.3.0"
},
@@ -24,6 +24,7 @@
"@types/jest": "^26.0.14",
"@types/mongoose": "^5.7.36",
"@types/react": "^16.9.49",
+ "@types/react-calendar": "^3.1.1",
"@types/uuid": "^8.3.0",
"babel-jest": "^26.3.0",
"jest": "^26.4.2",
diff --git a/styles/index.css b/styles/index.css
index 6a3c641..a79a933 100644
--- a/styles/index.css
+++ b/styles/index.css
@@ -120,49 +120,109 @@
content: '\274c';
}
-.Calendar-grid {
- @apply flex flex-wrap;
+.react-calendar {
+ @apply border border-gray-900;
}
-.Calendar-header {
- @apply flex justify-between bg-gray-700 text-gray-200 text-center;
+.react-calendar button {
+ @apply outline-none;
}
-.Calendar-header button {
- @apply w-10 bg-transparent text-gray-200 cursor-pointer;
+.react-calendar button:enabled:hover {
+ cursor: pointer;
}
-.Calendar-grid-item {
- @apply text-center p-1 border-r border-b border-solid border-gray-500;
- flex: 0 calc(100% / 7);
+.react-calendar__navigation {
+ @apply text-gray-100 bg-gray-900;
}
-.Calendar-grid-item--past {
- @apply text-gray-500 bg-gray-200;
+.react-calendar__navigation button {
+ @apply px-3 py-2;
+ min-width: 2rem;
}
-.Calendar-grid-item--current {
+.react-calendar__navigation button:enabled:hover,
+.react-calendar__navigation button:enabled:focus {
+}
+.react-calendar__navigation button[disabled] {
+ @apply text-gray-700 cursor-not-allowed;
+}
+.react-calendar__month-view__weekdays {
+ @apply text-sm text-center uppercase font-bold;
+}
+.react-calendar__month-view__weekdays__weekday {
+ @apply p-1;
+}
+
+.react-calendar__month-view__weekdays__weekday abbr {
+ @apply no-underline;
+}
+
+.react-calendar__month-view__weekNumbers {
@apply font-bold;
}
+.react-calendar__month-view__weekNumbers .react-calendar__tile {
+ @apply flex items-center content-center;
+}
+.react-calendar__month-view__days__day--weekend {
+ @apply text-red-600;
+}
+.react-calendar__month-view__days__day--neighboringMonth {
+ @apply text-gray-400;
+}
+.react-calendar__year-view .react-calendar__tile,
+.react-calendar__decade-view .react-calendar__tile,
+.react-calendar__century-view .react-calendar__tile {
+}
-.Calendar-grid-item--free:not(.Calendar-grid-item--past) {
+.react-calendar__tile {
+ @apply py-1;
+}
+
+.react-calendar__tile--free {
@apply bg-green-200;
}
-.Calendar-grid-item--booked {
+.react-calendar__tile--booked {
@apply bg-red-200 cursor-not-allowed;
}
-.Calendar-grid-item.nextMonth,
-.Calendar-grid-item.prevMonth {
- @apply text-gray-500;
+.react-calendar__tile--past {
+ @apply bg-gray-400 cursor-not-allowed;
}
-.Calendar-grid-item:nth-child(7n + 1) {
- @apply border-l;
+.react-calendar__tile:disabled {
+ @apply bg-gray-300;
}
-.Calendar-grid-item:nth-child(-n + 7) {
- @apply border-t;
+.react-calendar__tile:enabled:hover,
+.react-calendar__tile:enabled:focus {
+ @apply bg-gray-500;
+}
+.react-calendar__tile--now {
+ @apply text-green-400;
+}
+
+.react-calendar__tile--now:enabled:hover,
+.react-calendar__tile--now:enabled:focus {
+ background: #ffffa9;
+}
+.react-calendar__tile--hasActive {
+ background: #76baff;
+}
+.react-calendar__tile--hasActive:enabled:hover,
+.react-calendar__tile--hasActive:enabled:focus {
+ background: #a9d4ff;
+}
+.react-calendar__tile--active {
+ background: #006edc;
+ color: white;
+}
+.react-calendar__tile--active:enabled:hover,
+.react-calendar__tile--active:enabled:focus {
+ background: #1087ff;
+}
+.react-calendar--selectRange .react-calendar__tile--hover {
+ background-color: #e6e6e6;
}
/* Start purging... */