mirror of
https://github.com/tomru/pfadi-bussle.git
synced 2026-03-03 06:27:11 +01:00
switch to prisma
This commit is contained in:
@@ -1,17 +1,18 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
|
|
||||||
import { daysFormatFrontend } from '../helpers/date'
|
import {Booking} from '@prisma/client';
|
||||||
import { BookingDocument } from '../db/booking'
|
import { dateFormatFrontend } from '../helpers/date'
|
||||||
|
|
||||||
|
|
||||||
export default function BookingTable({
|
export default function BookingTable({
|
||||||
booking,
|
booking,
|
||||||
}: {
|
}: {
|
||||||
booking: BookingDocument
|
booking: Booking
|
||||||
}) {
|
}) {
|
||||||
const data = [
|
const data = [
|
||||||
{ name: 'Status', value: booking.status },
|
{ 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: 'Organisation', value: booking.org },
|
||||||
{
|
{
|
||||||
name: 'Addresse',
|
name: 'Addresse',
|
||||||
@@ -48,7 +49,7 @@ export default function BookingTable({
|
|||||||
</h3>
|
</h3>
|
||||||
<p className="mt-1 max-w-2xl text-sm text-gray-500">
|
<p className="mt-1 max-w-2xl text-sm text-gray-500">
|
||||||
Last updated{' '}
|
Last updated{' '}
|
||||||
{new Date(booking.updatedAt as string).toLocaleString(
|
{booking.updatedAt.toLocaleString(
|
||||||
new Intl.Locale('de')
|
new Intl.Locale('de')
|
||||||
)}
|
)}
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -1,20 +1,18 @@
|
|||||||
import React, { useEffect, useReducer } from 'react'
|
import React, { useEffect, useReducer } from 'react'
|
||||||
|
import { Prisma } from '@prisma/client'
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import { clearBookingData, loadBookingData } from '../helpers/storage'
|
import { clearBookingData, loadBookingData } from '../helpers/storage'
|
||||||
import { log } from '../helpers/log'
|
import { log } from '../helpers/log'
|
||||||
|
|
||||||
import { createBooking } from '../helpers/booking'
|
import { createBooking } from '../helpers/booking'
|
||||||
import { Booking } from '../db/booking'
|
|
||||||
|
|
||||||
export type BookFormData = Omit<Booking, 'uuid' | 'calendarEventId'>
|
|
||||||
|
|
||||||
type BookingProviderState = {
|
type BookingProviderState = {
|
||||||
postData?: boolean
|
postData?: boolean
|
||||||
postDataError?: string
|
postDataError?: string
|
||||||
postDataSuccess?: boolean
|
postDataSuccess?: boolean
|
||||||
formData: BookFormData
|
formData: Prisma.BookingCreateInput,
|
||||||
formDataChanged: string[]
|
formDataChanged: string[]
|
||||||
booking?: Booking
|
booking?: Prisma.BookingCreateInput,
|
||||||
dataStored: boolean
|
dataStored: boolean
|
||||||
dataStoredLoaded: boolean
|
dataStoredLoaded: boolean
|
||||||
}
|
}
|
||||||
|
|||||||
91
db/bill.ts
91
db/bill.ts
@@ -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<BillDocument>
|
|
||||||
|
|
||||||
const BillSchema = new mongoose.Schema<BillDocument>(
|
|
||||||
{
|
|
||||||
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<BillDocument, BillModel>('Bill', BillSchema)) as BillModel
|
|
||||||
168
db/booking.ts
168
db/booking.ts
@@ -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<BookingDocument> & {
|
|
||||||
findBookedDays(uuidsToIngore?: string[]): Promise<string[]>
|
|
||||||
}
|
|
||||||
|
|
||||||
const BookingSchema = new mongoose.Schema<BookingDocument>(
|
|
||||||
{
|
|
||||||
// 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<boolean> {
|
|
||||||
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<void> {
|
|
||||||
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<string[]> {
|
|
||||||
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<BookingDocument, BookingModel>(
|
|
||||||
'Booking',
|
|
||||||
BookingSchema
|
|
||||||
)) as BookingModel
|
|
||||||
|
|
||||||
export default BookingModel
|
|
||||||
13
db/enums.ts
13
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 {
|
export enum MILAGE_TARIFS {
|
||||||
INTERN = 'intern',
|
INTERN = 'intern',
|
||||||
EXTERN = 'extern',
|
EXTERN = 'extern',
|
||||||
|
|||||||
200
db/index.ts
200
db/index.ts
@@ -1,129 +1,121 @@
|
|||||||
import * as mongoose from 'mongoose'
|
import { BookingStatus, Booking, PrismaClient, Prisma } from '@prisma/client'
|
||||||
import BookingModel, { Booking, BookingDocument } from './booking'
|
|
||||||
import BillModel, { Bill } from './bill'
|
const prisma = new PrismaClient()
|
||||||
|
|
||||||
import { getBookedDays as calendarGetBookedDays } from '../lib/googlecalendar'
|
import { getBookedDays as calendarGetBookedDays } from '../lib/googlecalendar'
|
||||||
import { BOOKING_STATUS } from './enums'
|
|
||||||
import { uniqueFilter } from '../helpers/array'
|
import { uniqueFilter } from '../helpers/array'
|
||||||
|
import { dateFormatBackend, getDays, nowInTz } from '../helpers/date'
|
||||||
export const MONGO_URI = process.env.MONGO_URI
|
|
||||||
|
|
||||||
mongoose.connect(process.env.MONGO_URI, {
|
|
||||||
serverSelectionTimeoutMS: 3000,
|
|
||||||
})
|
|
||||||
|
|
||||||
export async function getBookedDays(
|
export async function getBookedDays(
|
||||||
uuidsToIngore?: string[]
|
uuidsToIngore?: string[]
|
||||||
): Promise<string[]> {
|
) {
|
||||||
const [bookedInDatabase, bookedInCalendar] = await Promise.all([
|
const [bookingsInDbRaw, bookingsInCalendar] = await Promise.all([
|
||||||
BookingModel.findBookedDays(uuidsToIngore),
|
prisma.booking.findMany({
|
||||||
|
where: {
|
||||||
|
uuid: { notIn: uuidsToIngore },
|
||||||
|
startDate: { gte: dateFormatBackend(nowInTz()) },
|
||||||
|
status: { notIn: [BookingStatus.REJECTED, BookingStatus.CANCELED] }
|
||||||
|
},
|
||||||
|
select: {
|
||||||
|
startDate: true,
|
||||||
|
endDate: true,
|
||||||
|
},
|
||||||
|
}),
|
||||||
calendarGetBookedDays(),
|
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<BookingDocument> {
|
export function getBookingByUUID(uuid: string) {
|
||||||
return BookingModel.findOne({ uuid })
|
// TODO: can we ignore canceled and rejected ones ?
|
||||||
|
return prisma.booking.findUniqueOrThrow({
|
||||||
|
where: {
|
||||||
|
uuid,
|
||||||
|
},
|
||||||
|
include: {
|
||||||
|
bill: true
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getBookings({
|
export function getBookings({
|
||||||
status = [BOOKING_STATUS.CONFIRMED, BOOKING_STATUS.REQUESTED],
|
status = [
|
||||||
|
BookingStatus.REQUESTED,
|
||||||
|
BookingStatus.CONFIRMED,
|
||||||
|
],
|
||||||
startDateGreaterThan = '2000-01-01T00:00:00Z',
|
startDateGreaterThan = '2000-01-01T00:00:00Z',
|
||||||
}: { status?: BOOKING_STATUS[]; startDateGreaterThan?: string } = {}): Promise<
|
}
|
||||||
BookingDocument[]
|
: { status?: BookingStatus[]; startDateGreaterThan?: string } = {}) {
|
||||||
> {
|
return prisma.booking.findMany({
|
||||||
return await BookingModel.find({
|
where: {
|
||||||
status: { $in: status },
|
startDate: { gte: startDateGreaterThan },
|
||||||
startDate: { $gte: startDateGreaterThan },
|
status: { notIn: status }
|
||||||
})
|
},
|
||||||
.sort({ startDate: -1 })
|
});
|
||||||
.exec()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function createBooking({
|
export function createBooking(data: Booking) {
|
||||||
startDate,
|
return prisma.booking.create({
|
||||||
endDate,
|
data
|
||||||
purpose,
|
});
|
||||||
org,
|
|
||||||
destination,
|
|
||||||
name,
|
|
||||||
email,
|
|
||||||
phone,
|
|
||||||
street,
|
|
||||||
zip,
|
|
||||||
city,
|
|
||||||
}: Booking): Promise<Booking> {
|
|
||||||
const booking = new BookingModel({
|
|
||||||
startDate,
|
|
||||||
endDate,
|
|
||||||
purpose,
|
|
||||||
org,
|
|
||||||
destination,
|
|
||||||
name,
|
|
||||||
email,
|
|
||||||
phone,
|
|
||||||
street,
|
|
||||||
zip,
|
|
||||||
city,
|
|
||||||
})
|
|
||||||
|
|
||||||
await booking.save()
|
|
||||||
return booking.toJSON<Booking>()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function patchBooking(
|
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,
|
bookingUUID: string,
|
||||||
bookingData: Booking
|
data: Prisma.BillCreateInput,
|
||||||
): Promise<{ current: Booking; previous: Booking }> {
|
) {
|
||||||
const booking = await getBookingByUUID(bookingUUID)
|
return prisma.bill.create({
|
||||||
const oldBooking = booking.toJSON<Booking>()
|
data: {
|
||||||
booking.set(bookingData)
|
...data,
|
||||||
await booking.save()
|
booking: {
|
||||||
|
connect: { uuid: bookingUUID }
|
||||||
return { current: booking.toJSON<Booking>(), previous: oldBooking }
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function createBill(
|
export function patchBill(
|
||||||
bookingUUID: string,
|
bookingUUID: string,
|
||||||
billData: Bill
|
data: Prisma.BillUncheckedUpdateInput,
|
||||||
): Promise<Bill> {
|
) {
|
||||||
const booking = await getBookingByUUID(bookingUUID)
|
const { id, ...rest } = data;
|
||||||
|
return prisma.bill.update({
|
||||||
const bill = new BillModel()
|
where: {
|
||||||
bill.set(billData)
|
},
|
||||||
|
data: {
|
||||||
await bill.save()
|
...rest,
|
||||||
|
booking: {
|
||||||
booking.bill = bill._id
|
connect: { uuid: bookingUUID }
|
||||||
await booking.save()
|
}
|
||||||
|
}
|
||||||
return bill.toJSON<Bill>()
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function patchBill(
|
export async function getMilageMax() {
|
||||||
bookingUUID: string,
|
const { milageEnd } = await prisma.bill.findFirst({
|
||||||
billData: Bill
|
select: { milageEnd: true },
|
||||||
): Promise<Bill> {
|
orderBy: [
|
||||||
const booking = await getBookingByUUID(bookingUUID)
|
{
|
||||||
const bill =
|
milageEnd: 'desc',
|
||||||
(booking.bill && (await BillModel.findById(booking.bill))) ||
|
},
|
||||||
(await BillModel.create({}))
|
],
|
||||||
|
});
|
||||||
|
|
||||||
bill.set(billData)
|
return milageEnd || 0;
|
||||||
await bill.save()
|
|
||||||
|
|
||||||
if (booking.bill !== bill._id) {
|
|
||||||
booking.bill = bill._id
|
|
||||||
await booking.save()
|
|
||||||
}
|
|
||||||
|
|
||||||
return bill.toJSON<Bill>()
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getMilageMax(): Promise<number> {
|
|
||||||
const billMaxMilageEnd = await BillModel.findOne({})
|
|
||||||
.sort('-milageEnd')
|
|
||||||
.select('milageEnd')
|
|
||||||
.exec()
|
|
||||||
|
|
||||||
return billMaxMilageEnd?.milageEnd || 0
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,6 @@ export function getNextBigger<T>(array: T[], pivot: T): T {
|
|||||||
return array.sort().find((day) => day > pivot)
|
return array.sort().find((day) => day > pivot)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function uniqueFilter(value, index, self) {
|
export function uniqueFilter<T>(value: T, index: number, self: T[]) {
|
||||||
return self.indexOf(value) === index
|
return self.indexOf(value) === index
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,79 +1,27 @@
|
|||||||
import { MILAGE_TARIFS } from '../db/enums'
|
import { Bill, Prisma } from '@prisma/client'
|
||||||
import { AdditionalCost, Bill } from '../db/bill'
|
|
||||||
import fetch from './fetch'
|
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({
|
export function getBillTotal({
|
||||||
tarif,
|
tarif,
|
||||||
milage,
|
milage,
|
||||||
additionalCosts,
|
additionalCosts,
|
||||||
}: {
|
}: {
|
||||||
tarif: MILAGE_TARIFS
|
tarif: Prisma.Decimal
|
||||||
milage?: number
|
milage?: number
|
||||||
additionalCosts: AdditionalCost[]
|
additionalCosts: Prisma.AdditionalCostsCreateInput[]
|
||||||
}): number {
|
}): Prisma.Decimal {
|
||||||
const milageCosts = getMilageCosts({ tarif, km: milage })
|
const milageCosts = tarif.mul(milage)
|
||||||
const additionalCostsSum = additionalCosts
|
const additionalCostsSum = additionalCosts
|
||||||
.map(({ value }) => value)
|
.reduce((acc, {value} ) => (value as Prisma.Decimal).plus(acc), new Prisma.Decimal(0))
|
||||||
.reduce((acc: number, value: number) => acc + value, 0)
|
|
||||||
|
|
||||||
return roundToCent(milageCosts + additionalCostsSum)
|
|
||||||
|
return additionalCostsSum.add(milageCosts).toDecimalPlaces(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function createBill(
|
export async function createBill(
|
||||||
bookingUuid: string,
|
bookingUuid: string,
|
||||||
bill: Bill
|
bill: Prisma.BillCreateInput
|
||||||
): Promise<Bill> {
|
): Promise<Bill> {
|
||||||
return fetch(`/api/bookings/${bookingUuid}/bill`, {
|
return fetch(`/api/bookings/${bookingUuid}/bill`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
@@ -83,7 +31,7 @@ export async function createBill(
|
|||||||
|
|
||||||
export async function patchBill(
|
export async function patchBill(
|
||||||
bookingUuid: string,
|
bookingUuid: string,
|
||||||
bill: Bill
|
bill: Prisma.BillUpdateInput
|
||||||
): Promise<Bill> {
|
): Promise<Bill> {
|
||||||
return fetch(`/api/bookings/${bookingUuid}/bill`, {
|
return fetch(`/api/bookings/${bookingUuid}/bill`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
|
|||||||
@@ -1,23 +1,22 @@
|
|||||||
import { BookFormData } from '../context/book'
|
import { Prisma, BookingStatus } from '@prisma/client'
|
||||||
import { BOOKING_STATUS } from '../db/enums'
|
|
||||||
import fetch from './fetch'
|
import fetch from './fetch'
|
||||||
|
|
||||||
export function getBookingStatus(status: BOOKING_STATUS) {
|
export function getBookingStatus(status: BookingStatus) {
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case BOOKING_STATUS.REQUESTED:
|
case BookingStatus.REQUESTED:
|
||||||
return 'Angefragt'
|
return 'Angefragt'
|
||||||
case BOOKING_STATUS.CONFIRMED:
|
case BookingStatus.CONFIRMED:
|
||||||
return 'Bestätigt'
|
return 'Bestätigt'
|
||||||
case BOOKING_STATUS.REJECTED:
|
case BookingStatus.REJECTED:
|
||||||
return 'Abgewiesen'
|
return 'Abgewiesen'
|
||||||
case BOOKING_STATUS.CANCELED:
|
case BookingStatus.CANCELED:
|
||||||
return 'Storniert'
|
return 'Storniert'
|
||||||
default:
|
default:
|
||||||
return 'Unbekannt - bitte kontaktieren Sie uns!'
|
return 'Unbekannt - bitte kontaktieren Sie uns!'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function createBooking(formData: BookFormData) {
|
export async function createBooking(formData: Prisma.BookingCreateInput) {
|
||||||
return fetch('/api/bookings', {
|
return fetch('/api/bookings', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: formData,
|
body: formData,
|
||||||
@@ -27,13 +26,13 @@ export async function createBooking(formData: BookFormData) {
|
|||||||
export async function cancelBooking(uuid: string) {
|
export async function cancelBooking(uuid: string) {
|
||||||
return fetch(`/api/bookings/${uuid}`, {
|
return fetch(`/api/bookings/${uuid}`, {
|
||||||
method: 'PATCH',
|
method: 'PATCH',
|
||||||
body: { status: BOOKING_STATUS.CANCELED },
|
body: { status: BookingStatus.CANCELED },
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function patchBooking(
|
export async function patchBooking(
|
||||||
uuid: string,
|
uuid: string,
|
||||||
bookingData: Partial<BookFormData>
|
bookingData: Prisma.BookingUpdateInput
|
||||||
) {
|
) {
|
||||||
return fetch(`/api/bookings/${uuid}`, {
|
return fetch(`/api/bookings/${uuid}`, {
|
||||||
method: 'PATCH',
|
method: 'PATCH',
|
||||||
|
|||||||
@@ -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'
|
import { utcToZonedTime } from 'date-fns-tz'
|
||||||
|
|
||||||
const FRONTEND_FORMAT = 'dd.MM.yyyy'
|
const FRONTEND_FORMAT = 'dd.MM.yyyy'
|
||||||
@@ -23,18 +23,18 @@ export function getDays({
|
|||||||
endDate,
|
endDate,
|
||||||
endDateExclusive = false,
|
endDateExclusive = false,
|
||||||
}: {
|
}: {
|
||||||
startDate: Date
|
startDate: string,
|
||||||
endDate: Date
|
endDate: string,
|
||||||
endDateExclusive?: boolean
|
endDateExclusive?: boolean
|
||||||
}): string[] {
|
}): string[] {
|
||||||
let currentDay = new Date(startDate.getTime())
|
let currentDay = new Date(startDate);
|
||||||
const days = [dateFormatBackend(currentDay)]
|
const days = [dateFormatBackend(currentDay)]
|
||||||
|
|
||||||
if (!endDate) {
|
if (!endDate) {
|
||||||
return days
|
return days
|
||||||
}
|
}
|
||||||
|
|
||||||
const inclusiveEndDate = endDateExclusive ? subDays(endDate, 1) : endDate
|
const inclusiveEndDate = endDateExclusive ? subDays(new Date(endDate), 1) : new Date(endDate)
|
||||||
|
|
||||||
while (currentDay < inclusiveEndDate) {
|
while (currentDay < inclusiveEndDate) {
|
||||||
currentDay = addDays(currentDay, 1)
|
currentDay = addDays(currentDay, 1)
|
||||||
@@ -84,3 +84,8 @@ export function nowInTz(timezone = 'Europe/Berlin'): Date {
|
|||||||
export function getNextDay(date: Date) {
|
export function getNextDay(date: Date) {
|
||||||
return addDays(date, 1)
|
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;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
import { createEvents, createEvent, EventStatus } from 'ics'
|
import { createEvents, createEvent, EventStatus } from 'ics'
|
||||||
import { Booking } from '../db/booking'
|
import { Booking, BookingStatus} from '@prisma/client';
|
||||||
import { BOOKING_STATUS } from '../db/enums'
|
|
||||||
import { getBaseURL } from './url'
|
import { getBaseURL } from './url'
|
||||||
import { daysFormatFrontend } from './date'
|
import { dateFormatFrontend, getDayCount } from './date'
|
||||||
|
|
||||||
function convertDay(value: string): [number, number, number] {
|
function convertDay(value: string): [number, number, number] {
|
||||||
const parts = value.split('-')
|
const parts = value.split('-')
|
||||||
@@ -16,9 +15,9 @@ export function generateCalendarEntry(booking: Booking): string {
|
|||||||
const { error, value } = createEvent({
|
const { error, value } = createEvent({
|
||||||
productId: 'app.vercel.pfadi-bussle/ics',
|
productId: 'app.vercel.pfadi-bussle/ics',
|
||||||
title: `Pfadi-Bussle Buchung`,
|
title: `Pfadi-Bussle Buchung`,
|
||||||
start: convertDay(booking.days[0]),
|
start: convertDay(booking.startDate),
|
||||||
startOutputType: 'local',
|
startOutputType: 'local',
|
||||||
duration: { days: booking.days.length },
|
duration: { days: getDayCount(booking) },
|
||||||
location: 'Mömpelgardgasse 25, 72348 Rosenfeld, Deutschland',
|
location: 'Mömpelgardgasse 25, 72348 Rosenfeld, Deutschland',
|
||||||
geo: { lat: 48.287044, lon: 8.726361 },
|
geo: { lat: 48.287044, lon: 8.726361 },
|
||||||
description: `Gebucht auf ${booking.name}
|
description: `Gebucht auf ${booking.name}
|
||||||
@@ -26,7 +25,7 @@ export function generateCalendarEntry(booking: Booking): string {
|
|||||||
Buchungs-Link: ${getBaseURL()}/bookings/${booking.uuid}
|
Buchungs-Link: ${getBaseURL()}/bookings/${booking.uuid}
|
||||||
`,
|
`,
|
||||||
status:
|
status:
|
||||||
booking.status === BOOKING_STATUS.CONFIRMED
|
booking.status === BookingStatus.CONFIRMED
|
||||||
? ('CONFIRMED' as EventStatus)
|
? ('CONFIRMED' as EventStatus)
|
||||||
: ('TENTATIVE' as EventStatus),
|
: ('TENTATIVE' as EventStatus),
|
||||||
})
|
})
|
||||||
@@ -54,12 +53,12 @@ export function generateBookedCalendar(bookings: Booking[]): string {
|
|||||||
} => ({
|
} => ({
|
||||||
productId: 'app.vercel.pfadi-bussle/ics',
|
productId: 'app.vercel.pfadi-bussle/ics',
|
||||||
calName: 'Pfadi-Bussle Buchungen',
|
calName: 'Pfadi-Bussle Buchungen',
|
||||||
start: convertDay(booking.days[0]),
|
start: convertDay(booking.startDate),
|
||||||
startOutputType: 'local',
|
startOutputType: 'local',
|
||||||
duration: { days: booking.days.length },
|
duration: { days: getDayCount(booking) },
|
||||||
title: `Buchung ${booking.name}`,
|
title: `Buchung ${booking.name}`,
|
||||||
description: `Name: ${booking.name}
|
description: `Name: ${booking.name}
|
||||||
Zeitraum: ${daysFormatFrontend(booking.days)}
|
Zeitraum: ${dateFormatFrontend(new Date(booking.startDate))}-${dateFormatFrontend(new Date(booking.endDate))}
|
||||||
|
|
||||||
Email: ${booking.email}
|
Email: ${booking.email}
|
||||||
Telefon: ${booking.phone}
|
Telefon: ${booking.phone}
|
||||||
@@ -67,7 +66,7 @@ Telefon: ${booking.phone}
|
|||||||
Link: ${getBaseURL()}/admin/bookings/${booking.uuid}
|
Link: ${getBaseURL()}/admin/bookings/${booking.uuid}
|
||||||
`,
|
`,
|
||||||
status:
|
status:
|
||||||
booking.status === BOOKING_STATUS.CONFIRMED
|
booking.status === BookingStatus.CONFIRMED
|
||||||
? ('CONFIRMED' as EventStatus)
|
? ('CONFIRMED' as EventStatus)
|
||||||
: ('TENTATIVE' as EventStatus),
|
: ('TENTATIVE' as EventStatus),
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Booking } from '../db/booking'
|
import { Booking, Prisma } from '@prisma/client';
|
||||||
import { getBaseURL } from '../helpers/url'
|
import { getBaseURL } from '../helpers/url'
|
||||||
import { log } from '../helpers/log'
|
import { log } from '../helpers/log'
|
||||||
import { daysFormatFrontend } from './date'
|
import { dateFormatFrontend } from './date'
|
||||||
import { generateCalendarEntry } from './ical'
|
import { generateCalendarEntry } from './ical'
|
||||||
import sgMail from '@sendgrid/mail'
|
import sgMail from '@sendgrid/mail'
|
||||||
|
|
||||||
@@ -34,10 +34,11 @@ Tel. 0151/212 253 62
|
|||||||
${getBaseURL()}
|
${getBaseURL()}
|
||||||
`
|
`
|
||||||
|
|
||||||
function getReceivedBookingBookerText(booking: Booking): string {
|
function getReceivedBookingBookerText(booking: Prisma.BookingCreateInput): string {
|
||||||
return `Hallo liebe/r ${booking.name},
|
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!
|
Nach Prüfung bestätigen wir die Buchung bald per E-Mail!
|
||||||
|
|
||||||
@@ -54,9 +55,9 @@ ${footer}
|
|||||||
function getBookingConfirmedText(booking: Booking): string {
|
function getBookingConfirmedText(booking: Booking): string {
|
||||||
return `Hallo liebe/r ${booking.name},
|
return `Hallo liebe/r ${booking.name},
|
||||||
|
|
||||||
deine Buchunganfrage zum ${daysFormatFrontend(
|
deine Buchunganfrage vom
|
||||||
booking.days
|
${dateFormatFrontend(new Date(booking.startDate))} bis ${dateFormatFrontend(new Date(booking.endDate))}
|
||||||
)} bestätigen wir gerne!
|
bestätigen wir gerne!
|
||||||
|
|
||||||
Bitte melde dich spätestens 7 Tage vor dem Buchungstermin per E-Mail oder Telefon
|
Bitte melde dich spätestens 7 Tage vor dem Buchungstermin per E-Mail oder Telefon
|
||||||
um eine Schlüsselübergabe zu vereinbaren.
|
um eine Schlüsselübergabe zu vereinbaren.
|
||||||
@@ -71,9 +72,9 @@ ${footer}
|
|||||||
function getBookingRejectedText(booking: Booking): string {
|
function getBookingRejectedText(booking: Booking): string {
|
||||||
return `Hallo liebe/r ${booking.name},
|
return `Hallo liebe/r ${booking.name},
|
||||||
|
|
||||||
es tut uns leid, aber deine Buchungsanfrage zum ${daysFormatFrontend(
|
es tut uns leid, aber deine Buchungsanfrage vom
|
||||||
booking.days
|
${dateFormatFrontend(new Date(booking.startDate))} bis ${dateFormatFrontend(new Date(booking.endDate))}
|
||||||
)} konnten wir leider nicht bestätigen.
|
konnten wir leider nicht bestätigen.
|
||||||
|
|
||||||
Willst du das Bussle an einem anderen Termin buchen? Dann stelle bitte nochmal
|
Willst du das Bussle an einem anderen Termin buchen? Dann stelle bitte nochmal
|
||||||
eine Buchungsanfrage auf ${getBaseURL()}.
|
eine Buchungsanfrage auf ${getBaseURL()}.
|
||||||
@@ -85,7 +86,9 @@ ${footer}
|
|||||||
function getBookingCanceledText(booking: Booking): string {
|
function getBookingCanceledText(booking: Booking): string {
|
||||||
return `Hallo liebe/r ${booking.name},
|
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
|
Willst du das Bussle an einem anderen Termin buchen? Dann stelle bitte nochmal
|
||||||
eine Buchungsanfrage auf ${getBaseURL()}.
|
eine Buchungsanfrage auf ${getBaseURL()}.
|
||||||
@@ -109,7 +112,7 @@ export async function sendReceivedBookingAdminMail(
|
|||||||
await sendMail({
|
await sendMail({
|
||||||
to: [{ email: ADMIN_EMAIL }],
|
to: [{ email: ADMIN_EMAIL }],
|
||||||
from: { email: FROM_EMAIL, name: 'Pfadi-Bussle Wart' },
|
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),
|
textPlainContent: getReceivedBookingAdminText(booking),
|
||||||
})
|
})
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -118,7 +121,7 @@ export async function sendReceivedBookingAdminMail(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function sendReceivedBookingBookerMail(
|
export async function sendReceivedBookingBookerMail(
|
||||||
booking: Booking
|
booking: Prisma.BookingCreateInput
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
try {
|
try {
|
||||||
await sendMail({
|
await sendMail({
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Booking } from '../db/booking'
|
import { Booking } from '@prisma/client'
|
||||||
import { log } from '../helpers/log'
|
import { log } from '../helpers/log'
|
||||||
|
|
||||||
const BOOKING_DATA_KEY = 'pfadiBussleBookingData'
|
const BOOKING_DATA_KEY = 'pfadiBussleBookingData'
|
||||||
|
|||||||
@@ -1,39 +1,36 @@
|
|||||||
|
import { Booking } from '@prisma/client';
|
||||||
import { startOfYear } from 'date-fns'
|
import { startOfYear } from 'date-fns'
|
||||||
import { nowInTz } from '../helpers/date'
|
import { nowInTz } from '../helpers/date'
|
||||||
import { getBookingByUUID, getBookings } from '../db/index'
|
import { getBookingByUUID, getBookings } from '../db/index'
|
||||||
|
|
||||||
export type ServerSideBooking = {
|
export type ServerSideBooking = {
|
||||||
props: {
|
props: {
|
||||||
booking: object
|
booking: Booking
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ServerSideRecentBooking = {
|
export type ServerSideRecentBooking = {
|
||||||
props: {
|
props: {
|
||||||
bookings: object[]
|
bookings: Booking[]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getServerSideRecentBookings =
|
export const getServerSideRecentBookings =
|
||||||
async (): Promise<ServerSideRecentBooking> => {
|
async () => {
|
||||||
const bookings = await getBookings({
|
const bookings = await getBookings({
|
||||||
startDateGreaterThan: startOfYear(nowInTz()).toISOString(),
|
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 {
|
return {
|
||||||
props: {
|
props: {
|
||||||
bookings: bookingsJSON,
|
bookings: bookings,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getServerSideBooking = async (
|
export const getServerSideBooking = async (
|
||||||
context: any
|
context: any
|
||||||
): Promise<ServerSideBooking> => {
|
) => {
|
||||||
const {
|
const {
|
||||||
res,
|
res,
|
||||||
params: { uuid: uuids },
|
params: { uuid: uuids },
|
||||||
@@ -47,11 +44,7 @@ export const getServerSideBooking = async (
|
|||||||
return { props: { booking: null } }
|
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 {
|
return {
|
||||||
props: { booking: bookingJSON },
|
props: { booking },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
|
import { Booking } from '@prisma/client';
|
||||||
import { google } from 'googleapis'
|
import { google } from 'googleapis'
|
||||||
import { getBaseURL } from '../helpers/url'
|
import { getBaseURL } from '../helpers/url'
|
||||||
import { Booking } from '../db/booking'
|
|
||||||
import { getDays, getNextDay, dateFormatBackend } from '../helpers/date'
|
import { getDays, getNextDay, dateFormatBackend } from '../helpers/date'
|
||||||
import { log } from '../helpers/log'
|
import { log } from '../helpers/log'
|
||||||
|
|
||||||
@@ -39,15 +39,15 @@ export async function getBookedDays() {
|
|||||||
.filter((event) => !!event.start.date)
|
.filter((event) => !!event.start.date)
|
||||||
.flatMap((event) =>
|
.flatMap((event) =>
|
||||||
getDays({
|
getDays({
|
||||||
startDate: new Date(event.start.date),
|
startDate: event.start.date,
|
||||||
endDate: new Date(event.end.date),
|
endDate: event.end.date,
|
||||||
endDateExclusive: true,
|
endDateExclusive: true,
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function getSummary(booking: Partial<Booking>): string {
|
function getSummary(booking: Booking): string {
|
||||||
let summary = ''
|
let summary = ''
|
||||||
|
|
||||||
if (booking.org) {
|
if (booking.org) {
|
||||||
@@ -59,13 +59,13 @@ function getSummary(booking: Partial<Booking>): string {
|
|||||||
return summary
|
return summary
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDescription(booking: Booking): string {
|
function getDescription(booking: Booking) {
|
||||||
const bookingUrl = `${getBaseURL()}/admin/booking/${booking.uuid}`
|
const bookingUrl = `${getBaseURL()}/admin/booking/${booking.uuid}`
|
||||||
|
|
||||||
return `Managelink ${bookingUrl}`
|
return `Managelink ${bookingUrl}`
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function createCalendarEvent(booking: Booking): Promise<Booking> {
|
export async function createCalendarEvent(booking: Booking) {
|
||||||
const exclusiveEndDate = dateFormatBackend(
|
const exclusiveEndDate = dateFormatBackend(
|
||||||
getNextDay(new Date(booking.endDate))
|
getNextDay(new Date(booking.endDate))
|
||||||
)
|
)
|
||||||
@@ -85,7 +85,7 @@ export async function createCalendarEvent(booking: Booking): Promise<Booking> {
|
|||||||
return booking
|
return booking
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function deleteCalendarEvent(booking: Booking) {
|
export async function deleteCalendarEvent(booking: { calendarEventId: string }) {
|
||||||
await calendar.events.delete({
|
await calendar.events.delete({
|
||||||
calendarId,
|
calendarId,
|
||||||
eventId: booking.calendarEventId,
|
eventId: booking.calendarEventId,
|
||||||
@@ -96,11 +96,11 @@ export async function deleteCalendarEvent(booking: Booking) {
|
|||||||
booking.calendarEventId = null
|
booking.calendarEventId = null
|
||||||
}
|
}
|
||||||
|
|
||||||
//export async function patchCalendarEvent(booking: { calendarEventId: string } & Partial<Booking> ) : Promise<Booking> {
|
export async function patchCalendarEvent(booking: Booking ) {
|
||||||
// const response = await calendar.events.patch({
|
await calendar.events.patch({
|
||||||
// calendarId,
|
calendarId,
|
||||||
// eventId: booking.calendarEventId,
|
eventId: booking.calendarEventId,
|
||||||
// });
|
});
|
||||||
//
|
|
||||||
// return booking;
|
return booking;
|
||||||
//}
|
}
|
||||||
|
|||||||
377
package-lock.json
generated
377
package-lock.json
generated
@@ -8,7 +8,8 @@
|
|||||||
"name": "pfadi-bussle",
|
"name": "pfadi-bussle",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"dependencies": {
|
"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",
|
"@sendgrid/mail": "7.7.0",
|
||||||
"autoprefixer": "10.4.12",
|
"autoprefixer": "10.4.12",
|
||||||
"classnames": "2.3.2",
|
"classnames": "2.3.2",
|
||||||
@@ -39,9 +40,10 @@
|
|||||||
"postcss-flexbugs-fixes": "5.0.2",
|
"postcss-flexbugs-fixes": "5.0.2",
|
||||||
"postcss-preset-env": "7.8.2",
|
"postcss-preset-env": "7.8.2",
|
||||||
"prettier": "2.7.1",
|
"prettier": "2.7.1",
|
||||||
|
"prisma": "^4.4.0",
|
||||||
"swr": "1.3.0",
|
"swr": "1.3.0",
|
||||||
"tailwindcss": "3.1.8",
|
"tailwindcss": "3.1.8",
|
||||||
"ts-jest": "29.0.3"
|
"ts-jest": "^29.0.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@ampproject/remapping": {
|
"node_modules/@ampproject/remapping": {
|
||||||
@@ -643,9 +645,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@csstools/postcss-cascade-layers": {
|
"node_modules/@csstools/postcss-cascade-layers": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/@csstools/postcss-cascade-layers/-/postcss-cascade-layers-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/@csstools/postcss-cascade-layers/-/postcss-cascade-layers-1.1.1.tgz",
|
||||||
"integrity": "sha512-XpA7g2KViA2ia23A5kZ/EQw+Sy308kLbvMlDPjFZmojwaJ9DYdJuwujFcDGK9v1QhHRmMEHbV2brVSQSLkN/7A==",
|
"integrity": "sha512-+KdYrpKC5TgomQr2DlZF4lDEpHcoxnj5IGddYYfBWJAKfj1JtuHUIqMa+E1pJJ+z3kvDViWMqyqPlG4Ja7amQA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@csstools/selector-specificity": "^2.0.2",
|
"@csstools/selector-specificity": "^2.0.2",
|
||||||
@@ -953,9 +955,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@eslint/eslintrc/node_modules/globals": {
|
"node_modules/@eslint/eslintrc/node_modules/globals": {
|
||||||
"version": "13.15.0",
|
"version": "13.17.0",
|
||||||
"resolved": "https://registry.npmjs.org/globals/-/globals-13.15.0.tgz",
|
"resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz",
|
||||||
"integrity": "sha512-bpzcOlgDhMG070Av0Vy5Owklpv1I6+j96GhUI7Rh7IzDCKLzboflLrrfqMu8NquDbiR4EOQk7XzJwqVJxicxog==",
|
"integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"type-fest": "^0.20.2"
|
"type-fest": "^0.20.2"
|
||||||
@@ -992,9 +994,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@humanwhocodes/config-array": {
|
"node_modules/@humanwhocodes/config-array": {
|
||||||
"version": "0.10.5",
|
"version": "0.10.7",
|
||||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.5.tgz",
|
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.7.tgz",
|
||||||
"integrity": "sha512-XVVDtp+dVvRxMoxSiSfasYaG02VEe1qH5cKgMQJWhol6HwzbcqoCMJi8dAGoYAO57jhUyhI6cWuRiTcRaDaYug==",
|
"integrity": "sha512-MDl6D6sBsaV452/QSdX+4CXIjZhIcI0PELsxUjk4U828yd58vk3bTIvk/6w5FY+4hIy9sLW0sfrV7K7Kc++j/w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@humanwhocodes/object-schema": "^1.2.1",
|
"@humanwhocodes/object-schema": "^1.2.1",
|
||||||
@@ -1419,12 +1421,12 @@
|
|||||||
"react": ">=16"
|
"react": ">=16"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@next-auth/mongodb-adapter": {
|
"node_modules/@next-auth/prisma-adapter": {
|
||||||
"version": "1.1.1",
|
"version": "1.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/@next-auth/mongodb-adapter/-/mongodb-adapter-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/@next-auth/prisma-adapter/-/prisma-adapter-1.0.4.tgz",
|
||||||
"integrity": "sha512-X5O4U4l2M8nyp/B3qF5GOr/JJw2ShKgWfTZRa80Y5CUzTPPmf09ggL5v5UwCmz9l2RIv2GUxO8hK4qrcaZvDRw==",
|
"integrity": "sha512-jIOM6CzCbl2/Mzbx9kb2IjtHoJOeRN9wtQgLk4EUm5bhneSVGv1rtz5TDskvp2UfCa+EK9nDmug+lje41z80Gg==",
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"mongodb": "^4.1.1",
|
"@prisma/client": ">=2.26.0 || >=3",
|
||||||
"next-auth": "^4"
|
"next-auth": "^4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -1700,6 +1702,38 @@
|
|||||||
"url": "https://github.com/sponsors/panva"
|
"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": {
|
"node_modules/@rushstack/eslint-patch": {
|
||||||
"version": "1.1.3",
|
"version": "1.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.1.3.tgz",
|
||||||
@@ -2717,9 +2751,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/caniuse-lite": {
|
"node_modules/caniuse-lite": {
|
||||||
"version": "1.0.30001407",
|
"version": "1.0.30001418",
|
||||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001407.tgz",
|
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001418.tgz",
|
||||||
"integrity": "sha512-4ydV+t4P7X3zH83fQWNDX/mQEzYomossfpViCOx9zHBSMV+rIe3LFqglHHtVyvNl1FhTNxPxs3jei82iqOW04w==",
|
"integrity": "sha512-oIs7+JL3K9JRQ3jPZjlH6qyYDp+nBTCais7hjh0s+fuBwufc7uZ7hPYMXrDOJhV360KGMTcczMRObk0/iMqZRg==",
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "opencollective",
|
"type": "opencollective",
|
||||||
@@ -2846,14 +2880,17 @@
|
|||||||
"integrity": "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw=="
|
"integrity": "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw=="
|
||||||
},
|
},
|
||||||
"node_modules/cliui": {
|
"node_modules/cliui": {
|
||||||
"version": "7.0.4",
|
"version": "8.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
|
||||||
"integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
|
"integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"string-width": "^4.2.0",
|
"string-width": "^4.2.0",
|
||||||
"strip-ansi": "^6.0.0",
|
"strip-ansi": "^6.0.1",
|
||||||
"wrap-ansi": "^7.0.0"
|
"wrap-ansi": "^7.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/co": {
|
"node_modules/co": {
|
||||||
@@ -3225,9 +3262,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/electron-to-chromium": {
|
"node_modules/electron-to-chromium": {
|
||||||
"version": "1.4.256",
|
"version": "1.4.276",
|
||||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.256.tgz",
|
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.276.tgz",
|
||||||
"integrity": "sha512-x+JnqyluoJv8I0U9gVe+Sk2st8vF0CzMt78SXxuoWCooLLY2k5VerIBdpvG7ql6GKI4dzNnPjmqgDJ76EdaAKw=="
|
"integrity": "sha512-EpuHPqu8YhonqLBXHoU6hDJCD98FCe6KDoet3/gY1qsQ6usjJoHqBH2YIVs8FXaAtHwVL8Uqa/fsYao/vq9VWQ=="
|
||||||
},
|
},
|
||||||
"node_modules/emittery": {
|
"node_modules/emittery": {
|
||||||
"version": "0.10.2",
|
"version": "0.10.2",
|
||||||
@@ -3257,22 +3294,22 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/es-abstract": {
|
"node_modules/es-abstract": {
|
||||||
"version": "1.20.2",
|
"version": "1.20.4",
|
||||||
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.2.tgz",
|
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.4.tgz",
|
||||||
"integrity": "sha512-XxXQuVNrySBNlEkTYJoDNFe5+s2yIOpzq80sUHEdPdQr0S5nTLz4ZPPPswNIpKseDDUS5yghX1gfLIHQZ1iNuQ==",
|
"integrity": "sha512-0UtvRN79eMe2L+UNEF1BwRe364sj/DXhQ/k5FmivgoSdpM90b8Jc0mDzKMGo7QS0BVbOP/bTwBKNnDc9rNzaPA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"call-bind": "^1.0.2",
|
"call-bind": "^1.0.2",
|
||||||
"es-to-primitive": "^1.2.1",
|
"es-to-primitive": "^1.2.1",
|
||||||
"function-bind": "^1.1.1",
|
"function-bind": "^1.1.1",
|
||||||
"function.prototype.name": "^1.1.5",
|
"function.prototype.name": "^1.1.5",
|
||||||
"get-intrinsic": "^1.1.2",
|
"get-intrinsic": "^1.1.3",
|
||||||
"get-symbol-description": "^1.0.0",
|
"get-symbol-description": "^1.0.0",
|
||||||
"has": "^1.0.3",
|
"has": "^1.0.3",
|
||||||
"has-property-descriptors": "^1.0.0",
|
"has-property-descriptors": "^1.0.0",
|
||||||
"has-symbols": "^1.0.3",
|
"has-symbols": "^1.0.3",
|
||||||
"internal-slot": "^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-negative-zero": "^2.0.2",
|
||||||
"is-regex": "^1.1.4",
|
"is-regex": "^1.1.4",
|
||||||
"is-shared-array-buffer": "^1.0.2",
|
"is-shared-array-buffer": "^1.0.2",
|
||||||
@@ -3282,6 +3319,7 @@
|
|||||||
"object-keys": "^1.1.1",
|
"object-keys": "^1.1.1",
|
||||||
"object.assign": "^4.1.4",
|
"object.assign": "^4.1.4",
|
||||||
"regexp.prototype.flags": "^1.4.3",
|
"regexp.prototype.flags": "^1.4.3",
|
||||||
|
"safe-regex-test": "^1.0.0",
|
||||||
"string.prototype.trimend": "^1.0.5",
|
"string.prototype.trimend": "^1.0.5",
|
||||||
"string.prototype.trimstart": "^1.0.5",
|
"string.prototype.trimstart": "^1.0.5",
|
||||||
"unbox-primitive": "^1.0.2"
|
"unbox-primitive": "^1.0.2"
|
||||||
@@ -3644,9 +3682,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/eslint-plugin-react": {
|
"node_modules/eslint-plugin-react": {
|
||||||
"version": "7.31.8",
|
"version": "7.31.10",
|
||||||
"resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.31.8.tgz",
|
"resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.31.10.tgz",
|
||||||
"integrity": "sha512-5lBTZmgQmARLLSYiwI71tiGVTLUuqXantZM6vlSY39OaDSV0M7+32K5DnLkmFrwTe+Ksz0ffuLUC91RUviVZfw==",
|
"integrity": "sha512-e4N/nc6AAlg4UKW/mXeYWd3R++qUano5/o+t+wnWxIf+bLsOaH3a4q74kX3nDjYym3VBN4HyO9nEn1GcAqgQOA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"array-includes": "^3.1.5",
|
"array-includes": "^3.1.5",
|
||||||
@@ -3695,34 +3733,18 @@
|
|||||||
"node": ">=0.10.0"
|
"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": {
|
"node_modules/eslint-plugin-react/node_modules/resolve": {
|
||||||
"version": "2.0.0-next.3",
|
"version": "2.0.0-next.4",
|
||||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.3.tgz",
|
"resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz",
|
||||||
"integrity": "sha512-W8LucSynKUIDu9ylraa7ueVZ7hc0uAgJBxVsQSKOXOyle8a93qXhcz+XAXZ8bIq2d6i4Ehddn6Evt+0/UwKk6Q==",
|
"integrity": "sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"is-core-module": "^2.2.0",
|
"is-core-module": "^2.9.0",
|
||||||
"path-parse": "^1.0.6"
|
"path-parse": "^1.0.7",
|
||||||
|
"supports-preserve-symlinks-flag": "^1.0.0"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"resolve": "bin/resolve"
|
||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
@@ -3983,9 +4005,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/estraverse": {
|
"node_modules/estraverse": {
|
||||||
"version": "5.2.0",
|
"version": "5.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
|
||||||
"integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==",
|
"integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=4.0"
|
"node": ">=4.0"
|
||||||
@@ -4092,7 +4114,7 @@
|
|||||||
"node_modules/exit": {
|
"node_modules/exit": {
|
||||||
"version": "0.1.2",
|
"version": "0.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz",
|
||||||
"integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=",
|
"integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.8.0"
|
"node": ">= 0.8.0"
|
||||||
@@ -4952,9 +4974,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/is-callable": {
|
"node_modules/is-callable": {
|
||||||
"version": "1.2.4",
|
"version": "1.2.7",
|
||||||
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz",
|
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
|
||||||
"integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==",
|
"integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
@@ -8453,6 +8475,23 @@
|
|||||||
"integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==",
|
"integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==",
|
||||||
"dev": true
|
"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": {
|
"node_modules/prompts": {
|
||||||
"version": "2.4.2",
|
"version": "2.4.2",
|
||||||
"resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz",
|
||||||
@@ -8467,13 +8506,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/prop-types": {
|
"node_modules/prop-types": {
|
||||||
"version": "15.7.2",
|
"version": "15.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz",
|
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
|
||||||
"integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==",
|
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"loose-envify": "^1.4.0",
|
"loose-envify": "^1.4.0",
|
||||||
"object-assign": "^4.1.1",
|
"object-assign": "^4.1.1",
|
||||||
"react-is": "^16.8.1"
|
"react-is": "^16.13.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/property-expr": {
|
"node_modules/property-expr": {
|
||||||
@@ -8690,7 +8729,7 @@
|
|||||||
"node_modules/require-directory": {
|
"node_modules/require-directory": {
|
||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
|
"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,
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
@@ -8807,6 +8846,20 @@
|
|||||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
||||||
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
|
"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": {
|
"node_modules/saslprep": {
|
||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.3.tgz",
|
||||||
@@ -9622,9 +9675,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/update-browserslist-db": {
|
"node_modules/update-browserslist-db": {
|
||||||
"version": "1.0.9",
|
"version": "1.0.10",
|
||||||
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.9.tgz",
|
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz",
|
||||||
"integrity": "sha512-/xsqn21EGVdXI3EXSum1Yckj3ZVZugqyOZQ/CxYPBD/R+ko9NSUScf8tFF4dOKY+2pvSSJA/S+5B8s4Zr4kyvg==",
|
"integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==",
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "opencollective",
|
"type": "opencollective",
|
||||||
@@ -9922,12 +9975,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/yargs": {
|
"node_modules/yargs": {
|
||||||
"version": "17.4.1",
|
"version": "17.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.0.tgz",
|
||||||
"integrity": "sha512-WSZD9jgobAg3ZKuCQZSa3g9QOJeCCqLoLAykiWgmXnDo9EPnn4RPf5qVTtzgOx66o6/oqhcA5tHtJXpG8pMt3g==",
|
"integrity": "sha512-8H/wTDqlSwoSnScvV2N/JHfLWOKuh5MVla9hqLjK3nsfyy6Y4kDSYSvkU5YCUEPOSnRXfIyx3Sq+B/IWudTo4g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"cliui": "^7.0.2",
|
"cliui": "^8.0.1",
|
||||||
"escalade": "^3.1.1",
|
"escalade": "^3.1.1",
|
||||||
"get-caller-file": "^2.0.5",
|
"get-caller-file": "^2.0.5",
|
||||||
"require-directory": "^2.1.1",
|
"require-directory": "^2.1.1",
|
||||||
@@ -10439,9 +10492,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@csstools/postcss-cascade-layers": {
|
"@csstools/postcss-cascade-layers": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/@csstools/postcss-cascade-layers/-/postcss-cascade-layers-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/@csstools/postcss-cascade-layers/-/postcss-cascade-layers-1.1.1.tgz",
|
||||||
"integrity": "sha512-XpA7g2KViA2ia23A5kZ/EQw+Sy308kLbvMlDPjFZmojwaJ9DYdJuwujFcDGK9v1QhHRmMEHbV2brVSQSLkN/7A==",
|
"integrity": "sha512-+KdYrpKC5TgomQr2DlZF4lDEpHcoxnj5IGddYYfBWJAKfj1JtuHUIqMa+E1pJJ+z3kvDViWMqyqPlG4Ja7amQA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@csstools/selector-specificity": "^2.0.2",
|
"@csstools/selector-specificity": "^2.0.2",
|
||||||
@@ -10598,9 +10651,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"globals": {
|
"globals": {
|
||||||
"version": "13.15.0",
|
"version": "13.17.0",
|
||||||
"resolved": "https://registry.npmjs.org/globals/-/globals-13.15.0.tgz",
|
"resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz",
|
||||||
"integrity": "sha512-bpzcOlgDhMG070Av0Vy5Owklpv1I6+j96GhUI7Rh7IzDCKLzboflLrrfqMu8NquDbiR4EOQk7XzJwqVJxicxog==",
|
"integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"type-fest": "^0.20.2"
|
"type-fest": "^0.20.2"
|
||||||
@@ -10624,9 +10677,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@humanwhocodes/config-array": {
|
"@humanwhocodes/config-array": {
|
||||||
"version": "0.10.5",
|
"version": "0.10.7",
|
||||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.5.tgz",
|
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.7.tgz",
|
||||||
"integrity": "sha512-XVVDtp+dVvRxMoxSiSfasYaG02VEe1qH5cKgMQJWhol6HwzbcqoCMJi8dAGoYAO57jhUyhI6cWuRiTcRaDaYug==",
|
"integrity": "sha512-MDl6D6sBsaV452/QSdX+4CXIjZhIcI0PELsxUjk4U828yd58vk3bTIvk/6w5FY+4hIy9sLW0sfrV7K7Kc++j/w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@humanwhocodes/object-schema": "^1.2.1",
|
"@humanwhocodes/object-schema": "^1.2.1",
|
||||||
@@ -10957,10 +11010,10 @@
|
|||||||
"@types/react": ">=16"
|
"@types/react": ">=16"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@next-auth/mongodb-adapter": {
|
"@next-auth/prisma-adapter": {
|
||||||
"version": "1.1.1",
|
"version": "1.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/@next-auth/mongodb-adapter/-/mongodb-adapter-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/@next-auth/prisma-adapter/-/prisma-adapter-1.0.4.tgz",
|
||||||
"integrity": "sha512-X5O4U4l2M8nyp/B3qF5GOr/JJw2ShKgWfTZRa80Y5CUzTPPmf09ggL5v5UwCmz9l2RIv2GUxO8hK4qrcaZvDRw==",
|
"integrity": "sha512-jIOM6CzCbl2/Mzbx9kb2IjtHoJOeRN9wtQgLk4EUm5bhneSVGv1rtz5TDskvp2UfCa+EK9nDmug+lje41z80Gg==",
|
||||||
"requires": {}
|
"requires": {}
|
||||||
},
|
},
|
||||||
"@next/env": {
|
"@next/env": {
|
||||||
@@ -11102,6 +11155,25 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@panva/hkdf/-/hkdf-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/@panva/hkdf/-/hkdf-1.0.1.tgz",
|
||||||
"integrity": "sha512-mMyQ9vjpuFqePkfe5bZVIf/H3Dmk6wA8Kjxff9RcO4kqzJo+Ek9pGKwZHpeMr7Eku0QhLXMCd7fNCSnEnRMubg=="
|
"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": {
|
"@rushstack/eslint-patch": {
|
||||||
"version": "1.1.3",
|
"version": "1.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.1.3.tgz",
|
||||||
@@ -11874,9 +11946,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"caniuse-lite": {
|
"caniuse-lite": {
|
||||||
"version": "1.0.30001407",
|
"version": "1.0.30001418",
|
||||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001407.tgz",
|
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001418.tgz",
|
||||||
"integrity": "sha512-4ydV+t4P7X3zH83fQWNDX/mQEzYomossfpViCOx9zHBSMV+rIe3LFqglHHtVyvNl1FhTNxPxs3jei82iqOW04w=="
|
"integrity": "sha512-oIs7+JL3K9JRQ3jPZjlH6qyYDp+nBTCais7hjh0s+fuBwufc7uZ7hPYMXrDOJhV360KGMTcczMRObk0/iMqZRg=="
|
||||||
},
|
},
|
||||||
"ccount": {
|
"ccount": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
@@ -11953,13 +12025,13 @@
|
|||||||
"integrity": "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw=="
|
"integrity": "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw=="
|
||||||
},
|
},
|
||||||
"cliui": {
|
"cliui": {
|
||||||
"version": "7.0.4",
|
"version": "8.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
|
||||||
"integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
|
"integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"string-width": "^4.2.0",
|
"string-width": "^4.2.0",
|
||||||
"strip-ansi": "^6.0.0",
|
"strip-ansi": "^6.0.1",
|
||||||
"wrap-ansi": "^7.0.0"
|
"wrap-ansi": "^7.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -12217,9 +12289,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"electron-to-chromium": {
|
"electron-to-chromium": {
|
||||||
"version": "1.4.256",
|
"version": "1.4.276",
|
||||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.256.tgz",
|
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.276.tgz",
|
||||||
"integrity": "sha512-x+JnqyluoJv8I0U9gVe+Sk2st8vF0CzMt78SXxuoWCooLLY2k5VerIBdpvG7ql6GKI4dzNnPjmqgDJ76EdaAKw=="
|
"integrity": "sha512-EpuHPqu8YhonqLBXHoU6hDJCD98FCe6KDoet3/gY1qsQ6usjJoHqBH2YIVs8FXaAtHwVL8Uqa/fsYao/vq9VWQ=="
|
||||||
},
|
},
|
||||||
"emittery": {
|
"emittery": {
|
||||||
"version": "0.10.2",
|
"version": "0.10.2",
|
||||||
@@ -12243,22 +12315,22 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"es-abstract": {
|
"es-abstract": {
|
||||||
"version": "1.20.2",
|
"version": "1.20.4",
|
||||||
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.2.tgz",
|
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.4.tgz",
|
||||||
"integrity": "sha512-XxXQuVNrySBNlEkTYJoDNFe5+s2yIOpzq80sUHEdPdQr0S5nTLz4ZPPPswNIpKseDDUS5yghX1gfLIHQZ1iNuQ==",
|
"integrity": "sha512-0UtvRN79eMe2L+UNEF1BwRe364sj/DXhQ/k5FmivgoSdpM90b8Jc0mDzKMGo7QS0BVbOP/bTwBKNnDc9rNzaPA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"call-bind": "^1.0.2",
|
"call-bind": "^1.0.2",
|
||||||
"es-to-primitive": "^1.2.1",
|
"es-to-primitive": "^1.2.1",
|
||||||
"function-bind": "^1.1.1",
|
"function-bind": "^1.1.1",
|
||||||
"function.prototype.name": "^1.1.5",
|
"function.prototype.name": "^1.1.5",
|
||||||
"get-intrinsic": "^1.1.2",
|
"get-intrinsic": "^1.1.3",
|
||||||
"get-symbol-description": "^1.0.0",
|
"get-symbol-description": "^1.0.0",
|
||||||
"has": "^1.0.3",
|
"has": "^1.0.3",
|
||||||
"has-property-descriptors": "^1.0.0",
|
"has-property-descriptors": "^1.0.0",
|
||||||
"has-symbols": "^1.0.3",
|
"has-symbols": "^1.0.3",
|
||||||
"internal-slot": "^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-negative-zero": "^2.0.2",
|
||||||
"is-regex": "^1.1.4",
|
"is-regex": "^1.1.4",
|
||||||
"is-shared-array-buffer": "^1.0.2",
|
"is-shared-array-buffer": "^1.0.2",
|
||||||
@@ -12268,6 +12340,7 @@
|
|||||||
"object-keys": "^1.1.1",
|
"object-keys": "^1.1.1",
|
||||||
"object.assign": "^4.1.4",
|
"object.assign": "^4.1.4",
|
||||||
"regexp.prototype.flags": "^1.4.3",
|
"regexp.prototype.flags": "^1.4.3",
|
||||||
|
"safe-regex-test": "^1.0.0",
|
||||||
"string.prototype.trimend": "^1.0.5",
|
"string.prototype.trimend": "^1.0.5",
|
||||||
"string.prototype.trimstart": "^1.0.5",
|
"string.prototype.trimstart": "^1.0.5",
|
||||||
"unbox-primitive": "^1.0.2"
|
"unbox-primitive": "^1.0.2"
|
||||||
@@ -12638,9 +12711,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"eslint-plugin-react": {
|
"eslint-plugin-react": {
|
||||||
"version": "7.31.8",
|
"version": "7.31.10",
|
||||||
"resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.31.8.tgz",
|
"resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.31.10.tgz",
|
||||||
"integrity": "sha512-5lBTZmgQmARLLSYiwI71tiGVTLUuqXantZM6vlSY39OaDSV0M7+32K5DnLkmFrwTe+Ksz0ffuLUC91RUviVZfw==",
|
"integrity": "sha512-e4N/nc6AAlg4UKW/mXeYWd3R++qUano5/o+t+wnWxIf+bLsOaH3a4q74kX3nDjYym3VBN4HyO9nEn1GcAqgQOA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"array-includes": "^3.1.5",
|
"array-includes": "^3.1.5",
|
||||||
@@ -12668,31 +12741,15 @@
|
|||||||
"esutils": "^2.0.2"
|
"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": {
|
"resolve": {
|
||||||
"version": "2.0.0-next.3",
|
"version": "2.0.0-next.4",
|
||||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.3.tgz",
|
"resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz",
|
||||||
"integrity": "sha512-W8LucSynKUIDu9ylraa7ueVZ7hc0uAgJBxVsQSKOXOyle8a93qXhcz+XAXZ8bIq2d6i4Ehddn6Evt+0/UwKk6Q==",
|
"integrity": "sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"is-core-module": "^2.2.0",
|
"is-core-module": "^2.9.0",
|
||||||
"path-parse": "^1.0.6"
|
"path-parse": "^1.0.7",
|
||||||
|
"supports-preserve-symlinks-flag": "^1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"semver": {
|
"semver": {
|
||||||
@@ -12787,9 +12844,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"estraverse": {
|
"estraverse": {
|
||||||
"version": "5.2.0",
|
"version": "5.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
|
||||||
"integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==",
|
"integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"estree-util-attach-comments": {
|
"estree-util-attach-comments": {
|
||||||
@@ -12867,7 +12924,7 @@
|
|||||||
"exit": {
|
"exit": {
|
||||||
"version": "0.1.2",
|
"version": "0.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz",
|
||||||
"integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=",
|
"integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"expect": {
|
"expect": {
|
||||||
@@ -13486,9 +13543,9 @@
|
|||||||
"integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ=="
|
"integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ=="
|
||||||
},
|
},
|
||||||
"is-callable": {
|
"is-callable": {
|
||||||
"version": "1.2.4",
|
"version": "1.2.7",
|
||||||
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz",
|
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
|
||||||
"integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==",
|
"integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"is-core-module": {
|
"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": {
|
"prompts": {
|
||||||
"version": "2.4.2",
|
"version": "2.4.2",
|
||||||
"resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz",
|
||||||
@@ -15842,13 +15908,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"prop-types": {
|
"prop-types": {
|
||||||
"version": "15.7.2",
|
"version": "15.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz",
|
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
|
||||||
"integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==",
|
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"loose-envify": "^1.4.0",
|
"loose-envify": "^1.4.0",
|
||||||
"object-assign": "^4.1.1",
|
"object-assign": "^4.1.1",
|
||||||
"react-is": "^16.8.1"
|
"react-is": "^16.13.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"property-expr": {
|
"property-expr": {
|
||||||
@@ -15992,7 +16058,7 @@
|
|||||||
"require-directory": {
|
"require-directory": {
|
||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
|
"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
|
"dev": true
|
||||||
},
|
},
|
||||||
"resolve": {
|
"resolve": {
|
||||||
@@ -16064,6 +16130,17 @@
|
|||||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
||||||
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
|
"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": {
|
"saslprep": {
|
||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.3.tgz",
|
||||||
@@ -16641,9 +16718,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"update-browserslist-db": {
|
"update-browserslist-db": {
|
||||||
"version": "1.0.9",
|
"version": "1.0.10",
|
||||||
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.9.tgz",
|
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz",
|
||||||
"integrity": "sha512-/xsqn21EGVdXI3EXSum1Yckj3ZVZugqyOZQ/CxYPBD/R+ko9NSUScf8tFF4dOKY+2pvSSJA/S+5B8s4Zr4kyvg==",
|
"integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"escalade": "^3.1.1",
|
"escalade": "^3.1.1",
|
||||||
"picocolors": "^1.0.0"
|
"picocolors": "^1.0.0"
|
||||||
@@ -16861,12 +16938,12 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"yargs": {
|
"yargs": {
|
||||||
"version": "17.4.1",
|
"version": "17.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.0.tgz",
|
||||||
"integrity": "sha512-WSZD9jgobAg3ZKuCQZSa3g9QOJeCCqLoLAykiWgmXnDo9EPnn4RPf5qVTtzgOx66o6/oqhcA5tHtJXpG8pMt3g==",
|
"integrity": "sha512-8H/wTDqlSwoSnScvV2N/JHfLWOKuh5MVla9hqLjK3nsfyy6Y4kDSYSvkU5YCUEPOSnRXfIyx3Sq+B/IWudTo4g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"cliui": "^7.0.2",
|
"cliui": "^8.0.1",
|
||||||
"escalade": "^3.1.1",
|
"escalade": "^3.1.1",
|
||||||
"get-caller-file": "^2.0.5",
|
"get-caller-file": "^2.0.5",
|
||||||
"require-directory": "^2.1.1",
|
"require-directory": "^2.1.1",
|
||||||
|
|||||||
@@ -11,7 +11,8 @@
|
|||||||
"test": "jest"
|
"test": "jest"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"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",
|
"@sendgrid/mail": "7.7.0",
|
||||||
"autoprefixer": "10.4.12",
|
"autoprefixer": "10.4.12",
|
||||||
"classnames": "2.3.2",
|
"classnames": "2.3.2",
|
||||||
@@ -38,13 +39,14 @@
|
|||||||
"eslint-config-next": "12.3.1",
|
"eslint-config-next": "12.3.1",
|
||||||
"eslint-config-prettier": "8.5.0",
|
"eslint-config-prettier": "8.5.0",
|
||||||
"jest": "29.1.2",
|
"jest": "29.1.2",
|
||||||
"ts-jest": "29.0.3",
|
|
||||||
"postcss": "8.4.17",
|
"postcss": "8.4.17",
|
||||||
"postcss-flexbugs-fixes": "5.0.2",
|
"postcss-flexbugs-fixes": "5.0.2",
|
||||||
"postcss-preset-env": "7.8.2",
|
"postcss-preset-env": "7.8.2",
|
||||||
"prettier": "2.7.1",
|
"prettier": "2.7.1",
|
||||||
|
"prisma": "^4.4.0",
|
||||||
"swr": "1.3.0",
|
"swr": "1.3.0",
|
||||||
"tailwindcss": "3.1.8"
|
"tailwindcss": "3.1.8",
|
||||||
|
"ts-jest": "^29.0.3"
|
||||||
},
|
},
|
||||||
"jest": {
|
"jest": {
|
||||||
"transform": {
|
"transform": {
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import React, { useEffect, useState } from 'react'
|
import React, { useEffect, useState } from 'react'
|
||||||
import Input from '../../../../components/input'
|
import Input from '../../../../components/input'
|
||||||
import Select from '../../../../components/select'
|
import Select from '../../../../components/select'
|
||||||
import { Booking } from '../../../../db/booking'
|
import { Booking, Bill, BillStatus, AdditionalCosts, Prisma } from '@prisma/client'
|
||||||
import { BILL_STATUS, MILAGE_TARIFS } from '../../../../db/enums'
|
import { MILAGE_TARIFS } from '../../../../db/enums'
|
||||||
import { getMilageMax } from '../../../../db/index'
|
import { getMilageMax } from '../../../../db/index'
|
||||||
import { daysFormatFrontend } from '../../../../helpers/date'
|
import { dateFormatFrontend } from '../../../../helpers/date'
|
||||||
import { log } from '../../../../helpers/log'
|
import { log } from '../../../../helpers/log'
|
||||||
import { getBillTotal, createBill, patchBill } from '../../../../helpers/bill'
|
import { getBillTotal, createBill, patchBill } from '../../../../helpers/bill'
|
||||||
import { getBookingStatus } from '../../../../helpers/booking'
|
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 (
|
return (
|
||||||
<option value={status} key={status}>
|
<option value={status} key={status}>
|
||||||
{getBillStatusLabel(status)}
|
{getBillStatusLabel(status)}
|
||||||
@@ -50,13 +50,13 @@ function getTarifLabel(tarif: MILAGE_TARIFS) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getBillStatusLabel(status: BILL_STATUS) {
|
function getBillStatusLabel(status: BillStatus) {
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case BILL_STATUS.UNINVOICED:
|
case BillStatus.UNINVOICED:
|
||||||
return 'Nicht gestellt'
|
return 'Nicht gestellt'
|
||||||
case BILL_STATUS.INVOICED:
|
case BillStatus.INVOICED:
|
||||||
return 'Gestellt'
|
return 'Gestellt'
|
||||||
case BILL_STATUS.PAID:
|
case BillStatus.PAID:
|
||||||
return 'Bezahlt'
|
return 'Bezahlt'
|
||||||
default:
|
default:
|
||||||
return 'Unbekannt!!!'
|
return 'Unbekannt!!!'
|
||||||
@@ -67,7 +67,7 @@ function BookingBillPage({
|
|||||||
booking: bookingProp,
|
booking: bookingProp,
|
||||||
milageMax,
|
milageMax,
|
||||||
}: {
|
}: {
|
||||||
booking: Booking
|
booking: Booking & { bill: Bill }
|
||||||
milageMax: number
|
milageMax: number
|
||||||
}) {
|
}) {
|
||||||
const [booking, setBooking] = useState(bookingProp)
|
const [booking, setBooking] = useState(bookingProp)
|
||||||
@@ -75,11 +75,11 @@ function BookingBillPage({
|
|||||||
booking?.bill?.milageStart || milageMax
|
booking?.bill?.milageStart || milageMax
|
||||||
)
|
)
|
||||||
const [milageEnd, setMilageEnd] = useState(booking?.bill?.milageEnd)
|
const [milageEnd, setMilageEnd] = useState(booking?.bill?.milageEnd)
|
||||||
const [tarif, setTarif] = useState(
|
const [tarif, setTarif] = useState<Prisma.Decimal>(
|
||||||
booking?.bill?.tarif || MILAGE_TARIFS.EXTERN
|
booking?.bill?.tarif
|
||||||
)
|
)
|
||||||
const [status, setStatus] = useState(booking?.bill?.status)
|
const [status, setStatus] = useState(booking?.bill?.status)
|
||||||
const [additionalCosts, setAdditionalCosts] = useState([])
|
const [additionalCosts, setAdditionalCosts] = useState<Prisma.AdditionalCostsCreateInput[]>([])
|
||||||
const [storingInProgress, setStoringInProgress] = useState(false)
|
const [storingInProgress, setStoringInProgress] = useState(false)
|
||||||
const [storingError, setStoringError] = useState(null)
|
const [storingError, setStoringError] = useState(null)
|
||||||
const milage =
|
const milage =
|
||||||
@@ -99,10 +99,9 @@ function BookingBillPage({
|
|||||||
const bill = await saveBill(booking.uuid, {
|
const bill = await saveBill(booking.uuid, {
|
||||||
milageStart,
|
milageStart,
|
||||||
milageEnd,
|
milageEnd,
|
||||||
milage,
|
|
||||||
tarif,
|
tarif,
|
||||||
status,
|
status,
|
||||||
additionalCosts,
|
additionalCosts: { create: additionalCosts },
|
||||||
})
|
})
|
||||||
|
|
||||||
booking.bill = bill
|
booking.bill = bill
|
||||||
@@ -118,7 +117,7 @@ function BookingBillPage({
|
|||||||
event: React.MouseEvent<HTMLButtonElement>
|
event: React.MouseEvent<HTMLButtonElement>
|
||||||
) {
|
) {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
setAdditionalCosts([...additionalCosts, { name: '', value: 0 }])
|
setAdditionalCosts([...additionalCosts, { name: '', value: new Prisma.Decimal(0) } as AdditionalCosts])
|
||||||
}
|
}
|
||||||
|
|
||||||
const onRemoveAdditionalCost = function(
|
const onRemoveAdditionalCost = function(
|
||||||
@@ -138,7 +137,7 @@ function BookingBillPage({
|
|||||||
<form className="w-full" onSubmit={onSubmit}>
|
<form className="w-full" onSubmit={onSubmit}>
|
||||||
<div>
|
<div>
|
||||||
<strong>Buchungszeitraum:</strong>{' '}
|
<strong>Buchungszeitraum:</strong>{' '}
|
||||||
{daysFormatFrontend(booking.days)}
|
{dateFormatFrontend(new Date(booking.startDate))}-{dateFormatFrontend(new Date(booking.endDate))}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<strong>Bucher:</strong> {booking.name}
|
<strong>Bucher:</strong> {booking.name}
|
||||||
@@ -171,8 +170,8 @@ function BookingBillPage({
|
|||||||
<Select
|
<Select
|
||||||
label="Rate"
|
label="Rate"
|
||||||
name="tarif"
|
name="tarif"
|
||||||
value={tarif}
|
value={tarif.toString()}
|
||||||
onChange={(e) => setTarif(e.target.value as MILAGE_TARIFS)}
|
onChange={(e) => setTarif(new Prisma.Decimal(e.target.value))}
|
||||||
>
|
>
|
||||||
{milageTarifOptions}
|
{milageTarifOptions}
|
||||||
</Select>
|
</Select>
|
||||||
@@ -211,7 +210,7 @@ function BookingBillPage({
|
|||||||
newAdditonalCosts[index] = {
|
newAdditonalCosts[index] = {
|
||||||
value: newAdditonalCosts[index].value,
|
value: newAdditonalCosts[index].value,
|
||||||
name: event.target.value,
|
name: event.target.value,
|
||||||
}
|
} as AdditionalCosts
|
||||||
setAdditionalCosts(newAdditonalCosts)
|
setAdditionalCosts(newAdditonalCosts)
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
@@ -219,13 +218,13 @@ function BookingBillPage({
|
|||||||
label={`Betrag`}
|
label={`Betrag`}
|
||||||
name={`additionalCostValue${index}`}
|
name={`additionalCostValue${index}`}
|
||||||
key={`additionalCostValue${index}`}
|
key={`additionalCostValue${index}`}
|
||||||
value={additionalCosts[index].value}
|
value={additionalCosts[index].value.toString()}
|
||||||
type="number"
|
type="number"
|
||||||
onChange={(event) => {
|
onChange={(event) => {
|
||||||
const newAdditonalCosts = [...additionalCosts]
|
const newAdditonalCosts = [...additionalCosts]
|
||||||
newAdditonalCosts[index] = {
|
newAdditonalCosts[index] = {
|
||||||
name: newAdditonalCosts[index].name,
|
name: newAdditonalCosts[index].name,
|
||||||
value: Number(event.target.value),
|
value: new Prisma.Decimal(event.target.value),
|
||||||
}
|
}
|
||||||
setAdditionalCosts(newAdditonalCosts)
|
setAdditionalCosts(newAdditonalCosts)
|
||||||
}}
|
}}
|
||||||
@@ -234,13 +233,13 @@ function BookingBillPage({
|
|||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
<Input label="Summe" name="total" readOnly value={total} />
|
<Input label="Summe" name="total" readOnly value={total.toString()} />
|
||||||
</div>
|
</div>
|
||||||
<Select
|
<Select
|
||||||
label="Status"
|
label="Status"
|
||||||
name={status}
|
name={status}
|
||||||
value={status}
|
value={status}
|
||||||
onChange={(e) => setStatus(e.target.value as BILL_STATUS)}
|
onChange={(e) => setStatus(e.target.value as BillStatus)}
|
||||||
>
|
>
|
||||||
{billStatusOptions}
|
{billStatusOptions}
|
||||||
</Select>
|
</Select>
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
import React, { useEffect, useState } from 'react'
|
import React, { useEffect, useState } from 'react'
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
|
import { BookingStatus, Booking } from '@prisma/client'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import Calendar from '../../../../components/calendar'
|
import Calendar from '../../../../components/calendar'
|
||||||
import { getServerSideBooking } from '../../../../lib/getServerSideProps'
|
import { getServerSideBooking } from '../../../../lib/getServerSideProps'
|
||||||
import { Booking } from '../../../../db/booking'
|
|
||||||
import { getBookingStatus, patchBooking } from '../../../../helpers/booking'
|
import { getBookingStatus, patchBooking } from '../../../../helpers/booking'
|
||||||
import { daysFormatFrontend } from '../../../../helpers/date'
|
import { daysFormatFrontend } from '../../../../helpers/date'
|
||||||
import { log } from '../../../../helpers/log'
|
import { log } from '../../../../helpers/log'
|
||||||
import { BOOKING_STATUS } from '../../../../db/enums'
|
|
||||||
|
|
||||||
export const getServerSideProps = getServerSideBooking
|
export const getServerSideProps = getServerSideBooking
|
||||||
|
|
||||||
@@ -25,7 +24,7 @@ function ShowBookingAdmin({ booking: bookingProp }: { booking: Booking }) {
|
|||||||
setStoringBookingError(null)
|
setStoringBookingError(null)
|
||||||
setStoringBooking(true)
|
setStoringBooking(true)
|
||||||
const updatedBooking = await patchBooking(booking.uuid, {
|
const updatedBooking = await patchBooking(booking.uuid, {
|
||||||
status: confirmed ? BOOKING_STATUS.CONFIRMED : BOOKING_STATUS.REJECTED,
|
status: confirmed ? BookingStatus.CONFIRMED : BookingStatus.REJECTED,
|
||||||
})
|
})
|
||||||
setBooking(updatedBooking)
|
setBooking(updatedBooking)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -40,7 +39,7 @@ function ShowBookingAdmin({ booking: bookingProp }: { booking: Booking }) {
|
|||||||
<h2 className="text-3xl">Buchung {booking.uuid}</h2>
|
<h2 className="text-3xl">Buchung {booking.uuid}</h2>
|
||||||
<Calendar start={booking.startDate} end={booking.endDate} />
|
<Calendar start={booking.startDate} end={booking.endDate} />
|
||||||
<div>
|
<div>
|
||||||
<strong>Buchungszeitraum:</strong> {daysFormatFrontend(booking.days)}
|
<strong>Buchungszeitraum:</strong> {daysFormatFrontend([booking.startDate])}-{daysFormatFrontend([booking.endDate])}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<strong>Bucher:</strong> {booking.name}
|
<strong>Bucher:</strong> {booking.name}
|
||||||
|
|||||||
@@ -1,64 +1,51 @@
|
|||||||
import { NextApiRequest, NextApiResponse } from 'next'
|
|
||||||
import NextAuth from 'next-auth'
|
import NextAuth from 'next-auth'
|
||||||
import EmailProvider from 'next-auth/providers/email'
|
import EmailProvider from 'next-auth/providers/email'
|
||||||
import GitHubProvider from 'next-auth/providers/github'
|
import GitHubProvider from 'next-auth/providers/github'
|
||||||
|
|
||||||
import { MongoDBAdapter } from '@next-auth/mongodb-adapter'
|
import { PrismaAdapter } from "@next-auth/prisma-adapter"
|
||||||
import { MONGO_URI } from '../../../db'
|
import { PrismaClient } from "@prisma/client"
|
||||||
import { MongoClient } from 'mongodb'
|
|
||||||
|
|
||||||
let client: MongoClient
|
const prisma = new PrismaClient()
|
||||||
|
|
||||||
const ADMIN_EMAIL = process.env.ADMIN_EMAIL
|
const ADMIN_EMAIL = process.env.ADMIN_EMAIL
|
||||||
const GITHUB_USERS_GRANTED = ['111471']
|
const GITHUB_USERS_GRANTED = ['111471']
|
||||||
|
|
||||||
async function getMongoClient() {
|
export default NextAuth({
|
||||||
if (!client) {
|
secret: process.env.NEXTAUTH_SECRET,
|
||||||
client = new MongoClient(MONGO_URI)
|
adapter: PrismaAdapter(prisma),
|
||||||
await client.connect()
|
providers: [
|
||||||
}
|
GitHubProvider({
|
||||||
|
clientId: process.env.GITHUB_CLIENT_ID,
|
||||||
return client
|
clientSecret: process.env.GITHUB_CLIENT_SECRET,
|
||||||
}
|
}),
|
||||||
|
EmailProvider({
|
||||||
export default async function auth(req: NextApiRequest, res: NextApiResponse) {
|
server: {
|
||||||
return await NextAuth(req, res, {
|
host: 'smtp.sendgrid.net',
|
||||||
secret: process.env.NEXTAUTH_SECRET,
|
port: 587,
|
||||||
adapter: MongoDBAdapter(getMongoClient()),
|
auth: {
|
||||||
providers: [
|
user: 'apikey',
|
||||||
GitHubProvider({
|
pass: process.env.SENDGRID_API_KEY,
|
||||||
clientId: process.env.GITHUB_CLIENT_ID,
|
|
||||||
clientSecret: process.env.GITHUB_CLIENT_SECRET,
|
|
||||||
}),
|
|
||||||
EmailProvider({
|
|
||||||
server: {
|
|
||||||
host: 'smtp.sendgrid.net',
|
|
||||||
port: 587,
|
|
||||||
auth: {
|
|
||||||
user: 'apikey',
|
|
||||||
pass: process.env.SENDGRID_API_KEY,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
from: process.env.FROM_EMAIL,
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
callbacks: {
|
|
||||||
async signIn({ account, email }) {
|
|
||||||
// if user sigin requested magic link via EmailProvider
|
|
||||||
if (account.provider === 'email') {
|
|
||||||
if (email.verificationRequest) {
|
|
||||||
// only allow admins by email entered
|
|
||||||
return account.providerAccountId === ADMIN_EMAIL
|
|
||||||
}
|
|
||||||
|
|
||||||
// if user accesses with magic link, also only allow admin
|
|
||||||
return account.providerAccountId === ADMIN_EMAIL
|
|
||||||
} else if (account.provider === 'github') {
|
|
||||||
// only one and only one user
|
|
||||||
return GITHUB_USERS_GRANTED.includes(account.providerAccountId)
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
},
|
},
|
||||||
|
from: process.env.FROM_EMAIL,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
callbacks: {
|
||||||
|
async signIn({ account, email }) {
|
||||||
|
// if user sigin requested magic link via EmailProvider
|
||||||
|
if (account.provider === 'email') {
|
||||||
|
if (email.verificationRequest) {
|
||||||
|
// only allow admins by email entered
|
||||||
|
return account.providerAccountId === ADMIN_EMAIL
|
||||||
|
}
|
||||||
|
|
||||||
|
// if user accesses with magic link, also only allow admin
|
||||||
|
return account.providerAccountId === ADMIN_EMAIL
|
||||||
|
} else if (account.provider === 'github') {
|
||||||
|
// only one and only one user
|
||||||
|
return GITHUB_USERS_GRANTED.includes(account.providerAccountId)
|
||||||
|
}
|
||||||
|
return false
|
||||||
},
|
},
|
||||||
})
|
},
|
||||||
}
|
});
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { NextApiRequest, NextApiResponse } from 'next'
|
import { NextApiRequest, NextApiResponse } from 'next'
|
||||||
import { Bill } from '../../../../db/bill'
|
import { Prisma } from '@prisma/client';
|
||||||
import { createBill, patchBill } from '../../../../db/index'
|
import { createBill, patchBill } from '../../../../db/index'
|
||||||
import { log } from '../../../../helpers/log'
|
import { log } from '../../../../helpers/log'
|
||||||
|
|
||||||
@@ -13,7 +13,7 @@ export default async function billHandler(
|
|||||||
} = req
|
} = req
|
||||||
const bookingUUID = Array.isArray(uuids) ? uuids[0] : uuids
|
const bookingUUID = Array.isArray(uuids) ? uuids[0] : uuids
|
||||||
|
|
||||||
let bill: Bill
|
let bill: Prisma.BillUpdateInput
|
||||||
|
|
||||||
switch (method) {
|
switch (method) {
|
||||||
case 'POST':
|
case 'POST':
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { NextApiRequest, NextApiResponse } from 'next'
|
import { NextApiRequest, NextApiResponse } from 'next'
|
||||||
import { Booking } from '../../../../db/booking'
|
import { Prisma, BookingStatus } from '@prisma/client';
|
||||||
import { BOOKING_STATUS } from '../../../../db/enums'
|
|
||||||
import { patchBooking } from '../../../../db/index'
|
import { patchBooking } from '../../../../db/index'
|
||||||
import {
|
import {
|
||||||
sendBookingConfirmed,
|
sendBookingConfirmed,
|
||||||
@@ -10,28 +9,27 @@ import {
|
|||||||
import { log } from '../../../../helpers/log'
|
import { log } from '../../../../helpers/log'
|
||||||
|
|
||||||
function changedStatus(
|
function changedStatus(
|
||||||
previous: Booking,
|
previous: Prisma.BookingUpdateInput,
|
||||||
current: Partial<Booking>,
|
current: Prisma.BookingUpdateInput,
|
||||||
status: BOOKING_STATUS
|
status: BookingStatus
|
||||||
): boolean {
|
): boolean {
|
||||||
return (
|
return (
|
||||||
[BOOKING_STATUS.REQUESTED].includes(previous.status) &&
|
BookingStatus.REQUESTED === previous.status &&
|
||||||
current.status === status
|
current.status === status
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
function wasRejected(previous: Booking, current: Partial<Booking>): boolean {
|
function wasRejected(previous: Prisma.BookingUpdateInput, current: Prisma.BookingUpdateInput): boolean {
|
||||||
return changedStatus(previous, current, BOOKING_STATUS.REJECTED)
|
return changedStatus(previous, current, BookingStatus.REJECTED)
|
||||||
}
|
}
|
||||||
|
|
||||||
function wasConfirmed(previous: Booking, current: Partial<Booking>): boolean {
|
function wasConfirmed(previous: Prisma.BookingUpdateInput, current: Prisma.BookingUpdateInput): boolean {
|
||||||
return changedStatus(previous, current, BOOKING_STATUS.CONFIRMED)
|
return changedStatus(previous, current, BookingStatus.CONFIRMED)
|
||||||
}
|
}
|
||||||
|
|
||||||
function wasCanceled(previous: Booking, current: Partial<Booking>): boolean {
|
function wasCanceled(previous: Prisma.BookingUpdateInput, current: Prisma.BookingUpdateInput): boolean {
|
||||||
return (
|
return (
|
||||||
[BOOKING_STATUS.REQUESTED, BOOKING_STATUS.CONFIRMED].includes(
|
[BookingStatus.REQUESTED, BookingStatus.CONFIRMED].find(s => s === previous.status)
|
||||||
previous.status
|
&& current.status === BookingStatus.CANCELED
|
||||||
) && current.status === BOOKING_STATUS.CANCELED
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,12 +46,12 @@ export default async function userHandler(
|
|||||||
|
|
||||||
switch (method) {
|
switch (method) {
|
||||||
case 'PATCH':
|
case 'PATCH':
|
||||||
if (!Object.values(BOOKING_STATUS).includes(req.body.status)) {
|
if (!Object.values(BookingStatus).includes(req.body.status)) {
|
||||||
res
|
res
|
||||||
.status(400)
|
.status(400)
|
||||||
.end(
|
.end(
|
||||||
`The attribute status can only be: ${Object.values(
|
`The attribute status can only be: ${Object.values(
|
||||||
BOOKING_STATUS
|
BookingStatus
|
||||||
).join(', ')}`
|
).join(', ')}`
|
||||||
)
|
)
|
||||||
break
|
break
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { Error } from 'mongoose'
|
|
||||||
import { NextApiRequest, NextApiResponse } from 'next'
|
import { NextApiRequest, NextApiResponse } from 'next'
|
||||||
import { Booking } from '../../../db/booking'
|
import { Booking, Prisma } from '@prisma/client';
|
||||||
import { createBooking } from '../../../db/index'
|
import { createBooking } from '../../../db/index'
|
||||||
import { log } from '../../../helpers/log'
|
import { log } from '../../../helpers/log'
|
||||||
import {
|
import {
|
||||||
@@ -14,17 +13,14 @@ export default async function userHandler(
|
|||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const { method } = req
|
const { method } = req
|
||||||
|
|
||||||
let booking: Booking
|
let booking: Booking;
|
||||||
|
|
||||||
switch (method) {
|
switch (method) {
|
||||||
case 'POST':
|
case 'POST':
|
||||||
try {
|
try {
|
||||||
booking = await createBooking(req.body)
|
booking = await createBooking(req.body)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e instanceof Error.ValidationError) {
|
// TODO: add validation for booking on same day
|
||||||
res.status(400).json({ message: e.message, errors: e.errors })
|
|
||||||
return
|
|
||||||
}
|
|
||||||
log.error('Failed to store booking', e)
|
log.error('Failed to store booking', e)
|
||||||
res.status(500).end(`Internal Server Error...Guru is meditating...`)
|
res.status(500).end(`Internal Server Error...Guru is meditating...`)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
import React, { useEffect, useState } from 'react'
|
import React, { useEffect, useState } from 'react'
|
||||||
import { getServerSideBooking } from '../../../lib/getServerSideProps'
|
import { getServerSideBooking } from '../../../lib/getServerSideProps'
|
||||||
import { Booking } from '../../../db/booking'
|
import { Booking, BookingStatus } from '@prisma/client'
|
||||||
import { BOOKING_STATUS } from '../../../db/enums'
|
import { dateFormatFrontend } from '../../../helpers/date'
|
||||||
import { daysFormatFrontend } from '../../../helpers/date'
|
|
||||||
import { log } from '../../../helpers/log'
|
import { log } from '../../../helpers/log'
|
||||||
import { getBookingStatus, cancelBooking } from '../../../helpers/booking'
|
import { getBookingStatus, cancelBooking } from '../../../helpers/booking'
|
||||||
|
|
||||||
@@ -45,12 +44,12 @@ export default function ShowBooking({
|
|||||||
<strong>Buchungsstatus:</strong> {getBookingStatus(booking.status)}
|
<strong>Buchungsstatus:</strong> {getBookingStatus(booking.status)}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<strong>Buchungszeitraum:</strong> {daysFormatFrontend(booking.days)}
|
<strong>Buchungszeitraum:</strong> {dateFormatFrontend(new Date(booking.startDate))}-{dateFormatFrontend(new Date(booking.endDate))}
|
||||||
</div>
|
</div>
|
||||||
{storingBookingError && (
|
{storingBookingError && (
|
||||||
<div className="error-message flex-grow">{storingBookingError}</div>
|
<div className="error-message flex-grow">{storingBookingError}</div>
|
||||||
)}
|
)}
|
||||||
{[BOOKING_STATUS.CONFIRMED, BOOKING_STATUS.REQUESTED].includes(
|
{([BookingStatus.CONFIRMED, BookingStatus.REQUESTED] as BookingStatus[]).includes(
|
||||||
booking.status
|
booking.status
|
||||||
) && (
|
) && (
|
||||||
<div className="my-6">
|
<div className="my-6">
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import React, { useEffect, useState } from 'react'
|
import React, { useEffect, useState } from 'react'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import { Booking } from '../../../db/booking'
|
import { Booking } from '@prisma/client'
|
||||||
import { loadBookingData, storeBookingData } from '../../../helpers/storage'
|
import { loadBookingData, storeBookingData } from '../../../helpers/storage'
|
||||||
import { getServerSideBooking } from '../../../lib/getServerSideProps'
|
import { getServerSideBooking } from '../../../lib/getServerSideProps'
|
||||||
|
|
||||||
|
|||||||
148
prisma/migrations/20221011094251_initial/migration.sql
Normal file
148
prisma/migrations/20221011094251_initial/migration.sql
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
-- CreateEnum
|
||||||
|
CREATE TYPE "BillStatus" AS ENUM ('UNINVOICED', 'INVOICED', 'PAID');
|
||||||
|
|
||||||
|
-- CreateEnum
|
||||||
|
CREATE TYPE "BookingStatus" AS ENUM ('REQUESTED', 'CONFIRMED', 'REJECTED', 'CANCELED');
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "AdditionalCosts" (
|
||||||
|
"id" SERIAL NOT NULL,
|
||||||
|
"name" TEXT NOT NULL,
|
||||||
|
"value" DECIMAL(65,30) NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "AdditionalCosts_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "Bill" (
|
||||||
|
"id" SERIAL NOT NULL,
|
||||||
|
"createdAt" DATE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"updatedAt" DATE NOT NULL,
|
||||||
|
"milageEnd" INTEGER NOT NULL,
|
||||||
|
"milageStart" INTEGER NOT NULL,
|
||||||
|
"status" "BillStatus" NOT NULL DEFAULT 'UNINVOICED',
|
||||||
|
"tarif" DECIMAL(65,30) NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "Bill_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "Booking" (
|
||||||
|
"id" TEXT NOT NULL,
|
||||||
|
"uuid" TEXT NOT NULL,
|
||||||
|
"createdAt" DATE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"updatedAt" DATE NOT NULL,
|
||||||
|
"billId" INTEGER NOT NULL,
|
||||||
|
"calendarEventId" TEXT,
|
||||||
|
"city" TEXT NOT NULL,
|
||||||
|
"destination" TEXT NOT NULL,
|
||||||
|
"email" TEXT NOT NULL,
|
||||||
|
"endDate" TEXT NOT NULL,
|
||||||
|
"name" TEXT NOT NULL,
|
||||||
|
"org" TEXT NOT NULL,
|
||||||
|
"phone" TEXT NOT NULL,
|
||||||
|
"purpose" TEXT NOT NULL,
|
||||||
|
"startDate" TEXT NOT NULL,
|
||||||
|
"status" "BookingStatus" NOT NULL DEFAULT 'REQUESTED',
|
||||||
|
"street" TEXT NOT NULL,
|
||||||
|
"zip" TEXT NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "Booking_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "Account" (
|
||||||
|
"id" TEXT NOT NULL,
|
||||||
|
"userId" TEXT NOT NULL,
|
||||||
|
"type" TEXT NOT NULL,
|
||||||
|
"provider" TEXT NOT NULL,
|
||||||
|
"providerAccountId" TEXT NOT NULL,
|
||||||
|
"refresh_token" TEXT,
|
||||||
|
"access_token" TEXT,
|
||||||
|
"expires_at" INTEGER,
|
||||||
|
"token_type" TEXT,
|
||||||
|
"scope" TEXT,
|
||||||
|
"id_token" TEXT,
|
||||||
|
"session_state" TEXT,
|
||||||
|
|
||||||
|
CONSTRAINT "Account_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "Session" (
|
||||||
|
"id" TEXT NOT NULL,
|
||||||
|
"sessionToken" TEXT NOT NULL,
|
||||||
|
"userId" TEXT NOT NULL,
|
||||||
|
"expires" TIMESTAMP(3) NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "Session_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "User" (
|
||||||
|
"id" TEXT NOT NULL,
|
||||||
|
"name" TEXT,
|
||||||
|
"email" TEXT,
|
||||||
|
"emailVerified" TIMESTAMP(3),
|
||||||
|
"image" TEXT,
|
||||||
|
|
||||||
|
CONSTRAINT "User_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "VerificationToken" (
|
||||||
|
"identifier" TEXT NOT NULL,
|
||||||
|
"token" TEXT NOT NULL,
|
||||||
|
"expires" TIMESTAMP(3) NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "_AdditionalCostsToBill" (
|
||||||
|
"A" INTEGER NOT NULL,
|
||||||
|
"B" INTEGER NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "Booking_uuid_key" ON "Booking"("uuid");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "Booking_billId_key" ON "Booking"("billId");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "uuid_1" ON "Booking"("uuid");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "Account_provider_providerAccountId_key" ON "Account"("provider", "providerAccountId");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "Session_sessionToken_key" ON "Session"("sessionToken");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "User_email_key" ON "User"("email");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "VerificationToken_token_key" ON "VerificationToken"("token");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "VerificationToken_identifier_token_key" ON "VerificationToken"("identifier", "token");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "_AdditionalCostsToBill_AB_unique" ON "_AdditionalCostsToBill"("A", "B");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "_AdditionalCostsToBill_B_index" ON "_AdditionalCostsToBill"("B");
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "Booking" ADD CONSTRAINT "Booking_billId_fkey" FOREIGN KEY ("billId") REFERENCES "Bill"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "Account" ADD CONSTRAINT "Account_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "Session" ADD CONSTRAINT "Session_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "_AdditionalCostsToBill" ADD CONSTRAINT "_AdditionalCostsToBill_A_fkey" FOREIGN KEY ("A") REFERENCES "AdditionalCosts"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "_AdditionalCostsToBill" ADD CONSTRAINT "_AdditionalCostsToBill_B_fkey" FOREIGN KEY ("B") REFERENCES "Bill"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
3
prisma/migrations/migration_lock.toml
Normal file
3
prisma/migrations/migration_lock.toml
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# Please do not edit this file manually
|
||||||
|
# It should be added in your version-control system (i.e. Git)
|
||||||
|
provider = "postgresql"
|
||||||
110
prisma/schema.prisma
Normal file
110
prisma/schema.prisma
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
generator client {
|
||||||
|
provider = "prisma-client-js"
|
||||||
|
}
|
||||||
|
|
||||||
|
datasource db {
|
||||||
|
provider = "postgres"
|
||||||
|
url = env("POSTGRES_URI")
|
||||||
|
}
|
||||||
|
|
||||||
|
model AdditionalCosts {
|
||||||
|
id Int @id @default(autoincrement())
|
||||||
|
name String
|
||||||
|
value Decimal
|
||||||
|
Bill Bill[]
|
||||||
|
}
|
||||||
|
|
||||||
|
enum BillStatus {
|
||||||
|
UNINVOICED
|
||||||
|
INVOICED
|
||||||
|
PAID
|
||||||
|
}
|
||||||
|
|
||||||
|
model Bill {
|
||||||
|
id Int @id @default(autoincrement())
|
||||||
|
createdAt DateTime @default(now()) @db.Date
|
||||||
|
updatedAt DateTime @updatedAt @db.Date
|
||||||
|
milageEnd Int
|
||||||
|
milageStart Int
|
||||||
|
status BillStatus @default(UNINVOICED)
|
||||||
|
tarif Decimal
|
||||||
|
additionalCosts AdditionalCosts[]
|
||||||
|
booking Booking?
|
||||||
|
}
|
||||||
|
|
||||||
|
enum BookingStatus {
|
||||||
|
REQUESTED
|
||||||
|
CONFIRMED
|
||||||
|
REJECTED
|
||||||
|
CANCELED
|
||||||
|
}
|
||||||
|
|
||||||
|
model Booking {
|
||||||
|
id String @id @default(uuid())
|
||||||
|
uuid String @unique @default(uuid())
|
||||||
|
createdAt DateTime @default(now()) @db.Date
|
||||||
|
updatedAt DateTime @updatedAt @db.Date
|
||||||
|
bill Bill? @relation(fields: [billId], references: [id], onDelete: Cascade)
|
||||||
|
billId Int @unique
|
||||||
|
calendarEventId String?
|
||||||
|
city String
|
||||||
|
destination String
|
||||||
|
email String
|
||||||
|
endDate String
|
||||||
|
name String
|
||||||
|
org String
|
||||||
|
phone String
|
||||||
|
purpose String
|
||||||
|
startDate String
|
||||||
|
status BookingStatus @default(REQUESTED)
|
||||||
|
street String
|
||||||
|
zip String
|
||||||
|
|
||||||
|
@@index([uuid], map: "uuid_1")
|
||||||
|
}
|
||||||
|
|
||||||
|
// next-auth
|
||||||
|
model Account {
|
||||||
|
id String @id @default(cuid())
|
||||||
|
userId String
|
||||||
|
type String
|
||||||
|
provider String
|
||||||
|
providerAccountId String
|
||||||
|
refresh_token String? @db.Text
|
||||||
|
access_token String? @db.Text
|
||||||
|
expires_at Int?
|
||||||
|
token_type String?
|
||||||
|
scope String?
|
||||||
|
id_token String? @db.Text
|
||||||
|
session_state String?
|
||||||
|
|
||||||
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||||
|
|
||||||
|
@@unique([provider, providerAccountId])
|
||||||
|
}
|
||||||
|
|
||||||
|
model Session {
|
||||||
|
id String @id @default(cuid())
|
||||||
|
sessionToken String @unique
|
||||||
|
userId String
|
||||||
|
expires DateTime
|
||||||
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||||
|
}
|
||||||
|
|
||||||
|
model User {
|
||||||
|
id String @id @default(cuid())
|
||||||
|
name String?
|
||||||
|
email String? @unique
|
||||||
|
emailVerified DateTime?
|
||||||
|
image String?
|
||||||
|
accounts Account[]
|
||||||
|
sessions Session[]
|
||||||
|
}
|
||||||
|
|
||||||
|
model VerificationToken {
|
||||||
|
identifier String
|
||||||
|
token String @unique
|
||||||
|
expires DateTime
|
||||||
|
|
||||||
|
@@unique([identifier, token])
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user