mirror of
https://github.com/tomru/pfadi-bussle.git
synced 2026-03-03 06:27:11 +01:00
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:
@@ -3,13 +3,11 @@ import { useRouter } from 'next/router'
|
||||
import { clearBookingData, loadBookingData } from '../helpers/storage'
|
||||
|
||||
import { createBooking } from '../helpers/booking'
|
||||
import { Booker } from '../db/booker'
|
||||
import { Booking } from '../db/booking'
|
||||
|
||||
export type BookFormData = Omit<Booking, 'uuid'> &
|
||||
Booker & {
|
||||
storeData?: boolean
|
||||
}
|
||||
export type BookFormData = Omit<Booking, 'uuid'> & {
|
||||
storeData?: boolean
|
||||
}
|
||||
|
||||
type BookingProviderState = {
|
||||
postData?: boolean
|
||||
|
||||
31
db/booker.ts
31
db/booker.ts
@@ -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)
|
||||
@@ -3,13 +3,17 @@ import { v4 as uuidv4 } from 'uuid'
|
||||
import { dateFormatBackend, getDays, nowInTz } from '../helpers/date'
|
||||
|
||||
import { Bill } from './bill'
|
||||
import { Booker } from './booker'
|
||||
import { BOOKING_STATUS, VALIDATION_ERRORS } from './enums'
|
||||
import { getBookedDays } from './index'
|
||||
|
||||
export type Booking = {
|
||||
uuid: string
|
||||
booker?: Booker
|
||||
name: string
|
||||
email: string
|
||||
phone: string
|
||||
street: string
|
||||
zip: string
|
||||
city: string
|
||||
bill?: Bill
|
||||
startDate: string
|
||||
endDate: string
|
||||
@@ -36,11 +40,12 @@ const BookingSchema = new mongoose.Schema<BookingDocument>(
|
||||
default: uuidv4,
|
||||
index: true,
|
||||
},
|
||||
booker: {
|
||||
type: mongoose.Schema.Types.ObjectId,
|
||||
ref: 'Booker',
|
||||
required: 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',
|
||||
|
||||
29
db/index.ts
29
db/index.ts
@@ -1,5 +1,4 @@
|
||||
import * as mongoose from 'mongoose'
|
||||
import BookerModel, { Booker } from './booker'
|
||||
import BookingModel, { Booking, BookingDocument } from './booking'
|
||||
import BillModel, { Bill } from './bill'
|
||||
import { BOOKING_STATUS } from './enums'
|
||||
@@ -20,7 +19,9 @@ function connect(): Promise<typeof mongoose> {
|
||||
return connectedPromise
|
||||
}
|
||||
|
||||
export async function getBookedDays(uuidsToIngore?: string[]): Promise<string[]> {
|
||||
export async function getBookedDays(
|
||||
uuidsToIngore?: string[]
|
||||
): Promise<string[]> {
|
||||
await connect()
|
||||
return BookingModel.findBookedDays(uuidsToIngore)
|
||||
}
|
||||
@@ -33,14 +34,14 @@ export async function getBookingByUUID(uuid: string): Promise<BookingDocument> {
|
||||
export async function getBookings({
|
||||
status = [BOOKING_STATUS.CONFIRMED, BOOKING_STATUS.REQUESTED],
|
||||
startDateGreaterThan = '2000-01-01T00:00:00Z',
|
||||
}: { status?: BOOKING_STATUS[]; startDateGreaterThan?: string } = {}): Promise<BookingDocument[]> {
|
||||
}: { status?: BOOKING_STATUS[]; startDateGreaterThan?: string } = {}): Promise<
|
||||
BookingDocument[]
|
||||
> {
|
||||
await connect()
|
||||
return await BookingModel.find({
|
||||
status: { $in: status },
|
||||
startDate: { $gte: startDateGreaterThan },
|
||||
})
|
||||
.populate('booker')
|
||||
.exec()
|
||||
}).exec()
|
||||
}
|
||||
|
||||
export async function createBooking({
|
||||
@@ -55,7 +56,7 @@ export async function createBooking({
|
||||
street,
|
||||
zip,
|
||||
city,
|
||||
}: Booking & Booker): Promise<Booking> {
|
||||
}: Booking): Promise<Booking> {
|
||||
await connect()
|
||||
const booking = new BookingModel({
|
||||
startDate,
|
||||
@@ -63,17 +64,15 @@ export async function createBooking({
|
||||
purpose,
|
||||
org,
|
||||
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.populate('booker').execPopulate()
|
||||
return booking.toJSON()
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ export function generateCalendarEntry(booking: Booking): string {
|
||||
duration: { days: booking.days.length },
|
||||
location: 'Mömpelgardgasse 25, 72348 Rosenfeld, Deutschland',
|
||||
geo: { lat: 48.287044, lon: 8.726361 },
|
||||
description: `Gebucht auf ${booking.booker.name}
|
||||
description: `Gebucht auf ${booking.name}
|
||||
|
||||
Buchungs-Link: ${getBaseURL()}/booking/${booking.uuid}
|
||||
`,
|
||||
@@ -39,18 +39,27 @@ Buchungs-Link: ${getBaseURL()}/booking/${booking.uuid}
|
||||
}
|
||||
|
||||
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',
|
||||
calName: 'Pfadi-Bussle Buchungen',
|
||||
start: convertDay(booking.days[0]),
|
||||
startOutputType: 'local',
|
||||
duration: { days: booking.days.length },
|
||||
title: `Buchung ${booking.booker.name}`,
|
||||
description: `Name: ${booking.booker.name}
|
||||
title: `Buchung ${booking.name}`,
|
||||
description: `Name: ${booking.name}
|
||||
Zeitraum: ${daysFormatFrontend(booking.days)}
|
||||
|
||||
Email: ${booking.booker.email}
|
||||
Telefon: ${booking.booker.phone}
|
||||
Email: ${booking.email}
|
||||
Telefon: ${booking.phone}
|
||||
|
||||
Link: ${getBaseURL()}/admin/booking/${booking.uuid}
|
||||
`,
|
||||
|
||||
@@ -32,7 +32,7 @@ Tel. 0151/212 253 62
|
||||
`
|
||||
|
||||
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)}!
|
||||
|
||||
@@ -49,7 +49,7 @@ ${footer}
|
||||
}
|
||||
|
||||
function getBookingConfirmedText(booking: Booking): string {
|
||||
return `Hallo liebe/r ${booking.booker.name},
|
||||
return `Hallo liebe/r ${booking.name},
|
||||
|
||||
deine Buchunganfrage zum ${daysFormatFrontend(
|
||||
booking.days
|
||||
@@ -65,7 +65,7 @@ ${footer}
|
||||
`
|
||||
}
|
||||
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(
|
||||
booking.days
|
||||
@@ -86,7 +86,9 @@ es ging folgende Buchung ein: ${getBaseURL()}/admin/booking/${booking.uuid}
|
||||
MfG`
|
||||
}
|
||||
|
||||
export async function sendReceivedBookingAdminMail(booking: Booking): Promise<void> {
|
||||
export async function sendReceivedBookingAdminMail(
|
||||
booking: Booking
|
||||
): Promise<void> {
|
||||
try {
|
||||
await sendMail({
|
||||
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 {
|
||||
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' },
|
||||
subject: `Deine Pfadi-Bussle Buchung ist eingegangen!`,
|
||||
textPlainContent: getReceivedBookingBookerText(booking),
|
||||
@@ -121,7 +125,7 @@ export async function sendReceivedBookingBookerMail(booking: Booking): Promise<v
|
||||
export async function sendBookingConfirmed(booking: Booking): Promise<void> {
|
||||
try {
|
||||
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' },
|
||||
subject: `Deine Pfadi-Bussle Buchung wurde bestätigt!`,
|
||||
textPlainContent: getBookingConfirmedText(booking),
|
||||
@@ -146,7 +150,7 @@ export async function sendBookingConfirmed(booking: Booking): Promise<void> {
|
||||
export async function sendBookingRejected(booking: Booking): Promise<void> {
|
||||
try {
|
||||
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' },
|
||||
subject: `Deine Pfadi-Bussle Buchung wurde abgelehnt!`,
|
||||
textPlainContent: getBookingRejectedText(booking),
|
||||
|
||||
@@ -7,8 +7,7 @@ function getStorage() {
|
||||
}
|
||||
|
||||
export function storeBookingData(booking: Booking) {
|
||||
const { name, email, street, zip, city } = booking.booker
|
||||
const { org } = booking
|
||||
const { name, email, street, zip, city, org } = booking
|
||||
|
||||
getStorage().setItem(
|
||||
BOOKING_DATA_KEY,
|
||||
|
||||
@@ -48,7 +48,6 @@ export const getServerSideBooking = async (
|
||||
return { props: { booking: null } }
|
||||
}
|
||||
|
||||
await booking.populate('booker').execPopulate()
|
||||
await booking.populate('bill').execPopulate()
|
||||
|
||||
// TODO: hack, not sure why _id is not serilizable
|
||||
|
||||
@@ -158,7 +158,7 @@ export default function BookingBillPage({
|
||||
{daysFormatFrontend(booking.days)}
|
||||
</div>
|
||||
<div>
|
||||
<strong>Bucher:</strong> {booking.booker.name}
|
||||
<strong>Bucher:</strong> {booking.name}
|
||||
</div>
|
||||
<div>
|
||||
<strong>Buchungsstatus:</strong>{' '}
|
||||
|
||||
@@ -74,7 +74,7 @@ export default function ShowBookingAdmin({
|
||||
<strong>Buchungszeitraum:</strong> {daysFormatFrontend(booking.days)}
|
||||
</div>
|
||||
<div>
|
||||
<strong>Bucher:</strong> {booking.booker.name}
|
||||
<strong>Bucher:</strong> {booking.name}
|
||||
</div>
|
||||
<div>
|
||||
<strong>Buchungsstatus:</strong> {getBookingStatus(booking.status)}
|
||||
|
||||
@@ -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">
|
||||
<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">
|
||||
{booking.booker.name}
|
||||
{booking.name}
|
||||
</dd>
|
||||
</div>
|
||||
<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>
|
||||
<dd className="mt-1 text-sm text-gray-900 sm:mt-0 sm:col-span-2">
|
||||
{booking.booker.email}
|
||||
{booking.email}
|
||||
</dd>
|
||||
</div>
|
||||
<div className="bg-white px-2 py-3 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
||||
|
||||
@@ -51,7 +51,6 @@ export default withSession(async function userHandler(
|
||||
booking.set(req.body)
|
||||
try {
|
||||
await booking.save()
|
||||
await booking.populate('booker').execPopulate()
|
||||
res.status(200).json(booking.toJSON())
|
||||
} catch (error) {
|
||||
res.status(400).end(`Failed to save booking: ${error.message}`)
|
||||
|
||||
@@ -30,15 +30,11 @@ export default async function userHandler(
|
||||
return
|
||||
}
|
||||
|
||||
console.log(
|
||||
`received booking ${booking.uuid} from {booking.booker.email}`
|
||||
)
|
||||
console.log(`received booking ${booking.uuid} from {booking.email}`)
|
||||
await sendReceivedBookingAdminMail(booking)
|
||||
console.log(`send booking ${booking.uuid} received to admin`)
|
||||
await sendReceivedBookingBookerMail(booking)
|
||||
console.log(
|
||||
`send booking ${booking.uuid} received to {booking.booker.email}`
|
||||
)
|
||||
console.log(`send booking ${booking.uuid} received to {booking.email}`)
|
||||
break
|
||||
default:
|
||||
res.setHeader('Allow', ['POST'])
|
||||
|
||||
Reference in New Issue
Block a user