remover booker, that's overdosed

It also brings the problem of consolidating bookers over multiple
bookings. The amount of data is not justifying having it in an own
entity
This commit is contained in:
Thomas Ruoff
2021-06-21 23:21:23 +02:00
parent 3700b5f450
commit 9f3b6bb2e1
13 changed files with 63 additions and 86 deletions

View File

@@ -3,13 +3,11 @@ import { useRouter } from 'next/router'
import { clearBookingData, loadBookingData } from '../helpers/storage' import { clearBookingData, loadBookingData } from '../helpers/storage'
import { createBooking } from '../helpers/booking' import { createBooking } from '../helpers/booking'
import { Booker } from '../db/booker'
import { Booking } from '../db/booking' import { Booking } from '../db/booking'
export type BookFormData = Omit<Booking, 'uuid'> & export type BookFormData = Omit<Booking, 'uuid'> & {
Booker & { storeData?: boolean
storeData?: boolean }
}
type BookingProviderState = { type BookingProviderState = {
postData?: boolean postData?: boolean

View File

@@ -1,31 +0,0 @@
import * as mongoose from 'mongoose'
export type Booker = {
name: string
email: string
phone: string
street: string
zip: string
city: string
}
export type BookerDocument = Booker &
mongoose.SchemaTimestampsConfig &
mongoose.Document
export type BookerModel = mongoose.Model<BookerDocument>
const BookerSchema = new mongoose.Schema<BookerDocument>(
{
name: { type: String, required: true },
email: { type: String, required: true, unique: true, minlength: 5 },
phone: { type: String, required: false },
street: { type: String, required: true },
zip: { type: String, required: true },
city: { type: String, required: true },
},
{ timestamps: true, collation: { locale: 'de', strength: 1 } }
)
export default <BookerModel>mongoose.models.Booker ||
mongoose.model<BookerDocument, BookerModel>('Booker', BookerSchema)

View File

@@ -3,13 +3,17 @@ import { v4 as uuidv4 } from 'uuid'
import { dateFormatBackend, getDays, nowInTz } from '../helpers/date' import { dateFormatBackend, getDays, nowInTz } from '../helpers/date'
import { Bill } from './bill' import { Bill } from './bill'
import { Booker } from './booker'
import { BOOKING_STATUS, VALIDATION_ERRORS } from './enums' import { BOOKING_STATUS, VALIDATION_ERRORS } from './enums'
import { getBookedDays } from './index' import { getBookedDays } from './index'
export type Booking = { export type Booking = {
uuid: string uuid: string
booker?: Booker name: string
email: string
phone: string
street: string
zip: string
city: string
bill?: Bill bill?: Bill
startDate: string startDate: string
endDate: string endDate: string
@@ -36,11 +40,12 @@ const BookingSchema = new mongoose.Schema<BookingDocument>(
default: uuidv4, default: uuidv4,
index: true, index: true,
}, },
booker: { name: { type: String, required: true },
type: mongoose.Schema.Types.ObjectId, email: { type: String, required: true, minlength: 5 },
ref: 'Booker', phone: { type: String, required: false },
required: true, street: { type: String, required: true },
}, zip: { type: String, required: true },
city: { type: String, required: true },
bill: { bill: {
type: mongoose.Schema.Types.ObjectId, type: mongoose.Schema.Types.ObjectId,
ref: 'Bill', ref: 'Bill',

View File

@@ -1,5 +1,4 @@
import * as mongoose from 'mongoose' import * as mongoose from 'mongoose'
import BookerModel, { Booker } from './booker'
import BookingModel, { Booking, BookingDocument } from './booking' import BookingModel, { Booking, BookingDocument } from './booking'
import BillModel, { Bill } from './bill' import BillModel, { Bill } from './bill'
import { BOOKING_STATUS } from './enums' import { BOOKING_STATUS } from './enums'
@@ -20,7 +19,9 @@ function connect(): Promise<typeof mongoose> {
return connectedPromise return connectedPromise
} }
export async function getBookedDays(uuidsToIngore?: string[]): Promise<string[]> { export async function getBookedDays(
uuidsToIngore?: string[]
): Promise<string[]> {
await connect() await connect()
return BookingModel.findBookedDays(uuidsToIngore) return BookingModel.findBookedDays(uuidsToIngore)
} }
@@ -33,14 +34,14 @@ export async function getBookingByUUID(uuid: string): Promise<BookingDocument> {
export async function getBookings({ export async function getBookings({
status = [BOOKING_STATUS.CONFIRMED, BOOKING_STATUS.REQUESTED], status = [BOOKING_STATUS.CONFIRMED, BOOKING_STATUS.REQUESTED],
startDateGreaterThan = '2000-01-01T00:00:00Z', startDateGreaterThan = '2000-01-01T00:00:00Z',
}: { status?: BOOKING_STATUS[]; startDateGreaterThan?: string } = {}): Promise<BookingDocument[]> { }: { status?: BOOKING_STATUS[]; startDateGreaterThan?: string } = {}): Promise<
BookingDocument[]
> {
await connect() await connect()
return await BookingModel.find({ return await BookingModel.find({
status: { $in: status }, status: { $in: status },
startDate: { $gte: startDateGreaterThan }, startDate: { $gte: startDateGreaterThan },
}) }).exec()
.populate('booker')
.exec()
} }
export async function createBooking({ export async function createBooking({
@@ -55,7 +56,7 @@ export async function createBooking({
street, street,
zip, zip,
city, city,
}: Booking & Booker): Promise<Booking> { }: Booking): Promise<Booking> {
await connect() await connect()
const booking = new BookingModel({ const booking = new BookingModel({
startDate, startDate,
@@ -63,17 +64,15 @@ export async function createBooking({
purpose, purpose,
org, org,
destination, destination,
name,
email,
phone,
street,
zip,
city,
}) })
let booker = await BookerModel.findOne({ email }).exec()
if (!booker) {
booker = new BookerModel({ name, email, phone, street, zip, city })
await booker.save()
}
booking.booker = booker._id
await booking.save() await booking.save()
await booking.populate('booker').execPopulate()
return booking.toJSON() return booking.toJSON()
} }

View File

@@ -21,7 +21,7 @@ export function generateCalendarEntry(booking: Booking): string {
duration: { days: booking.days.length }, duration: { days: booking.days.length },
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.booker.name} description: `Gebucht auf ${booking.name}
Buchungs-Link: ${getBaseURL()}/booking/${booking.uuid} Buchungs-Link: ${getBaseURL()}/booking/${booking.uuid}
`, `,
@@ -39,18 +39,27 @@ Buchungs-Link: ${getBaseURL()}/booking/${booking.uuid}
} }
export function generateBookedCalendar(bookings: Booking[]): string { export function generateBookedCalendar(bookings: Booking[]): string {
const events = bookings.map((booking): { productId: string; calName: string; start: [number, number, number]; startOutputType: 'local' | 'utc'; duration: { days: number }; title: string; description: string; status: EventStatus } => ({ const events = bookings.map((booking): {
productId: string
calName: string
start: [number, number, number]
startOutputType: 'local' | 'utc'
duration: { days: number }
title: string
description: string
status: EventStatus
} => ({
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.days[0]),
startOutputType: 'local', startOutputType: 'local',
duration: { days: booking.days.length }, duration: { days: booking.days.length },
title: `Buchung ${booking.booker.name}`, title: `Buchung ${booking.name}`,
description: `Name: ${booking.booker.name} description: `Name: ${booking.name}
Zeitraum: ${daysFormatFrontend(booking.days)} Zeitraum: ${daysFormatFrontend(booking.days)}
Email: ${booking.booker.email} Email: ${booking.email}
Telefon: ${booking.booker.phone} Telefon: ${booking.phone}
Link: ${getBaseURL()}/admin/booking/${booking.uuid} Link: ${getBaseURL()}/admin/booking/${booking.uuid}
`, `,

View File

@@ -32,7 +32,7 @@ Tel. 0151/212 253 62
` `
function getReceivedBookingBookerText(booking: Booking): string { function getReceivedBookingBookerText(booking: Booking): string {
return `Hallo liebe/r ${booking.booker.name}, return `Hallo liebe/r ${booking.name},
Vielen Dank für Deine Buchungsanfrage zum ${daysFormatFrontend(booking.days)}! Vielen Dank für Deine Buchungsanfrage zum ${daysFormatFrontend(booking.days)}!
@@ -49,7 +49,7 @@ ${footer}
} }
function getBookingConfirmedText(booking: Booking): string { function getBookingConfirmedText(booking: Booking): string {
return `Hallo liebe/r ${booking.booker.name}, return `Hallo liebe/r ${booking.name},
deine Buchunganfrage zum ${daysFormatFrontend( deine Buchunganfrage zum ${daysFormatFrontend(
booking.days booking.days
@@ -65,7 +65,7 @@ ${footer}
` `
} }
function getBookingRejectedText(booking: Booking): string { function getBookingRejectedText(booking: Booking): string {
return `Hallo liebe/r ${booking.booker.name}, return `Hallo liebe/r ${booking.name},
es tut uns leid aber deine Buchungsanfrage zum ${daysFormatFrontend( es tut uns leid aber deine Buchungsanfrage zum ${daysFormatFrontend(
booking.days booking.days
@@ -86,7 +86,9 @@ es ging folgende Buchung ein: ${getBaseURL()}/admin/booking/${booking.uuid}
MfG` MfG`
} }
export async function sendReceivedBookingAdminMail(booking: Booking): Promise<void> { export async function sendReceivedBookingAdminMail(
booking: Booking
): Promise<void> {
try { try {
await sendMail({ await sendMail({
to: [{ email: ADMIN_EMAIL }], to: [{ email: ADMIN_EMAIL }],
@@ -102,10 +104,12 @@ export async function sendReceivedBookingAdminMail(booking: Booking): Promise<vo
} }
} }
export async function sendReceivedBookingBookerMail(booking: Booking): Promise<void> { export async function sendReceivedBookingBookerMail(
booking: Booking
): Promise<void> {
try { try {
await sendMail({ await sendMail({
to: [{ email: booking.booker.email, name: booking.booker.name }], to: [{ email: booking.email, name: booking.name }],
from: { email: FROM_EMAIL, name: 'Pfadi-Bussle Wart' }, from: { email: FROM_EMAIL, name: 'Pfadi-Bussle Wart' },
subject: `Deine Pfadi-Bussle Buchung ist eingegangen!`, subject: `Deine Pfadi-Bussle Buchung ist eingegangen!`,
textPlainContent: getReceivedBookingBookerText(booking), textPlainContent: getReceivedBookingBookerText(booking),
@@ -121,7 +125,7 @@ export async function sendReceivedBookingBookerMail(booking: Booking): Promise<v
export async function sendBookingConfirmed(booking: Booking): Promise<void> { export async function sendBookingConfirmed(booking: Booking): Promise<void> {
try { try {
await sendMail({ await sendMail({
to: [{ email: booking.booker.email, name: booking.booker.name }], to: [{ email: booking.email, name: booking.name }],
from: { email: FROM_EMAIL, name: 'Pfadi-Bussle Wart' }, from: { email: FROM_EMAIL, name: 'Pfadi-Bussle Wart' },
subject: `Deine Pfadi-Bussle Buchung wurde bestätigt!`, subject: `Deine Pfadi-Bussle Buchung wurde bestätigt!`,
textPlainContent: getBookingConfirmedText(booking), textPlainContent: getBookingConfirmedText(booking),
@@ -146,7 +150,7 @@ export async function sendBookingConfirmed(booking: Booking): Promise<void> {
export async function sendBookingRejected(booking: Booking): Promise<void> { export async function sendBookingRejected(booking: Booking): Promise<void> {
try { try {
await sendMail({ await sendMail({
to: [{ email: booking.booker.email, name: booking.booker.name }], to: [{ email: booking.email, name: booking.name }],
from: { email: FROM_EMAIL, name: 'Pfadi-Bussle Wart' }, from: { email: FROM_EMAIL, name: 'Pfadi-Bussle Wart' },
subject: `Deine Pfadi-Bussle Buchung wurde abgelehnt!`, subject: `Deine Pfadi-Bussle Buchung wurde abgelehnt!`,
textPlainContent: getBookingRejectedText(booking), textPlainContent: getBookingRejectedText(booking),

View File

@@ -7,8 +7,7 @@ function getStorage() {
} }
export function storeBookingData(booking: Booking) { export function storeBookingData(booking: Booking) {
const { name, email, street, zip, city } = booking.booker const { name, email, street, zip, city, org } = booking
const { org } = booking
getStorage().setItem( getStorage().setItem(
BOOKING_DATA_KEY, BOOKING_DATA_KEY,

View File

@@ -48,7 +48,6 @@ export const getServerSideBooking = async (
return { props: { booking: null } } return { props: { booking: null } }
} }
await booking.populate('booker').execPopulate()
await booking.populate('bill').execPopulate() await booking.populate('bill').execPopulate()
// TODO: hack, not sure why _id is not serilizable // TODO: hack, not sure why _id is not serilizable

View File

@@ -158,7 +158,7 @@ export default function BookingBillPage({
{daysFormatFrontend(booking.days)} {daysFormatFrontend(booking.days)}
</div> </div>
<div> <div>
<strong>Bucher:</strong> {booking.booker.name} <strong>Bucher:</strong> {booking.name}
</div> </div>
<div> <div>
<strong>Buchungsstatus:</strong>{' '} <strong>Buchungsstatus:</strong>{' '}

View File

@@ -74,7 +74,7 @@ export default function ShowBookingAdmin({
<strong>Buchungszeitraum:</strong> {daysFormatFrontend(booking.days)} <strong>Buchungszeitraum:</strong> {daysFormatFrontend(booking.days)}
</div> </div>
<div> <div>
<strong>Bucher:</strong> {booking.booker.name} <strong>Bucher:</strong> {booking.name}
</div> </div>
<div> <div>
<strong>Buchungsstatus:</strong> {getBookingStatus(booking.status)} <strong>Buchungsstatus:</strong> {getBookingStatus(booking.status)}

View File

@@ -59,13 +59,13 @@ export default function AdminRecentBookings({ bookings }) {
<div className="bg-white px-2 py-3 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6"> <div className="bg-white px-2 py-3 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
<dt className="text-sm font-medium text-gray-500">Bucher</dt> <dt className="text-sm font-medium text-gray-500">Bucher</dt>
<dd className="mt-1 text-sm text-gray-900 sm:mt-0 sm:col-span-2"> <dd className="mt-1 text-sm text-gray-900 sm:mt-0 sm:col-span-2">
{booking.booker.name} {booking.name}
</dd> </dd>
</div> </div>
<div className="bg-gray-100 px-2 py-3 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6"> <div className="bg-gray-100 px-2 py-3 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
<dt className="text-sm font-medium text-gray-500">Email</dt> <dt className="text-sm font-medium text-gray-500">Email</dt>
<dd className="mt-1 text-sm text-gray-900 sm:mt-0 sm:col-span-2"> <dd className="mt-1 text-sm text-gray-900 sm:mt-0 sm:col-span-2">
{booking.booker.email} {booking.email}
</dd> </dd>
</div> </div>
<div className="bg-white px-2 py-3 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6"> <div className="bg-white px-2 py-3 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">

View File

@@ -51,7 +51,6 @@ export default withSession(async function userHandler(
booking.set(req.body) booking.set(req.body)
try { try {
await booking.save() await booking.save()
await booking.populate('booker').execPopulate()
res.status(200).json(booking.toJSON()) res.status(200).json(booking.toJSON())
} catch (error) { } catch (error) {
res.status(400).end(`Failed to save booking: ${error.message}`) res.status(400).end(`Failed to save booking: ${error.message}`)

View File

@@ -30,15 +30,11 @@ export default async function userHandler(
return return
} }
console.log( console.log(`received booking ${booking.uuid} from {booking.email}`)
`received booking ${booking.uuid} from {booking.booker.email}`
)
await sendReceivedBookingAdminMail(booking) await sendReceivedBookingAdminMail(booking)
console.log(`send booking ${booking.uuid} received to admin`) console.log(`send booking ${booking.uuid} received to admin`)
await sendReceivedBookingBookerMail(booking) await sendReceivedBookingBookerMail(booking)
console.log( console.log(`send booking ${booking.uuid} received to {booking.email}`)
`send booking ${booking.uuid} received to {booking.booker.email}`
)
break break
default: default:
res.setHeader('Allow', ['POST']) res.setHeader('Allow', ['POST'])