diff --git a/components/bookingTable.tsx b/components/bookingTable.tsx index 3f9e025..6b945e5 100644 --- a/components/bookingTable.tsx +++ b/components/bookingTable.tsx @@ -1,17 +1,18 @@ import React from 'react' import Link from 'next/link' -import { daysFormatFrontend } from '../helpers/date' -import { BookingDocument } from '../db/booking' +import {Booking} from '@prisma/client'; +import { dateFormatFrontend } from '../helpers/date' + export default function BookingTable({ booking, }: { - booking: BookingDocument + booking: Booking }) { const data = [ { name: 'Status', value: booking.status }, - { name: 'Buchungszeitraum', value: daysFormatFrontend(booking.days) }, + { name: 'Buchungszeitraum', value: `${dateFormatFrontend(new Date(booking.startDate))}-${dateFormatFrontend(new Date(booking.endDate))}` }, { name: 'Organisation', value: booking.org }, { name: 'Addresse', @@ -48,7 +49,7 @@ export default function BookingTable({

Last updated{' '} - {new Date(booking.updatedAt as string).toLocaleString( + {booking.updatedAt.toLocaleString( new Intl.Locale('de') )}

diff --git a/context/book.tsx b/context/book.tsx index 45c8ba3..ad3e7f4 100644 --- a/context/book.tsx +++ b/context/book.tsx @@ -1,20 +1,18 @@ import React, { useEffect, useReducer } from 'react' +import { Prisma } from '@prisma/client' import { useRouter } from 'next/router' import { clearBookingData, loadBookingData } from '../helpers/storage' import { log } from '../helpers/log' import { createBooking } from '../helpers/booking' -import { Booking } from '../db/booking' - -export type BookFormData = Omit type BookingProviderState = { postData?: boolean postDataError?: string postDataSuccess?: boolean - formData: BookFormData + formData: Prisma.BookingCreateInput, formDataChanged: string[] - booking?: Booking + booking?: Prisma.BookingCreateInput, dataStored: boolean dataStoredLoaded: boolean } diff --git a/db/bill.ts b/db/bill.ts deleted file mode 100644 index 2a91f19..0000000 --- a/db/bill.ts +++ /dev/null @@ -1,91 +0,0 @@ -import * as mongoose from 'mongoose' -import { BILL_STATUS, MILAGE_TARIFS } from './enums' -import { getBillTotal } from '../helpers/bill' - -export type AdditionalCost = { - name: string - value: number -} - -export type Bill = { - milageStart: number - milageEnd: number - milage?: number - tarif: MILAGE_TARIFS - status: BILL_STATUS - additionalCosts: AdditionalCost[] -} - -export type BillDocument = Bill & - mongoose.SchemaTimestampsConfig & - mongoose.Document - -export type BillModel = mongoose.Model - -const BillSchema = new mongoose.Schema( - { - milageStart: { - type: Number, - required: true, - validate: { - validator: function (v: number): boolean { - const bill = this as BillDocument - - return v <= bill.milageEnd - }, - message: (props: { value: Number }) => - `${props.value} is bigger than milageEnd!`, - }, - }, - milageEnd: { - type: Number, - required: true, - - validate: { - validator: function (v: number): boolean { - const bill = this as BillDocument - - return v >= bill.milageStart - }, - message: (props: { value: Number }) => - `${props.value} is smaller than milageStart!`, - }, - }, - tarif: { - type: String, - enum: Object.values(MILAGE_TARIFS), - default: MILAGE_TARIFS.EXTERN, - required: true, - }, - additionalCosts: [ - { - name: { type: String, required: true }, - value: { type: Number, required: true }, - }, - ], - status: { - type: String, - enum: Object.values(BILL_STATUS), - default: BILL_STATUS.UNINVOICED, - }, - }, - { - timestamps: true, - toJSON: { virtuals: true, getters: true }, - toObject: { virtuals: true, getters: true }, - } -) - -BillSchema.virtual('milage').get(function (): number { - const bill = this as BillDocument - return bill.milageEnd - bill.milageStart -}) - -BillSchema.virtual('total').get(function (): number { - const bill = this as BillDocument - - return getBillTotal(bill) -}) - -export default (mongoose.models.Bill || - mongoose.model('Bill', BillSchema)) as BillModel diff --git a/db/booking.ts b/db/booking.ts deleted file mode 100644 index eaa60fc..0000000 --- a/db/booking.ts +++ /dev/null @@ -1,168 +0,0 @@ -import * as mongoose from 'mongoose' -import { v4 as uuidv4 } from 'uuid' -import { - dateFormatBackend, - getDays, - nowInTz, - dateParseBackend, -} from '../helpers/date' -import { createCalendarEvent, deleteCalendarEvent } from '../lib/googlecalendar' - -import { Bill } from './bill' -import { BOOKING_STATUS, VALIDATION_ERRORS } from './enums' - -export type Booking = { - uuid: string - name: string - email: string - phone: string - street: string - zip: string - city: string - bill?: Bill - // format YYYY-MM-DD - startDate: string - // format YYYY-MM-DD - endDate: string - status?: BOOKING_STATUS - purpose?: string - org?: string - destination?: string - days?: string[] - calendarEventId: string -} - -export type BookingDocument = Booking & - mongoose.Document & - mongoose.SchemaTimestampsConfig - -export type BookingModel = mongoose.Model & { - findBookedDays(uuidsToIngore?: string[]): Promise -} - -const BookingSchema = new mongoose.Schema( - { - // need a seperate uuid to be able to target a booking anonimously - uuid: { - type: String, - default: uuidv4, - index: true, - }, - name: { type: String, required: true }, - email: { type: String, required: true, minlength: 5 }, - phone: { type: String, required: false }, - street: { type: String, required: true }, - zip: { type: String, required: true }, - city: { type: String, required: true }, - bill: { - type: mongoose.Schema.Types.ObjectId, - ref: 'Bill', - required: false, - }, - startDate: { - type: String, - required: true, - validator: function (value: string): boolean { - return !!dateParseBackend(value) - }, - }, - endDate: { - type: String, - required: true, - validator: function (value: string): boolean { - return !!dateParseBackend(value) - }, - }, - days: { - type: [String], - required: true, - validate: { - validator: async function (days: string[]): Promise { - const booking = this as Booking - const uuid = booking.uuid && [booking.uuid] - const bookedDays = await BookingModel.findBookedDays(uuid) - - const doubleBookedDays = days.filter((day: string): boolean => - bookedDays.includes(day) - ) - return doubleBookedDays.length === 0 - }, - message: (props: { value: string[] }): string => - `At least one day is of ${props.value.join(',')} is already booked`, - type: VALIDATION_ERRORS.AT_LEAST_ONE_DAY_BOOKED, - }, - }, - status: { - type: String, - enum: Object.values(BOOKING_STATUS), - required: true, - default: BOOKING_STATUS.REQUESTED, - }, - purpose: { type: String, required: false }, - org: { type: String, required: false }, - destination: { type: String, required: false }, - calendarEventId: { type: String, required: false }, - }, - { - timestamps: true, - toJSON: { virtuals: true, getters: true }, - toObject: { virtuals: true, getters: true }, - } -) - -BookingSchema.pre('validate', function (next: () => void): void { - const booking = this as BookingDocument - booking.days = getDays({ - startDate: new Date(booking.startDate), - endDate: new Date(booking.endDate), - }) - next() -}) - -BookingSchema.pre('save', async function (next: () => void): Promise { - const booking = this as BookingDocument - - if (!booking.calendarEventId) { - // create calendar event before saving to database - await createCalendarEvent(booking) - } else if ( - [BOOKING_STATUS.CANCELED, BOOKING_STATUS.REJECTED].includes(booking.status) - ) { - // event has been canceled or rejected, delete calendar event again to free up the slot - await deleteCalendarEvent(booking) - } - - next() -}) - -BookingSchema.static( - 'findBookedDays', - async function (uuidsToIngore: string[] = []): Promise { - const model = this as BookingModel - const now = nowInTz() - const bookedDays = await model - .find( - { - status: { $in: [BOOKING_STATUS.REQUESTED, BOOKING_STATUS.CONFIRMED] }, - uuid: { $nin: uuidsToIngore }, - // dateFormatBackend uses YYYY-MM-DD, which is startOfDay anyway - endDate: { $gt: dateFormatBackend(now) }, - }, - 'days' - ) - .exec() - - return bookedDays - .map((b) => b.days) - .flat() - .sort() - } -) - -const BookingModel = (mongoose.models.Booking || - mongoose.model( - 'Booking', - BookingSchema - )) as BookingModel - -export default BookingModel diff --git a/db/enums.ts b/db/enums.ts index 2e57aba..027c602 100644 --- a/db/enums.ts +++ b/db/enums.ts @@ -1,16 +1,3 @@ -export enum BOOKING_STATUS { - REQUESTED = 'requested', - CONFIRMED = 'confirmed', - REJECTED = 'rejected', - CANCELED = 'canceled', -} - -export enum BILL_STATUS { - UNINVOICED = 'uninvoiced', - INVOICED = 'invoiced', - PAID = 'paid', -} - export enum MILAGE_TARIFS { INTERN = 'intern', EXTERN = 'extern', diff --git a/db/index.ts b/db/index.ts index b03db5b..4619a9a 100644 --- a/db/index.ts +++ b/db/index.ts @@ -1,129 +1,121 @@ -import * as mongoose from 'mongoose' -import BookingModel, { Booking, BookingDocument } from './booking' -import BillModel, { Bill } from './bill' +import { BookingStatus, Booking, PrismaClient, Prisma } from '@prisma/client' + +const prisma = new PrismaClient() + import { getBookedDays as calendarGetBookedDays } from '../lib/googlecalendar' -import { BOOKING_STATUS } from './enums' import { uniqueFilter } from '../helpers/array' - -export const MONGO_URI = process.env.MONGO_URI - -mongoose.connect(process.env.MONGO_URI, { - serverSelectionTimeoutMS: 3000, -}) +import { dateFormatBackend, getDays, nowInTz } from '../helpers/date' export async function getBookedDays( uuidsToIngore?: string[] -): Promise { - const [bookedInDatabase, bookedInCalendar] = await Promise.all([ - BookingModel.findBookedDays(uuidsToIngore), +) { + const [bookingsInDbRaw, bookingsInCalendar] = await Promise.all([ + prisma.booking.findMany({ + where: { + uuid: { notIn: uuidsToIngore }, + startDate: { gte: dateFormatBackend(nowInTz()) }, + status: { notIn: [BookingStatus.REJECTED, BookingStatus.CANCELED] } + }, + select: { + startDate: true, + endDate: true, + }, + }), calendarGetBookedDays(), ]) - return [...bookedInDatabase, ...bookedInCalendar].filter(uniqueFilter).sort() + + const bookingsInDb = bookingsInDbRaw.map(booking => getDays(booking)).flat(); + + return [...bookingsInDb, ...bookingsInCalendar].filter(uniqueFilter).sort() } -export async function getBookingByUUID(uuid: string): Promise { - return BookingModel.findOne({ uuid }) +export function getBookingByUUID(uuid: string) { + // TODO: can we ignore canceled and rejected ones ? + return prisma.booking.findUniqueOrThrow({ + where: { + uuid, + }, + include: { + bill: true + } + }) } -export async function getBookings({ - status = [BOOKING_STATUS.CONFIRMED, BOOKING_STATUS.REQUESTED], +export function getBookings({ + status = [ + BookingStatus.REQUESTED, + BookingStatus.CONFIRMED, + ], startDateGreaterThan = '2000-01-01T00:00:00Z', -}: { status?: BOOKING_STATUS[]; startDateGreaterThan?: string } = {}): Promise< - BookingDocument[] -> { - return await BookingModel.find({ - status: { $in: status }, - startDate: { $gte: startDateGreaterThan }, - }) - .sort({ startDate: -1 }) - .exec() +} + : { status?: BookingStatus[]; startDateGreaterThan?: string } = {}) { + return prisma.booking.findMany({ + where: { + startDate: { gte: startDateGreaterThan }, + status: { notIn: status } + }, + }); } -export async function createBooking({ - startDate, - endDate, - purpose, - org, - destination, - name, - email, - phone, - street, - zip, - city, -}: Booking): Promise { - const booking = new BookingModel({ - startDate, - endDate, - purpose, - org, - destination, - name, - email, - phone, - street, - zip, - city, - }) - - await booking.save() - return booking.toJSON() +export function createBooking(data: Booking) { + return prisma.booking.create({ + data + }); } export async function patchBooking( + uuid: string, + data: Prisma.BookingCreateInput +) { + const current = await prisma.booking.update({ + where: { uuid }, + data + }); + const previous = { ...current, ...data } + return { current, previous } + +} + +export function createBill( bookingUUID: string, - bookingData: Booking -): Promise<{ current: Booking; previous: Booking }> { - const booking = await getBookingByUUID(bookingUUID) - const oldBooking = booking.toJSON() - booking.set(bookingData) - await booking.save() - - return { current: booking.toJSON(), previous: oldBooking } + data: Prisma.BillCreateInput, +) { + return prisma.bill.create({ + data: { + ...data, + booking: { + connect: { uuid: bookingUUID } + } + } + }); } -export async function createBill( +export function patchBill( bookingUUID: string, - billData: Bill -): Promise { - const booking = await getBookingByUUID(bookingUUID) - - const bill = new BillModel() - bill.set(billData) - - await bill.save() - - booking.bill = bill._id - await booking.save() - - return bill.toJSON() + data: Prisma.BillUncheckedUpdateInput, +) { + const { id, ...rest } = data; + return prisma.bill.update({ + where: { + }, + data: { + ...rest, + booking: { + connect: { uuid: bookingUUID } + } + } + }); } -export async function patchBill( - bookingUUID: string, - billData: Bill -): Promise { - const booking = await getBookingByUUID(bookingUUID) - const bill = - (booking.bill && (await BillModel.findById(booking.bill))) || - (await BillModel.create({})) +export async function getMilageMax() { + const { milageEnd } = await prisma.bill.findFirst({ + select: { milageEnd: true }, + orderBy: [ + { + milageEnd: 'desc', + }, + ], + }); - bill.set(billData) - await bill.save() - - if (booking.bill !== bill._id) { - booking.bill = bill._id - await booking.save() - } - - return bill.toJSON() -} - -export async function getMilageMax(): Promise { - const billMaxMilageEnd = await BillModel.findOne({}) - .sort('-milageEnd') - .select('milageEnd') - .exec() - - return billMaxMilageEnd?.milageEnd || 0 + return milageEnd || 0; } diff --git a/helpers/array.ts b/helpers/array.ts index eeca9b0..130a046 100644 --- a/helpers/array.ts +++ b/helpers/array.ts @@ -17,6 +17,6 @@ export function getNextBigger(array: T[], pivot: T): T { return array.sort().find((day) => day > pivot) } -export function uniqueFilter(value, index, self) { +export function uniqueFilter(value: T, index: number, self: T[]) { return self.indexOf(value) === index } diff --git a/helpers/bill.ts b/helpers/bill.ts index 7fce605..700f796 100644 --- a/helpers/bill.ts +++ b/helpers/bill.ts @@ -1,79 +1,27 @@ -import { MILAGE_TARIFS } from '../db/enums' -import { AdditionalCost, Bill } from '../db/bill' +import { Bill, Prisma } from '@prisma/client' import fetch from './fetch' -function roundToCent(amount: number): number { - return Math.round(amount * 100) / 100 -} - -export function getMilageCosts({ - tarif, - km, -}: { - tarif: MILAGE_TARIFS - km: number -}): number { - if (tarif === MILAGE_TARIFS.NOCHARGE) { - return 0 - } - - if (km <= 0) { - return 0 - } - - let rate: number - - if (tarif === MILAGE_TARIFS.EXTERN) { - if (km <= 200) { - rate = 0.42 - } else if (km <= 1000) { - rate = 0.25 - } else if (km <= 2000) { - rate = 0.2 - } else { - rate = 0.18 - } - } - - if (tarif === MILAGE_TARIFS.INTERN) { - if (km <= 200) { - rate = 0.37 - } else if (km <= 1000) { - rate = 0.22 - } else if (km <= 2000) { - rate = 0.15 - } else { - rate = 0.13 - } - } - - if (rate === undefined) { - throw Error('Unable to determine rate') - } - - return roundToCent(km * rate) -} export function getBillTotal({ tarif, milage, additionalCosts, }: { - tarif: MILAGE_TARIFS + tarif: Prisma.Decimal milage?: number - additionalCosts: AdditionalCost[] -}): number { - const milageCosts = getMilageCosts({ tarif, km: milage }) + additionalCosts: Prisma.AdditionalCostsCreateInput[] +}): Prisma.Decimal { + const milageCosts = tarif.mul(milage) const additionalCostsSum = additionalCosts - .map(({ value }) => value) - .reduce((acc: number, value: number) => acc + value, 0) + .reduce((acc, {value} ) => (value as Prisma.Decimal).plus(acc), new Prisma.Decimal(0)) - return roundToCent(milageCosts + additionalCostsSum) + + return additionalCostsSum.add(milageCosts).toDecimalPlaces(2); } export async function createBill( bookingUuid: string, - bill: Bill + bill: Prisma.BillCreateInput ): Promise { return fetch(`/api/bookings/${bookingUuid}/bill`, { method: 'POST', @@ -83,7 +31,7 @@ export async function createBill( export async function patchBill( bookingUuid: string, - bill: Bill + bill: Prisma.BillUpdateInput ): Promise { return fetch(`/api/bookings/${bookingUuid}/bill`, { method: 'POST', diff --git a/helpers/booking.ts b/helpers/booking.ts index 12460be..658744d 100644 --- a/helpers/booking.ts +++ b/helpers/booking.ts @@ -1,23 +1,22 @@ -import { BookFormData } from '../context/book' -import { BOOKING_STATUS } from '../db/enums' +import { Prisma, BookingStatus } from '@prisma/client' import fetch from './fetch' -export function getBookingStatus(status: BOOKING_STATUS) { +export function getBookingStatus(status: BookingStatus) { switch (status) { - case BOOKING_STATUS.REQUESTED: + case BookingStatus.REQUESTED: return 'Angefragt' - case BOOKING_STATUS.CONFIRMED: + case BookingStatus.CONFIRMED: return 'Bestätigt' - case BOOKING_STATUS.REJECTED: + case BookingStatus.REJECTED: return 'Abgewiesen' - case BOOKING_STATUS.CANCELED: + case BookingStatus.CANCELED: return 'Storniert' default: return 'Unbekannt - bitte kontaktieren Sie uns!' } } -export async function createBooking(formData: BookFormData) { +export async function createBooking(formData: Prisma.BookingCreateInput) { return fetch('/api/bookings', { method: 'POST', body: formData, @@ -27,13 +26,13 @@ export async function createBooking(formData: BookFormData) { export async function cancelBooking(uuid: string) { return fetch(`/api/bookings/${uuid}`, { method: 'PATCH', - body: { status: BOOKING_STATUS.CANCELED }, + body: { status: BookingStatus.CANCELED }, }) } export async function patchBooking( uuid: string, - bookingData: Partial + bookingData: Prisma.BookingUpdateInput ) { return fetch(`/api/bookings/${uuid}`, { method: 'PATCH', diff --git a/helpers/date.ts b/helpers/date.ts index 43014ad..6a3da61 100644 --- a/helpers/date.ts +++ b/helpers/date.ts @@ -1,4 +1,4 @@ -import { parse, format, addDays, subDays } from 'date-fns' +import { parse, format, addDays, subDays, differenceInDays } from 'date-fns' import { utcToZonedTime } from 'date-fns-tz' const FRONTEND_FORMAT = 'dd.MM.yyyy' @@ -23,18 +23,18 @@ export function getDays({ endDate, endDateExclusive = false, }: { - startDate: Date - endDate: Date + startDate: string, + endDate: string, endDateExclusive?: boolean }): string[] { - let currentDay = new Date(startDate.getTime()) + let currentDay = new Date(startDate); const days = [dateFormatBackend(currentDay)] if (!endDate) { return days } - const inclusiveEndDate = endDateExclusive ? subDays(endDate, 1) : endDate + const inclusiveEndDate = endDateExclusive ? subDays(new Date(endDate), 1) : new Date(endDate) while (currentDay < inclusiveEndDate) { currentDay = addDays(currentDay, 1) @@ -84,3 +84,8 @@ export function nowInTz(timezone = 'Europe/Berlin'): Date { export function getNextDay(date: Date) { return addDays(date, 1) } + +export function getDayCount({ startDate, endDate }: { startDate: string, endDate: string }) { + // TODO: check if this actually works as expected + return differenceInDays(new Date(startDate), new Date(endDate)) + 1 // add one as it only counts full days; +} diff --git a/helpers/ical.ts b/helpers/ical.ts index 637b91c..3020c9e 100644 --- a/helpers/ical.ts +++ b/helpers/ical.ts @@ -1,8 +1,7 @@ import { createEvents, createEvent, EventStatus } from 'ics' -import { Booking } from '../db/booking' -import { BOOKING_STATUS } from '../db/enums' +import { Booking, BookingStatus} from '@prisma/client'; import { getBaseURL } from './url' -import { daysFormatFrontend } from './date' +import { dateFormatFrontend, getDayCount } from './date' function convertDay(value: string): [number, number, number] { const parts = value.split('-') @@ -16,9 +15,9 @@ export function generateCalendarEntry(booking: Booking): string { const { error, value } = createEvent({ productId: 'app.vercel.pfadi-bussle/ics', title: `Pfadi-Bussle Buchung`, - start: convertDay(booking.days[0]), + start: convertDay(booking.startDate), startOutputType: 'local', - duration: { days: booking.days.length }, + duration: { days: getDayCount(booking) }, location: 'Mömpelgardgasse 25, 72348 Rosenfeld, Deutschland', geo: { lat: 48.287044, lon: 8.726361 }, description: `Gebucht auf ${booking.name} @@ -26,7 +25,7 @@ export function generateCalendarEntry(booking: Booking): string { Buchungs-Link: ${getBaseURL()}/bookings/${booking.uuid} `, status: - booking.status === BOOKING_STATUS.CONFIRMED + booking.status === BookingStatus.CONFIRMED ? ('CONFIRMED' as EventStatus) : ('TENTATIVE' as EventStatus), }) @@ -54,12 +53,12 @@ export function generateBookedCalendar(bookings: Booking[]): string { } => ({ productId: 'app.vercel.pfadi-bussle/ics', calName: 'Pfadi-Bussle Buchungen', - start: convertDay(booking.days[0]), + start: convertDay(booking.startDate), startOutputType: 'local', - duration: { days: booking.days.length }, + duration: { days: getDayCount(booking) }, title: `Buchung ${booking.name}`, description: `Name: ${booking.name} -Zeitraum: ${daysFormatFrontend(booking.days)} +Zeitraum: ${dateFormatFrontend(new Date(booking.startDate))}-${dateFormatFrontend(new Date(booking.endDate))} Email: ${booking.email} Telefon: ${booking.phone} @@ -67,7 +66,7 @@ Telefon: ${booking.phone} Link: ${getBaseURL()}/admin/bookings/${booking.uuid} `, status: - booking.status === BOOKING_STATUS.CONFIRMED + booking.status === BookingStatus.CONFIRMED ? ('CONFIRMED' as EventStatus) : ('TENTATIVE' as EventStatus), }) diff --git a/helpers/mail.ts b/helpers/mail.ts index 16a788a..24c9921 100644 --- a/helpers/mail.ts +++ b/helpers/mail.ts @@ -1,7 +1,7 @@ -import { Booking } from '../db/booking' +import { Booking, Prisma } from '@prisma/client'; import { getBaseURL } from '../helpers/url' import { log } from '../helpers/log' -import { daysFormatFrontend } from './date' +import { dateFormatFrontend } from './date' import { generateCalendarEntry } from './ical' import sgMail from '@sendgrid/mail' @@ -34,10 +34,11 @@ Tel. 0151/212 253 62 ${getBaseURL()} ` -function getReceivedBookingBookerText(booking: Booking): string { +function getReceivedBookingBookerText(booking: Prisma.BookingCreateInput): string { return `Hallo liebe/r ${booking.name}, -Vielen Dank für Deine Buchungsanfrage zum ${daysFormatFrontend(booking.days)}! +Vielen Dank für Deine Buchungsanfrage vom +${dateFormatFrontend(new Date(booking.startDate))} bis ${dateFormatFrontend(new Date(booking.endDate))} Nach Prüfung bestätigen wir die Buchung bald per E-Mail! @@ -54,9 +55,9 @@ ${footer} function getBookingConfirmedText(booking: Booking): string { return `Hallo liebe/r ${booking.name}, -deine Buchunganfrage zum ${daysFormatFrontend( - booking.days - )} bestätigen wir gerne! +deine Buchunganfrage vom +${dateFormatFrontend(new Date(booking.startDate))} bis ${dateFormatFrontend(new Date(booking.endDate))} +bestätigen wir gerne! Bitte melde dich spätestens 7 Tage vor dem Buchungstermin per E-Mail oder Telefon um eine Schlüsselübergabe zu vereinbaren. @@ -71,9 +72,9 @@ ${footer} function getBookingRejectedText(booking: Booking): string { return `Hallo liebe/r ${booking.name}, -es tut uns leid, aber deine Buchungsanfrage zum ${daysFormatFrontend( - booking.days - )} konnten wir leider nicht bestätigen. +es tut uns leid, aber deine Buchungsanfrage vom +${dateFormatFrontend(new Date(booking.startDate))} bis ${dateFormatFrontend(new Date(booking.endDate))} +konnten wir leider nicht bestätigen. Willst du das Bussle an einem anderen Termin buchen? Dann stelle bitte nochmal eine Buchungsanfrage auf ${getBaseURL()}. @@ -85,7 +86,9 @@ ${footer} function getBookingCanceledText(booking: Booking): string { return `Hallo liebe/r ${booking.name}, -deine Buchungsanfrage zum ${daysFormatFrontend(booking.days)} wurde storniert. +deine Buchungsanfrage vom +${dateFormatFrontend(new Date(booking.startDate))} bis ${dateFormatFrontend(new Date(booking.endDate))} +wurde storniert. Willst du das Bussle an einem anderen Termin buchen? Dann stelle bitte nochmal eine Buchungsanfrage auf ${getBaseURL()}. @@ -109,7 +112,7 @@ export async function sendReceivedBookingAdminMail( await sendMail({ to: [{ email: ADMIN_EMAIL }], from: { email: FROM_EMAIL, name: 'Pfadi-Bussle Wart' }, - subject: `Buchung für ${booking.days} eingegangen!`, + subject: `Buchung für ${booking.startDate}-${booking.endDate} eingegangen!`, textPlainContent: getReceivedBookingAdminText(booking), }) } catch (error) { @@ -118,7 +121,7 @@ export async function sendReceivedBookingAdminMail( } export async function sendReceivedBookingBookerMail( - booking: Booking + booking: Prisma.BookingCreateInput ): Promise { try { await sendMail({ diff --git a/helpers/storage.ts b/helpers/storage.ts index 2992922..fed8ae7 100644 --- a/helpers/storage.ts +++ b/helpers/storage.ts @@ -1,4 +1,4 @@ -import { Booking } from '../db/booking' +import { Booking } from '@prisma/client' import { log } from '../helpers/log' const BOOKING_DATA_KEY = 'pfadiBussleBookingData' diff --git a/lib/getServerSideProps.ts b/lib/getServerSideProps.ts index 5fdfd7a..f3a3203 100644 --- a/lib/getServerSideProps.ts +++ b/lib/getServerSideProps.ts @@ -1,39 +1,36 @@ +import { Booking } from '@prisma/client'; import { startOfYear } from 'date-fns' import { nowInTz } from '../helpers/date' import { getBookingByUUID, getBookings } from '../db/index' export type ServerSideBooking = { props: { - booking: object + booking: Booking } } export type ServerSideRecentBooking = { props: { - bookings: object[] + bookings: Booking[] } } export const getServerSideRecentBookings = - async (): Promise => { + async () => { const bookings = await getBookings({ startDateGreaterThan: startOfYear(nowInTz()).toISOString(), }) - // TODO: hack, not sure why _id is not serilizable - const bookingsJSON = JSON.parse( - JSON.stringify(bookings.map((b) => b.toJSON())) - ) as object[] return { props: { - bookings: bookingsJSON, + bookings: bookings, }, } } export const getServerSideBooking = async ( context: any -): Promise => { +) => { const { res, params: { uuid: uuids }, @@ -47,11 +44,7 @@ export const getServerSideBooking = async ( return { props: { booking: null } } } - await booking.populate('bill') - - // TODO: hack, not sure why _id is not serilizable - const bookingJSON = JSON.parse(JSON.stringify(booking.toJSON())) as object return { - props: { booking: bookingJSON }, + props: { booking }, } } diff --git a/lib/googlecalendar.ts b/lib/googlecalendar.ts index 6d49db7..abb7114 100644 --- a/lib/googlecalendar.ts +++ b/lib/googlecalendar.ts @@ -1,6 +1,6 @@ +import { Booking } from '@prisma/client'; import { google } from 'googleapis' import { getBaseURL } from '../helpers/url' -import { Booking } from '../db/booking' import { getDays, getNextDay, dateFormatBackend } from '../helpers/date' import { log } from '../helpers/log' @@ -39,15 +39,15 @@ export async function getBookedDays() { .filter((event) => !!event.start.date) .flatMap((event) => getDays({ - startDate: new Date(event.start.date), - endDate: new Date(event.end.date), + startDate: event.start.date, + endDate: event.end.date, endDateExclusive: true, }) ) ) } -function getSummary(booking: Partial): string { +function getSummary(booking: Booking): string { let summary = '' if (booking.org) { @@ -59,13 +59,13 @@ function getSummary(booking: Partial): string { return summary } -function getDescription(booking: Booking): string { +function getDescription(booking: Booking) { const bookingUrl = `${getBaseURL()}/admin/booking/${booking.uuid}` return `Managelink ${bookingUrl}` } -export async function createCalendarEvent(booking: Booking): Promise { +export async function createCalendarEvent(booking: Booking) { const exclusiveEndDate = dateFormatBackend( getNextDay(new Date(booking.endDate)) ) @@ -85,7 +85,7 @@ export async function createCalendarEvent(booking: Booking): Promise { return booking } -export async function deleteCalendarEvent(booking: Booking) { +export async function deleteCalendarEvent(booking: { calendarEventId: string }) { await calendar.events.delete({ calendarId, eventId: booking.calendarEventId, @@ -96,11 +96,11 @@ export async function deleteCalendarEvent(booking: Booking) { booking.calendarEventId = null } -//export async function patchCalendarEvent(booking: { calendarEventId: string } & Partial ) : Promise { -// const response = await calendar.events.patch({ -// calendarId, -// eventId: booking.calendarEventId, -// }); -// -// return booking; -//} +export async function patchCalendarEvent(booking: Booking ) { + await calendar.events.patch({ + calendarId, + eventId: booking.calendarEventId, + }); + + return booking; +} diff --git a/package-lock.json b/package-lock.json index 574a41f..3c105d3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,7 +8,8 @@ "name": "pfadi-bussle", "version": "0.1.0", "dependencies": { - "@next-auth/mongodb-adapter": "1.1.1", + "@next-auth/prisma-adapter": "^1.0.4", + "@prisma/client": "^4.4.0", "@sendgrid/mail": "7.7.0", "autoprefixer": "10.4.12", "classnames": "2.3.2", @@ -39,9 +40,10 @@ "postcss-flexbugs-fixes": "5.0.2", "postcss-preset-env": "7.8.2", "prettier": "2.7.1", + "prisma": "^4.4.0", "swr": "1.3.0", "tailwindcss": "3.1.8", - "ts-jest": "29.0.3" + "ts-jest": "^29.0.3" } }, "node_modules/@ampproject/remapping": { @@ -643,9 +645,9 @@ "dev": true }, "node_modules/@csstools/postcss-cascade-layers": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@csstools/postcss-cascade-layers/-/postcss-cascade-layers-1.1.0.tgz", - "integrity": "sha512-XpA7g2KViA2ia23A5kZ/EQw+Sy308kLbvMlDPjFZmojwaJ9DYdJuwujFcDGK9v1QhHRmMEHbV2brVSQSLkN/7A==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-cascade-layers/-/postcss-cascade-layers-1.1.1.tgz", + "integrity": "sha512-+KdYrpKC5TgomQr2DlZF4lDEpHcoxnj5IGddYYfBWJAKfj1JtuHUIqMa+E1pJJ+z3kvDViWMqyqPlG4Ja7amQA==", "dev": true, "dependencies": { "@csstools/selector-specificity": "^2.0.2", @@ -953,9 +955,9 @@ "dev": true }, "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "13.15.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.15.0.tgz", - "integrity": "sha512-bpzcOlgDhMG070Av0Vy5Owklpv1I6+j96GhUI7Rh7IzDCKLzboflLrrfqMu8NquDbiR4EOQk7XzJwqVJxicxog==", + "version": "13.17.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz", + "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==", "dev": true, "dependencies": { "type-fest": "^0.20.2" @@ -992,9 +994,9 @@ } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.10.5", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.5.tgz", - "integrity": "sha512-XVVDtp+dVvRxMoxSiSfasYaG02VEe1qH5cKgMQJWhol6HwzbcqoCMJi8dAGoYAO57jhUyhI6cWuRiTcRaDaYug==", + "version": "0.10.7", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.7.tgz", + "integrity": "sha512-MDl6D6sBsaV452/QSdX+4CXIjZhIcI0PELsxUjk4U828yd58vk3bTIvk/6w5FY+4hIy9sLW0sfrV7K7Kc++j/w==", "dev": true, "dependencies": { "@humanwhocodes/object-schema": "^1.2.1", @@ -1419,12 +1421,12 @@ "react": ">=16" } }, - "node_modules/@next-auth/mongodb-adapter": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@next-auth/mongodb-adapter/-/mongodb-adapter-1.1.1.tgz", - "integrity": "sha512-X5O4U4l2M8nyp/B3qF5GOr/JJw2ShKgWfTZRa80Y5CUzTPPmf09ggL5v5UwCmz9l2RIv2GUxO8hK4qrcaZvDRw==", + "node_modules/@next-auth/prisma-adapter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@next-auth/prisma-adapter/-/prisma-adapter-1.0.4.tgz", + "integrity": "sha512-jIOM6CzCbl2/Mzbx9kb2IjtHoJOeRN9wtQgLk4EUm5bhneSVGv1rtz5TDskvp2UfCa+EK9nDmug+lje41z80Gg==", "peerDependencies": { - "mongodb": "^4.1.1", + "@prisma/client": ">=2.26.0 || >=3", "next-auth": "^4" } }, @@ -1700,6 +1702,38 @@ "url": "https://github.com/sponsors/panva" } }, + "node_modules/@prisma/client": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@prisma/client/-/client-4.4.0.tgz", + "integrity": "sha512-ciKOP246x1xwr04G9ajHlJ4pkmtu9Q6esVyqVBO0QJihaKQIUvbPjClp17IsRJyxqNpFm4ScbOc/s9DUzKHINQ==", + "hasInstallScript": true, + "dependencies": { + "@prisma/engines-version": "4.4.0-66.f352a33b70356f46311da8b00d83386dd9f145d6" + }, + "engines": { + "node": ">=14.17" + }, + "peerDependencies": { + "prisma": "*" + }, + "peerDependenciesMeta": { + "prisma": { + "optional": true + } + } + }, + "node_modules/@prisma/engines": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-4.4.0.tgz", + "integrity": "sha512-Fpykccxlt9MHrAs/QpPGpI2nOiRxuLA+LiApgA59ibbf24YICZIMWd3SI2YD+q0IAIso0jCGiHhirAIbxK3RyQ==", + "devOptional": true, + "hasInstallScript": true + }, + "node_modules/@prisma/engines-version": { + "version": "4.4.0-66.f352a33b70356f46311da8b00d83386dd9f145d6", + "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-4.4.0-66.f352a33b70356f46311da8b00d83386dd9f145d6.tgz", + "integrity": "sha512-P5v/PuEIJLYXZUZBvOLPqoyCW+m6StNqHdiR6te++gYVODpPdLakks5HVx3JaZIY+LwR02juJWFlwpc9Eog/ug==" + }, "node_modules/@rushstack/eslint-patch": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.1.3.tgz", @@ -2717,9 +2751,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001407", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001407.tgz", - "integrity": "sha512-4ydV+t4P7X3zH83fQWNDX/mQEzYomossfpViCOx9zHBSMV+rIe3LFqglHHtVyvNl1FhTNxPxs3jei82iqOW04w==", + "version": "1.0.30001418", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001418.tgz", + "integrity": "sha512-oIs7+JL3K9JRQ3jPZjlH6qyYDp+nBTCais7hjh0s+fuBwufc7uZ7hPYMXrDOJhV360KGMTcczMRObk0/iMqZRg==", "funding": [ { "type": "opencollective", @@ -2846,14 +2880,17 @@ "integrity": "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==" }, "node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "dev": true, "dependencies": { "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", + "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" } }, "node_modules/co": { @@ -3225,9 +3262,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.256", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.256.tgz", - "integrity": "sha512-x+JnqyluoJv8I0U9gVe+Sk2st8vF0CzMt78SXxuoWCooLLY2k5VerIBdpvG7ql6GKI4dzNnPjmqgDJ76EdaAKw==" + "version": "1.4.276", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.276.tgz", + "integrity": "sha512-EpuHPqu8YhonqLBXHoU6hDJCD98FCe6KDoet3/gY1qsQ6usjJoHqBH2YIVs8FXaAtHwVL8Uqa/fsYao/vq9VWQ==" }, "node_modules/emittery": { "version": "0.10.2", @@ -3257,22 +3294,22 @@ } }, "node_modules/es-abstract": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.2.tgz", - "integrity": "sha512-XxXQuVNrySBNlEkTYJoDNFe5+s2yIOpzq80sUHEdPdQr0S5nTLz4ZPPPswNIpKseDDUS5yghX1gfLIHQZ1iNuQ==", + "version": "1.20.4", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.4.tgz", + "integrity": "sha512-0UtvRN79eMe2L+UNEF1BwRe364sj/DXhQ/k5FmivgoSdpM90b8Jc0mDzKMGo7QS0BVbOP/bTwBKNnDc9rNzaPA==", "dev": true, "dependencies": { "call-bind": "^1.0.2", "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", "function.prototype.name": "^1.1.5", - "get-intrinsic": "^1.1.2", + "get-intrinsic": "^1.1.3", "get-symbol-description": "^1.0.0", "has": "^1.0.3", "has-property-descriptors": "^1.0.0", "has-symbols": "^1.0.3", "internal-slot": "^1.0.3", - "is-callable": "^1.2.4", + "is-callable": "^1.2.7", "is-negative-zero": "^2.0.2", "is-regex": "^1.1.4", "is-shared-array-buffer": "^1.0.2", @@ -3282,6 +3319,7 @@ "object-keys": "^1.1.1", "object.assign": "^4.1.4", "regexp.prototype.flags": "^1.4.3", + "safe-regex-test": "^1.0.0", "string.prototype.trimend": "^1.0.5", "string.prototype.trimstart": "^1.0.5", "unbox-primitive": "^1.0.2" @@ -3644,9 +3682,9 @@ "dev": true }, "node_modules/eslint-plugin-react": { - "version": "7.31.8", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.31.8.tgz", - "integrity": "sha512-5lBTZmgQmARLLSYiwI71tiGVTLUuqXantZM6vlSY39OaDSV0M7+32K5DnLkmFrwTe+Ksz0ffuLUC91RUviVZfw==", + "version": "7.31.10", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.31.10.tgz", + "integrity": "sha512-e4N/nc6AAlg4UKW/mXeYWd3R++qUano5/o+t+wnWxIf+bLsOaH3a4q74kX3nDjYym3VBN4HyO9nEn1GcAqgQOA==", "dev": true, "dependencies": { "array-includes": "^3.1.5", @@ -3695,34 +3733,18 @@ "node": ">=0.10.0" } }, - "node_modules/eslint-plugin-react/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/eslint-plugin-react/node_modules/prop-types": { - "version": "15.8.1", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", - "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "dev": true, - "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - } - }, "node_modules/eslint-plugin-react/node_modules/resolve": { - "version": "2.0.0-next.3", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.3.tgz", - "integrity": "sha512-W8LucSynKUIDu9ylraa7ueVZ7hc0uAgJBxVsQSKOXOyle8a93qXhcz+XAXZ8bIq2d6i4Ehddn6Evt+0/UwKk6Q==", + "version": "2.0.0-next.4", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz", + "integrity": "sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==", "dev": true, "dependencies": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -3983,9 +4005,9 @@ } }, "node_modules/estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, "engines": { "node": ">=4.0" @@ -4092,7 +4114,7 @@ "node_modules/exit": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", "dev": true, "engines": { "node": ">= 0.8.0" @@ -4952,9 +4974,9 @@ } }, "node_modules/is-callable": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", - "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", "dev": true, "engines": { "node": ">= 0.4" @@ -8453,6 +8475,23 @@ "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", "dev": true }, + "node_modules/prisma": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/prisma/-/prisma-4.4.0.tgz", + "integrity": "sha512-l/QKLmLcKJQFuc+X02LyICo0NWTUVaNNZ00jKJBqwDyhwMAhboD1FWwYV50rkH4Wls0RviAJSFzkC2ZrfawpfA==", + "devOptional": true, + "hasInstallScript": true, + "dependencies": { + "@prisma/engines": "4.4.0" + }, + "bin": { + "prisma": "build/index.js", + "prisma2": "build/index.js" + }, + "engines": { + "node": ">=14.17" + } + }, "node_modules/prompts": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", @@ -8467,13 +8506,13 @@ } }, "node_modules/prop-types": { - "version": "15.7.2", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", - "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", - "react-is": "^16.8.1" + "react-is": "^16.13.1" } }, "node_modules/property-expr": { @@ -8690,7 +8729,7 @@ "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "dev": true, "engines": { "node": ">=0.10.0" @@ -8807,6 +8846,20 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, + "node_modules/safe-regex-test": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", + "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/saslprep": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.3.tgz", @@ -9622,9 +9675,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.9.tgz", - "integrity": "sha512-/xsqn21EGVdXI3EXSum1Yckj3ZVZugqyOZQ/CxYPBD/R+ko9NSUScf8tFF4dOKY+2pvSSJA/S+5B8s4Zr4kyvg==", + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", + "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", "funding": [ { "type": "opencollective", @@ -9922,12 +9975,12 @@ } }, "node_modules/yargs": { - "version": "17.4.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.4.1.tgz", - "integrity": "sha512-WSZD9jgobAg3ZKuCQZSa3g9QOJeCCqLoLAykiWgmXnDo9EPnn4RPf5qVTtzgOx66o6/oqhcA5tHtJXpG8pMt3g==", + "version": "17.6.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.0.tgz", + "integrity": "sha512-8H/wTDqlSwoSnScvV2N/JHfLWOKuh5MVla9hqLjK3nsfyy6Y4kDSYSvkU5YCUEPOSnRXfIyx3Sq+B/IWudTo4g==", "dev": true, "dependencies": { - "cliui": "^7.0.2", + "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", @@ -10439,9 +10492,9 @@ "dev": true }, "@csstools/postcss-cascade-layers": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@csstools/postcss-cascade-layers/-/postcss-cascade-layers-1.1.0.tgz", - "integrity": "sha512-XpA7g2KViA2ia23A5kZ/EQw+Sy308kLbvMlDPjFZmojwaJ9DYdJuwujFcDGK9v1QhHRmMEHbV2brVSQSLkN/7A==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-cascade-layers/-/postcss-cascade-layers-1.1.1.tgz", + "integrity": "sha512-+KdYrpKC5TgomQr2DlZF4lDEpHcoxnj5IGddYYfBWJAKfj1JtuHUIqMa+E1pJJ+z3kvDViWMqyqPlG4Ja7amQA==", "dev": true, "requires": { "@csstools/selector-specificity": "^2.0.2", @@ -10598,9 +10651,9 @@ "dev": true }, "globals": { - "version": "13.15.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.15.0.tgz", - "integrity": "sha512-bpzcOlgDhMG070Av0Vy5Owklpv1I6+j96GhUI7Rh7IzDCKLzboflLrrfqMu8NquDbiR4EOQk7XzJwqVJxicxog==", + "version": "13.17.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz", + "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==", "dev": true, "requires": { "type-fest": "^0.20.2" @@ -10624,9 +10677,9 @@ } }, "@humanwhocodes/config-array": { - "version": "0.10.5", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.5.tgz", - "integrity": "sha512-XVVDtp+dVvRxMoxSiSfasYaG02VEe1qH5cKgMQJWhol6HwzbcqoCMJi8dAGoYAO57jhUyhI6cWuRiTcRaDaYug==", + "version": "0.10.7", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.7.tgz", + "integrity": "sha512-MDl6D6sBsaV452/QSdX+4CXIjZhIcI0PELsxUjk4U828yd58vk3bTIvk/6w5FY+4hIy9sLW0sfrV7K7Kc++j/w==", "dev": true, "requires": { "@humanwhocodes/object-schema": "^1.2.1", @@ -10957,10 +11010,10 @@ "@types/react": ">=16" } }, - "@next-auth/mongodb-adapter": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@next-auth/mongodb-adapter/-/mongodb-adapter-1.1.1.tgz", - "integrity": "sha512-X5O4U4l2M8nyp/B3qF5GOr/JJw2ShKgWfTZRa80Y5CUzTPPmf09ggL5v5UwCmz9l2RIv2GUxO8hK4qrcaZvDRw==", + "@next-auth/prisma-adapter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@next-auth/prisma-adapter/-/prisma-adapter-1.0.4.tgz", + "integrity": "sha512-jIOM6CzCbl2/Mzbx9kb2IjtHoJOeRN9wtQgLk4EUm5bhneSVGv1rtz5TDskvp2UfCa+EK9nDmug+lje41z80Gg==", "requires": {} }, "@next/env": { @@ -11102,6 +11155,25 @@ "resolved": "https://registry.npmjs.org/@panva/hkdf/-/hkdf-1.0.1.tgz", "integrity": "sha512-mMyQ9vjpuFqePkfe5bZVIf/H3Dmk6wA8Kjxff9RcO4kqzJo+Ek9pGKwZHpeMr7Eku0QhLXMCd7fNCSnEnRMubg==" }, + "@prisma/client": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@prisma/client/-/client-4.4.0.tgz", + "integrity": "sha512-ciKOP246x1xwr04G9ajHlJ4pkmtu9Q6esVyqVBO0QJihaKQIUvbPjClp17IsRJyxqNpFm4ScbOc/s9DUzKHINQ==", + "requires": { + "@prisma/engines-version": "4.4.0-66.f352a33b70356f46311da8b00d83386dd9f145d6" + } + }, + "@prisma/engines": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-4.4.0.tgz", + "integrity": "sha512-Fpykccxlt9MHrAs/QpPGpI2nOiRxuLA+LiApgA59ibbf24YICZIMWd3SI2YD+q0IAIso0jCGiHhirAIbxK3RyQ==", + "devOptional": true + }, + "@prisma/engines-version": { + "version": "4.4.0-66.f352a33b70356f46311da8b00d83386dd9f145d6", + "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-4.4.0-66.f352a33b70356f46311da8b00d83386dd9f145d6.tgz", + "integrity": "sha512-P5v/PuEIJLYXZUZBvOLPqoyCW+m6StNqHdiR6te++gYVODpPdLakks5HVx3JaZIY+LwR02juJWFlwpc9Eog/ug==" + }, "@rushstack/eslint-patch": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.1.3.tgz", @@ -11874,9 +11946,9 @@ "dev": true }, "caniuse-lite": { - "version": "1.0.30001407", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001407.tgz", - "integrity": "sha512-4ydV+t4P7X3zH83fQWNDX/mQEzYomossfpViCOx9zHBSMV+rIe3LFqglHHtVyvNl1FhTNxPxs3jei82iqOW04w==" + "version": "1.0.30001418", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001418.tgz", + "integrity": "sha512-oIs7+JL3K9JRQ3jPZjlH6qyYDp+nBTCais7hjh0s+fuBwufc7uZ7hPYMXrDOJhV360KGMTcczMRObk0/iMqZRg==" }, "ccount": { "version": "2.0.1", @@ -11953,13 +12025,13 @@ "integrity": "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==" }, "cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "dev": true, "requires": { "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", + "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, @@ -12217,9 +12289,9 @@ } }, "electron-to-chromium": { - "version": "1.4.256", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.256.tgz", - "integrity": "sha512-x+JnqyluoJv8I0U9gVe+Sk2st8vF0CzMt78SXxuoWCooLLY2k5VerIBdpvG7ql6GKI4dzNnPjmqgDJ76EdaAKw==" + "version": "1.4.276", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.276.tgz", + "integrity": "sha512-EpuHPqu8YhonqLBXHoU6hDJCD98FCe6KDoet3/gY1qsQ6usjJoHqBH2YIVs8FXaAtHwVL8Uqa/fsYao/vq9VWQ==" }, "emittery": { "version": "0.10.2", @@ -12243,22 +12315,22 @@ } }, "es-abstract": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.2.tgz", - "integrity": "sha512-XxXQuVNrySBNlEkTYJoDNFe5+s2yIOpzq80sUHEdPdQr0S5nTLz4ZPPPswNIpKseDDUS5yghX1gfLIHQZ1iNuQ==", + "version": "1.20.4", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.4.tgz", + "integrity": "sha512-0UtvRN79eMe2L+UNEF1BwRe364sj/DXhQ/k5FmivgoSdpM90b8Jc0mDzKMGo7QS0BVbOP/bTwBKNnDc9rNzaPA==", "dev": true, "requires": { "call-bind": "^1.0.2", "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", "function.prototype.name": "^1.1.5", - "get-intrinsic": "^1.1.2", + "get-intrinsic": "^1.1.3", "get-symbol-description": "^1.0.0", "has": "^1.0.3", "has-property-descriptors": "^1.0.0", "has-symbols": "^1.0.3", "internal-slot": "^1.0.3", - "is-callable": "^1.2.4", + "is-callable": "^1.2.7", "is-negative-zero": "^2.0.2", "is-regex": "^1.1.4", "is-shared-array-buffer": "^1.0.2", @@ -12268,6 +12340,7 @@ "object-keys": "^1.1.1", "object.assign": "^4.1.4", "regexp.prototype.flags": "^1.4.3", + "safe-regex-test": "^1.0.0", "string.prototype.trimend": "^1.0.5", "string.prototype.trimstart": "^1.0.5", "unbox-primitive": "^1.0.2" @@ -12638,9 +12711,9 @@ } }, "eslint-plugin-react": { - "version": "7.31.8", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.31.8.tgz", - "integrity": "sha512-5lBTZmgQmARLLSYiwI71tiGVTLUuqXantZM6vlSY39OaDSV0M7+32K5DnLkmFrwTe+Ksz0ffuLUC91RUviVZfw==", + "version": "7.31.10", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.31.10.tgz", + "integrity": "sha512-e4N/nc6AAlg4UKW/mXeYWd3R++qUano5/o+t+wnWxIf+bLsOaH3a4q74kX3nDjYym3VBN4HyO9nEn1GcAqgQOA==", "dev": true, "requires": { "array-includes": "^3.1.5", @@ -12668,31 +12741,15 @@ "esutils": "^2.0.2" } }, - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - }, - "prop-types": { - "version": "15.8.1", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", - "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "dev": true, - "requires": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - } - }, "resolve": { - "version": "2.0.0-next.3", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.3.tgz", - "integrity": "sha512-W8LucSynKUIDu9ylraa7ueVZ7hc0uAgJBxVsQSKOXOyle8a93qXhcz+XAXZ8bIq2d6i4Ehddn6Evt+0/UwKk6Q==", + "version": "2.0.0-next.4", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz", + "integrity": "sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==", "dev": true, "requires": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" } }, "semver": { @@ -12787,9 +12844,9 @@ } }, "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true }, "estree-util-attach-comments": { @@ -12867,7 +12924,7 @@ "exit": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", "dev": true }, "expect": { @@ -13486,9 +13543,9 @@ "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==" }, "is-callable": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", - "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", "dev": true }, "is-core-module": { @@ -15831,6 +15888,15 @@ } } }, + "prisma": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/prisma/-/prisma-4.4.0.tgz", + "integrity": "sha512-l/QKLmLcKJQFuc+X02LyICo0NWTUVaNNZ00jKJBqwDyhwMAhboD1FWwYV50rkH4Wls0RviAJSFzkC2ZrfawpfA==", + "devOptional": true, + "requires": { + "@prisma/engines": "4.4.0" + } + }, "prompts": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", @@ -15842,13 +15908,13 @@ } }, "prop-types": { - "version": "15.7.2", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", - "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", "requires": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", - "react-is": "^16.8.1" + "react-is": "^16.13.1" } }, "property-expr": { @@ -15992,7 +16058,7 @@ "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "dev": true }, "resolve": { @@ -16064,6 +16130,17 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, + "safe-regex-test": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", + "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" + } + }, "saslprep": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.3.tgz", @@ -16641,9 +16718,9 @@ } }, "update-browserslist-db": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.9.tgz", - "integrity": "sha512-/xsqn21EGVdXI3EXSum1Yckj3ZVZugqyOZQ/CxYPBD/R+ko9NSUScf8tFF4dOKY+2pvSSJA/S+5B8s4Zr4kyvg==", + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", + "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", "requires": { "escalade": "^3.1.1", "picocolors": "^1.0.0" @@ -16861,12 +16938,12 @@ "dev": true }, "yargs": { - "version": "17.4.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.4.1.tgz", - "integrity": "sha512-WSZD9jgobAg3ZKuCQZSa3g9QOJeCCqLoLAykiWgmXnDo9EPnn4RPf5qVTtzgOx66o6/oqhcA5tHtJXpG8pMt3g==", + "version": "17.6.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.0.tgz", + "integrity": "sha512-8H/wTDqlSwoSnScvV2N/JHfLWOKuh5MVla9hqLjK3nsfyy6Y4kDSYSvkU5YCUEPOSnRXfIyx3Sq+B/IWudTo4g==", "dev": true, "requires": { - "cliui": "^7.0.2", + "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", diff --git a/package.json b/package.json index 4e88e75..385ac6f 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,8 @@ "test": "jest" }, "dependencies": { - "@next-auth/mongodb-adapter": "1.1.1", + "@next-auth/prisma-adapter": "^1.0.4", + "@prisma/client": "^4.4.0", "@sendgrid/mail": "7.7.0", "autoprefixer": "10.4.12", "classnames": "2.3.2", @@ -38,13 +39,14 @@ "eslint-config-next": "12.3.1", "eslint-config-prettier": "8.5.0", "jest": "29.1.2", - "ts-jest": "29.0.3", "postcss": "8.4.17", "postcss-flexbugs-fixes": "5.0.2", "postcss-preset-env": "7.8.2", "prettier": "2.7.1", + "prisma": "^4.4.0", "swr": "1.3.0", - "tailwindcss": "3.1.8" + "tailwindcss": "3.1.8", + "ts-jest": "^29.0.3" }, "jest": { "transform": { diff --git a/pages/admin/bookings/[uuid]/bill.tsx b/pages/admin/bookings/[uuid]/bill.tsx index fc2e7f0..03aeecf 100644 --- a/pages/admin/bookings/[uuid]/bill.tsx +++ b/pages/admin/bookings/[uuid]/bill.tsx @@ -1,10 +1,10 @@ import React, { useEffect, useState } from 'react' import Input from '../../../../components/input' import Select from '../../../../components/select' -import { Booking } from '../../../../db/booking' -import { BILL_STATUS, MILAGE_TARIFS } from '../../../../db/enums' +import { Booking, Bill, BillStatus, AdditionalCosts, Prisma } from '@prisma/client' +import { MILAGE_TARIFS } from '../../../../db/enums' import { getMilageMax } from '../../../../db/index' -import { daysFormatFrontend } from '../../../../helpers/date' +import { dateFormatFrontend } from '../../../../helpers/date' import { log } from '../../../../helpers/log' import { getBillTotal, createBill, patchBill } from '../../../../helpers/bill' import { getBookingStatus } from '../../../../helpers/booking' @@ -29,7 +29,7 @@ const milageTarifOptions = Object.values(MILAGE_TARIFS).map((tarif) => { ) }) -const billStatusOptions = Object.values(BILL_STATUS).map((status) => { +const billStatusOptions = Object.values(BillStatus).map((status) => { return (