mirror of
https://github.com/tomru/pfadi-bussle.git
synced 2026-03-03 06:27:11 +01:00
prettier all the things
This commit is contained in:
committed by
Thomas Ruoff
parent
c35d3009c6
commit
36f8719531
@@ -19,34 +19,34 @@ export default function DateSelect() {
|
|||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
className="my-6 max-w-lg"
|
className="my-6 max-w-lg"
|
||||||
/>
|
/>
|
||||||
</InputWrapper>
|
</InputWrapper>
|
||||||
<div className="flex flex-wrap -mx-3 mb-2">
|
<div className="flex flex-wrap -mx-3 mb-2">
|
||||||
<div className="w-full md:w-2/5 px-3 mb-2 md:mb-0">
|
<div className="w-full md:w-2/5 px-3 mb-2 md:mb-0">
|
||||||
<Input
|
<Input
|
||||||
label="Von"
|
label="Von"
|
||||||
type="date"
|
type="date"
|
||||||
className=""
|
className=""
|
||||||
name="startDate"
|
name="startDate"
|
||||||
value={startDate || ''}
|
value={startDate || ''}
|
||||||
onChange={onChangeEvent}
|
onChange={onChangeEvent}
|
||||||
min={today}
|
min={today}
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
</div>
|
|
||||||
<div className="w-full md:w-2/5 px-3 mb-2 md:mb-0">
|
|
||||||
<Input
|
|
||||||
required
|
|
||||||
label="Bis"
|
|
||||||
type="date"
|
|
||||||
className=""
|
|
||||||
name="endDate"
|
|
||||||
value={endDate || ''}
|
|
||||||
placeholder="Von"
|
|
||||||
onChange={onChangeEvent}
|
|
||||||
min={startDate || today}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div className="w-full md:w-2/5 px-3 mb-2 md:mb-0">
|
||||||
|
<Input
|
||||||
|
required
|
||||||
|
label="Bis"
|
||||||
|
type="date"
|
||||||
|
className=""
|
||||||
|
name="endDate"
|
||||||
|
value={endDate || ''}
|
||||||
|
placeholder="Von"
|
||||||
|
onChange={onChangeEvent}
|
||||||
|
min={startDate || today}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,10 @@ function BookForm() {
|
|||||||
{dataStoredLoaded && (
|
{dataStoredLoaded && (
|
||||||
<p className="mb-6 info-message">
|
<p className="mb-6 info-message">
|
||||||
Buchungsdaten wurden aus Deinem Browser geladen und vorausgefüllt.{' '}
|
Buchungsdaten wurden aus Deinem Browser geladen und vorausgefüllt.{' '}
|
||||||
<a className="font-medium text-blue-400 underline cursor-pointer hover:text-blue-600" onClick={forgetData}>
|
<a
|
||||||
|
className="font-medium text-blue-400 underline cursor-pointer hover:text-blue-600"
|
||||||
|
onClick={forgetData}
|
||||||
|
>
|
||||||
Daten wieder vergessen
|
Daten wieder vergessen
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -9,7 +9,10 @@ export default function Denied() {
|
|||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
signIn()
|
signIn()
|
||||||
}}>Melde dich an um diese Seite zu sehen.</a>
|
}}
|
||||||
|
>
|
||||||
|
Melde dich an um diese Seite zu sehen.
|
||||||
|
</a>
|
||||||
</p>
|
</p>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -7,10 +7,18 @@ type InputProps = React.InputHTMLAttributes<HTMLInputElement> & {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function Input(props: InputProps) {
|
export default function Input(props: InputProps) {
|
||||||
const { label, name, required, type = 'text', className = "", ...rest } = props
|
const {
|
||||||
|
label,
|
||||||
|
name,
|
||||||
|
required,
|
||||||
|
type = 'text',
|
||||||
|
className = '',
|
||||||
|
...rest
|
||||||
|
} = props
|
||||||
|
|
||||||
const defaultClasses = "appearance-none bg-gray-50 text-gray-500 border rounded py-2 px-3 mb-3 leading-tight disabled:bg-gray-200 disabled:cursor-not-allowed focus: outline-none focus:bg-white w-full"
|
const defaultClasses =
|
||||||
const classes = `${defaultClasses} ${className}`;
|
'appearance-none bg-gray-50 text-gray-500 border rounded py-2 px-3 mb-3 leading-tight disabled:bg-gray-200 disabled:cursor-not-allowed focus: outline-none focus:bg-white w-full'
|
||||||
|
const classes = `${defaultClasses} ${className}`
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<InputWrapper label={label} name={name} required={required}>
|
<InputWrapper label={label} name={name} required={required}>
|
||||||
|
|||||||
@@ -13,7 +13,10 @@ export default function Input(props: {
|
|||||||
<>
|
<>
|
||||||
<div className="flex flex-wrap -mx-3 mb-2">
|
<div className="flex flex-wrap -mx-3 mb-2">
|
||||||
<div className="w-full px-3 mb-2">
|
<div className="w-full px-3 mb-2">
|
||||||
<label className="block uppercase tracking-wide text-gray-500 text-xs font-bold mb-2" htmlFor={name}>
|
<label
|
||||||
|
className="block uppercase tracking-wide text-gray-500 text-xs font-bold mb-2"
|
||||||
|
htmlFor={name}
|
||||||
|
>
|
||||||
{label} {required && <Required />}
|
{label} {required && <Required />}
|
||||||
</label>
|
</label>
|
||||||
{children}
|
{children}
|
||||||
|
|||||||
@@ -1,32 +1,36 @@
|
|||||||
const H1 = (props: any) => (
|
const H1 = (props: any) => (
|
||||||
<h1
|
<h1
|
||||||
className="pb-2 mt-6 mb-4 text-4xl font-semibold leading-tight border-b"
|
className="pb-2 mt-6 mb-4 text-4xl font-semibold leading-tight border-b"
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
const H2 = (props: any) => (
|
const H2 = (props: any) => (
|
||||||
<h2
|
<h2
|
||||||
className="pb-2 mt-6 mb-4 text-2xl font-semibold leading-tight border-b"
|
className="pb-2 mt-6 mb-4 text-2xl font-semibold leading-tight border-b"
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
const H3 = (props: any) => (
|
const H3 = (props: any) => (
|
||||||
<h3 className="mt-6 mb-4 text-lg font-semibold leading-snug" {...props} />
|
<h3 className="mt-6 mb-4 text-lg font-semibold leading-snug" {...props} />
|
||||||
)
|
)
|
||||||
const H4 = (props: any) => (
|
const H4 = (props: any) => (
|
||||||
<h4 className="mt-6 mb-4 text-base font-semibold leading-none" {...props} />
|
<h4 className="mt-6 mb-4 text-base font-semibold leading-none" {...props} />
|
||||||
)
|
)
|
||||||
const H5 = (props: any) => (
|
const H5 = (props: any) => (
|
||||||
<h5 className="mt-6 mb-4 text-sm font-semibold leading-tight" {...props} />
|
<h5 className="mt-6 mb-4 text-sm font-semibold leading-tight" {...props} />
|
||||||
)
|
)
|
||||||
const H6 = (props: any) => (
|
const H6 = (props: any) => (
|
||||||
<h6
|
<h6
|
||||||
className="mt-6 mb-4 text-sm font-semibold leading-tight text-gray-600"
|
className="mt-6 mb-4 text-sm font-semibold leading-tight text-gray-600"
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
const UL = (props: any) => <ul className="pl-8 text-base list-disc" {...props} />
|
const UL = (props: any) => (
|
||||||
const OL = (props: any) => <ol className="pl-8 text-base list-decimal" {...props} />
|
<ul className="pl-8 text-base list-disc" {...props} />
|
||||||
|
)
|
||||||
|
const OL = (props: any) => (
|
||||||
|
<ol className="pl-8 text-base list-decimal" {...props} />
|
||||||
|
)
|
||||||
|
|
||||||
const MdComponents = {
|
const MdComponents = {
|
||||||
h1: H1,
|
h1: H1,
|
||||||
@@ -39,4 +43,4 @@ const MdComponents = {
|
|||||||
ol: OL,
|
ol: OL,
|
||||||
}
|
}
|
||||||
|
|
||||||
export default MdComponents;
|
export default MdComponents
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import { useSession } from 'next-auth/react'
|
|||||||
|
|
||||||
import User from './user'
|
import User from './user'
|
||||||
|
|
||||||
|
|
||||||
const pathNameLabelMap = {
|
const pathNameLabelMap = {
|
||||||
'/login': 'Login',
|
'/login': 'Login',
|
||||||
'/admin': 'Buchungsübersicht',
|
'/admin': 'Buchungsübersicht',
|
||||||
@@ -21,7 +20,7 @@ function getPathNameMap(route: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function Navigation() {
|
export default function Navigation() {
|
||||||
const { data, status } = useSession();
|
const { data, status } = useSession()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
||||||
const pathname = router.pathname
|
const pathname = router.pathname
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
import { useSession, signOut } from 'next-auth/react'
|
import { useSession, signOut } from 'next-auth/react'
|
||||||
|
|
||||||
|
|
||||||
export default function User() {
|
export default function User() {
|
||||||
const { data, status } = useSession();
|
const { data, status } = useSession()
|
||||||
|
|
||||||
if (status === 'loading' || !data?.user?.email) {
|
if (status === 'loading' || !data?.user?.email) {
|
||||||
return null;
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -34,9 +34,8 @@ type BookAction = {
|
|||||||
payload?: any
|
payload?: any
|
||||||
}
|
}
|
||||||
|
|
||||||
export const BookContext: React.Context<BookProvider> = React.createContext<
|
export const BookContext: React.Context<BookProvider> =
|
||||||
BookProvider
|
React.createContext<BookProvider>(null)
|
||||||
>(null)
|
|
||||||
|
|
||||||
export const ACTIONS = {
|
export const ACTIONS = {
|
||||||
SET_FORM_DATA: 'setFormData',
|
SET_FORM_DATA: 'setFormData',
|
||||||
|
|||||||
@@ -22,8 +22,8 @@ export type Booking = {
|
|||||||
purpose?: string
|
purpose?: string
|
||||||
org?: string
|
org?: string
|
||||||
destination?: string
|
destination?: string
|
||||||
days?: string[],
|
days?: string[]
|
||||||
calendarEventId: string,
|
calendarEventId: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export type BookingDocument = Booking &
|
export type BookingDocument = Booking &
|
||||||
@@ -128,37 +128,43 @@ BookingSchema.pre('save', async function (next: () => void): Promise<void> {
|
|||||||
|
|
||||||
if (!booking.calendarEventId) {
|
if (!booking.calendarEventId) {
|
||||||
// create calendar event before saving to database
|
// create calendar event before saving to database
|
||||||
await createCalendarEvent(booking);
|
await createCalendarEvent(booking)
|
||||||
} else if ([BOOKING_STATUS.CANCELED, BOOKING_STATUS.REJECTED].includes(booking.status)) {
|
} 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
|
// event has been canceled or rejected, delete calendar event again to free up the slot
|
||||||
await deleteCalendarEvent(booking);
|
await deleteCalendarEvent(booking)
|
||||||
}
|
}
|
||||||
|
|
||||||
next();
|
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()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
export default (mongoose.models.Booking ||
|
export default (mongoose.models.Booking ||
|
||||||
mongoose.model<BookingDocument, BookingModel>('Booking', BookingSchema)) as BookingModel
|
mongoose.model<BookingDocument, BookingModel>(
|
||||||
|
'Booking',
|
||||||
|
BookingSchema
|
||||||
|
)) as BookingModel
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { BOOKING_STATUS } from './enums'
|
|||||||
|
|
||||||
let connectedPromise: Promise<mongoose.Mongoose>
|
let connectedPromise: Promise<mongoose.Mongoose>
|
||||||
|
|
||||||
export const MONGO_URI = process.env.MONGO_URI;
|
export const MONGO_URI = process.env.MONGO_URI
|
||||||
|
|
||||||
export const MONGODB_OPTIONS = {
|
export const MONGODB_OPTIONS = {
|
||||||
useCreateIndex: true,
|
useCreateIndex: true,
|
||||||
@@ -45,7 +45,9 @@ export async function getBookings({
|
|||||||
return await BookingModel.find({
|
return await BookingModel.find({
|
||||||
status: { $in: status },
|
status: { $in: status },
|
||||||
startDate: { $gte: startDateGreaterThan },
|
startDate: { $gte: startDateGreaterThan },
|
||||||
}).sort({ startDate: -1 }).exec()
|
})
|
||||||
|
.sort({ startDate: -1 })
|
||||||
|
.exec()
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function createBooking({
|
export async function createBooking({
|
||||||
|
|||||||
@@ -39,23 +39,26 @@ Buchungs-Link: ${getBaseURL()}/bookings/${booking.uuid}
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function generateBookedCalendar(bookings: Booking[]): string {
|
export function generateBookedCalendar(bookings: Booking[]): string {
|
||||||
const events = bookings.map((booking): {
|
const events = bookings.map(
|
||||||
productId: string
|
(
|
||||||
calName: string
|
booking
|
||||||
start: [number, number, number]
|
): {
|
||||||
startOutputType: 'local' | 'utc'
|
productId: string
|
||||||
duration: { days: number }
|
calName: string
|
||||||
title: string
|
start: [number, number, number]
|
||||||
description: string
|
startOutputType: 'local' | 'utc'
|
||||||
status: EventStatus
|
duration: { days: number }
|
||||||
} => ({
|
title: string
|
||||||
productId: 'app.vercel.pfadi-bussle/ics',
|
description: string
|
||||||
calName: 'Pfadi-Bussle Buchungen',
|
status: EventStatus
|
||||||
start: convertDay(booking.days[0]),
|
} => ({
|
||||||
startOutputType: 'local',
|
productId: 'app.vercel.pfadi-bussle/ics',
|
||||||
duration: { days: booking.days.length },
|
calName: 'Pfadi-Bussle Buchungen',
|
||||||
title: `Buchung ${booking.name}`,
|
start: convertDay(booking.days[0]),
|
||||||
description: `Name: ${booking.name}
|
startOutputType: 'local',
|
||||||
|
duration: { days: booking.days.length },
|
||||||
|
title: `Buchung ${booking.name}`,
|
||||||
|
description: `Name: ${booking.name}
|
||||||
Zeitraum: ${daysFormatFrontend(booking.days)}
|
Zeitraum: ${daysFormatFrontend(booking.days)}
|
||||||
|
|
||||||
Email: ${booking.email}
|
Email: ${booking.email}
|
||||||
@@ -63,11 +66,12 @@ Telefon: ${booking.phone}
|
|||||||
|
|
||||||
Link: ${getBaseURL()}/admin/bookings/${booking.uuid}
|
Link: ${getBaseURL()}/admin/bookings/${booking.uuid}
|
||||||
`,
|
`,
|
||||||
status:
|
status:
|
||||||
booking.status === BOOKING_STATUS.CONFIRMED
|
booking.status === BOOKING_STATUS.CONFIRMED
|
||||||
? ('CONFIRMED' as EventStatus)
|
? ('CONFIRMED' as EventStatus)
|
||||||
: ('TENTATIVE' as EventStatus),
|
: ('TENTATIVE' as EventStatus),
|
||||||
}))
|
})
|
||||||
|
)
|
||||||
|
|
||||||
const { error, value } = createEvents(events)
|
const { error, value } = createEvents(events)
|
||||||
|
|
||||||
|
|||||||
@@ -14,23 +14,22 @@ export type ServerSideRecentBooking = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getServerSideRecentBookings = async (): Promise<
|
export const getServerSideRecentBookings =
|
||||||
ServerSideRecentBooking
|
async (): Promise<ServerSideRecentBooking> => {
|
||||||
> => {
|
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
|
// TODO: hack, not sure why _id is not serilizable
|
||||||
const bookingsJSON = JSON.parse(
|
const bookingsJSON = JSON.parse(
|
||||||
JSON.stringify(bookings.map((b) => b.toJSON()))
|
JSON.stringify(bookings.map((b) => b.toJSON()))
|
||||||
) as object[]
|
) as object[]
|
||||||
return {
|
return {
|
||||||
props: {
|
props: {
|
||||||
bookings: bookingsJSON,
|
bookings: bookingsJSON,
|
||||||
},
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
export const getServerSideBooking = async (
|
export const getServerSideBooking = async (
|
||||||
context: any
|
context: any
|
||||||
|
|||||||
@@ -1,46 +1,44 @@
|
|||||||
|
import { google } from 'googleapis'
|
||||||
|
import { Booking } from '../db/booking'
|
||||||
|
|
||||||
import {google} from 'googleapis';
|
const keyFile = process.env.GOOGLE_SERVICE_ACCOUNT_KEY_FILE
|
||||||
import { Booking } from '../db/booking';
|
const calendarId = process.env.GOOGLE_CALENDAR_ID
|
||||||
|
|
||||||
const keyFile = process.env.GOOGLE_SERVICE_ACCOUNT_KEY_FILE;
|
|
||||||
const calendarId = process.env.GOOGLE_CALENDAR_ID;
|
|
||||||
|
|
||||||
const auth = new google.auth.GoogleAuth({
|
const auth = new google.auth.GoogleAuth({
|
||||||
keyFile,
|
keyFile,
|
||||||
scopes: [
|
scopes: [
|
||||||
'https://www.googleapis.com/auth/calendar',
|
'https://www.googleapis.com/auth/calendar',
|
||||||
'https://www.googleapis.com/auth/calendar.readonly'
|
'https://www.googleapis.com/auth/calendar.readonly',
|
||||||
],
|
],
|
||||||
});
|
})
|
||||||
|
|
||||||
const calendar = google.calendar({
|
const calendar = google.calendar({
|
||||||
version: 'v3',
|
version: 'v3',
|
||||||
auth,
|
auth,
|
||||||
});
|
})
|
||||||
|
|
||||||
export async function getNewEvents() {
|
export async function getNewEvents() {
|
||||||
const { data } = await calendar.events.list({
|
const { data } = await calendar.events.list({
|
||||||
calendarId,
|
calendarId,
|
||||||
timeMin: new Date().toISOString()}
|
timeMin: new Date().toISOString(),
|
||||||
);
|
})
|
||||||
|
|
||||||
return data.items;
|
return data.items
|
||||||
}
|
}
|
||||||
|
|
||||||
function getSummary(booking: Partial<Booking>) : string {
|
function getSummary(booking: Partial<Booking>): string {
|
||||||
let summary = "";
|
let summary = ''
|
||||||
|
|
||||||
if (booking.org) {
|
if (booking.org) {
|
||||||
summary += `${booking.org} - `;
|
summary += `${booking.org} - `
|
||||||
}
|
}
|
||||||
|
|
||||||
summary += booking.name;
|
summary += booking.name
|
||||||
|
|
||||||
return summary;
|
return summary
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function createCalendarEvent(booking : Booking) : Promise<Booking> {
|
export async function createCalendarEvent(booking: Booking): Promise<Booking> {
|
||||||
|
|
||||||
const response = await calendar.events.insert({
|
const response = await calendar.events.insert({
|
||||||
auth,
|
auth,
|
||||||
calendarId,
|
calendarId,
|
||||||
@@ -49,12 +47,12 @@ export async function createCalendarEvent(booking : Booking) : Promise<Booking>
|
|||||||
// description,
|
// description,
|
||||||
start: { date: booking.startDate },
|
start: { date: booking.startDate },
|
||||||
end: { date: booking.endDate },
|
end: { date: booking.endDate },
|
||||||
}
|
},
|
||||||
});
|
})
|
||||||
|
|
||||||
booking.calendarEventId = response.data.id;
|
booking.calendarEventId = response.data.id
|
||||||
|
|
||||||
return booking;
|
return booking
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function deleteCalendarEvent(booking: Booking) {
|
export async function deleteCalendarEvent(booking: Booking) {
|
||||||
@@ -62,9 +60,9 @@ export async function deleteCalendarEvent(booking: Booking) {
|
|||||||
auth,
|
auth,
|
||||||
calendarId,
|
calendarId,
|
||||||
eventId: booking.calendarEventId,
|
eventId: booking.calendarEventId,
|
||||||
});
|
})
|
||||||
|
|
||||||
booking.calendarEventId = null;
|
booking.calendarEventId = null
|
||||||
}
|
}
|
||||||
|
|
||||||
//export async function patchCalendarEvent(booking: { calendarEventId: string } & Partial<Booking> ) : Promise<Booking> {
|
//export async function patchCalendarEvent(booking: { calendarEventId: string } & Partial<Booking> ) : Promise<Booking> {
|
||||||
@@ -76,4 +74,3 @@ export async function deleteCalendarEvent(booking: Booking) {
|
|||||||
//
|
//
|
||||||
// return booking;
|
// return booking;
|
||||||
//}
|
//}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react'
|
||||||
|
|
||||||
import { useSession, signIn, SessionProvider } from "next-auth/react"
|
import { useSession, signIn, SessionProvider } from 'next-auth/react'
|
||||||
import '../styles/index.css'
|
import '../styles/index.css'
|
||||||
|
|
||||||
function Auth({ children }) {
|
function Auth({ children }) {
|
||||||
@@ -21,8 +21,10 @@ function Auth({ children }) {
|
|||||||
return <div>Loading...</div>
|
return <div>Loading...</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function MyApp({ Component, pageProps: { session, ...pageProps } }) {
|
export default function MyApp({
|
||||||
|
Component,
|
||||||
|
pageProps: { session, ...pageProps },
|
||||||
|
}) {
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col min-h-screen">
|
<div className="flex flex-col min-h-screen">
|
||||||
<SessionProvider session={session}>
|
<SessionProvider session={session}>
|
||||||
@@ -37,4 +39,3 @@ export default function MyApp({ Component, pageProps: { session, ...pageProps }
|
|||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ export const getServerSideProps = async (context) => {
|
|||||||
...serverSideBookingProps.props,
|
...serverSideBookingProps.props,
|
||||||
milageMax,
|
milageMax,
|
||||||
},
|
},
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const milageTarifOptions = Object.values(MILAGE_TARIFS).map((tarif) => {
|
const milageTarifOptions = Object.values(MILAGE_TARIFS).map((tarif) => {
|
||||||
@@ -134,135 +134,133 @@ function BookingBillPage({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Layout>
|
<Layout>
|
||||||
{booking && (
|
{booking && (
|
||||||
<form className="w-full" onSubmit={onSubmit}>
|
<form className="w-full" onSubmit={onSubmit}>
|
||||||
<div>
|
<div>
|
||||||
<strong>Buchungszeitraum:</strong>{' '}
|
<strong>Buchungszeitraum:</strong>{' '}
|
||||||
{daysFormatFrontend(booking.days)}
|
{daysFormatFrontend(booking.days)}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<strong>Bucher:</strong> {booking.name}
|
<strong>Bucher:</strong> {booking.name}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<strong>Buchungsstatus:</strong>{' '}
|
<strong>Buchungsstatus:</strong> {getBookingStatus(booking.status)}
|
||||||
{getBookingStatus(booking.status)}
|
</div>
|
||||||
</div>
|
<div>
|
||||||
<div>
|
<Input
|
||||||
<Input
|
label="Anfangskilometer"
|
||||||
label="Anfangskilometer"
|
name="milageStart"
|
||||||
name="milageStart"
|
required
|
||||||
required
|
value={milageStart}
|
||||||
value={milageStart}
|
type="number"
|
||||||
type="number"
|
onChange={(e: React.ChangeEvent<React.ElementRef<'input'>>) =>
|
||||||
onChange={(e: React.ChangeEvent<React.ElementRef<'input'>>) =>
|
setMilageStart(Number(e.target.value))
|
||||||
setMilageStart(Number(e.target.value))
|
}
|
||||||
}
|
/>
|
||||||
/>
|
<Input
|
||||||
<Input
|
label="Endkilometer"
|
||||||
label="Endkilometer"
|
name="milageEnd"
|
||||||
name="milageEnd"
|
required
|
||||||
required
|
value={milageEnd}
|
||||||
value={milageEnd}
|
type="number"
|
||||||
type="number"
|
onChange={(e: React.ChangeEvent<React.ElementRef<'input'>>) =>
|
||||||
onChange={(e: React.ChangeEvent<React.ElementRef<'input'>>) =>
|
setMilageEnd(Number(e.target.value))
|
||||||
setMilageEnd(Number(e.target.value))
|
}
|
||||||
}
|
/>
|
||||||
/>
|
<Input label="Gefahren" name="milage" readOnly value={milage} />
|
||||||
<Input label="Gefahren" name="milage" readOnly value={milage} />
|
|
||||||
<Select
|
|
||||||
label="Rate"
|
|
||||||
name="tarif"
|
|
||||||
value={tarif}
|
|
||||||
onChange={(e) => setTarif(e.target.value as MILAGE_TARIFS)}
|
|
||||||
>
|
|
||||||
{milageTarifOptions}
|
|
||||||
</Select>
|
|
||||||
<div className="mb-3">
|
|
||||||
<button
|
|
||||||
className="ibtn btn-gray mr-3"
|
|
||||||
onClick={onAddAdditionalCost}
|
|
||||||
title="Zusätzliche Kosten hinzufügen"
|
|
||||||
>
|
|
||||||
+
|
|
||||||
</button>
|
|
||||||
<label className="flabel inline">Zusätzliche Kosten</label>
|
|
||||||
</div>
|
|
||||||
{additionalCosts.map((_, index) => {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<div className="mb-3" key={`label${index}`}>
|
|
||||||
<button
|
|
||||||
className="ibtn btn-gray mr-3"
|
|
||||||
onClick={(event) =>
|
|
||||||
onRemoveAdditionalCost(event, index)
|
|
||||||
}
|
|
||||||
title="Entfernen"
|
|
||||||
>
|
|
||||||
-
|
|
||||||
</button>
|
|
||||||
<label className="flabel inline">{`Kostenpunkt ${index + 1
|
|
||||||
}`}</label>
|
|
||||||
</div>
|
|
||||||
<div className="ml-10 mb-3" key={`input{index}`}>
|
|
||||||
<Input
|
|
||||||
label={`Name`}
|
|
||||||
name={`additionalCostName${index}`}
|
|
||||||
key={`additionalCostName${index}`}
|
|
||||||
value={additionalCosts[index].name}
|
|
||||||
onChange={(event) => {
|
|
||||||
const newAdditonalCosts = [...additionalCosts]
|
|
||||||
newAdditonalCosts[index] = {
|
|
||||||
value: newAdditonalCosts[index].value,
|
|
||||||
name: event.target.value,
|
|
||||||
}
|
|
||||||
setAdditionalCosts(newAdditonalCosts)
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Input
|
|
||||||
label={`Betrag`}
|
|
||||||
name={`additionalCostValue${index}`}
|
|
||||||
key={`additionalCostValue${index}`}
|
|
||||||
value={additionalCosts[index].value}
|
|
||||||
type="number"
|
|
||||||
onChange={(event) => {
|
|
||||||
const newAdditonalCosts = [...additionalCosts]
|
|
||||||
newAdditonalCosts[index] = {
|
|
||||||
name: newAdditonalCosts[index].name,
|
|
||||||
value: Number(event.target.value),
|
|
||||||
}
|
|
||||||
setAdditionalCosts(newAdditonalCosts)
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
<Input label="Summe" name="total" readOnly value={total} />
|
|
||||||
</div>
|
|
||||||
<Select
|
<Select
|
||||||
label="Status"
|
label="Rate"
|
||||||
name={status}
|
name="tarif"
|
||||||
value={status}
|
value={tarif}
|
||||||
onChange={(e) => setStatus(e.target.value as BILL_STATUS)}
|
onChange={(e) => setTarif(e.target.value as MILAGE_TARIFS)}
|
||||||
>
|
>
|
||||||
{billStatusOptions}
|
{milageTarifOptions}
|
||||||
</Select>
|
</Select>
|
||||||
{storingError && (
|
<div className="mb-3">
|
||||||
<div className="error-message flex-grow mt-6">{storingError}</div>
|
<button
|
||||||
)}
|
className="ibtn btn-gray mr-3"
|
||||||
<button
|
onClick={onAddAdditionalCost}
|
||||||
type="submit"
|
title="Zusätzliche Kosten hinzufügen"
|
||||||
className="btn btn-blue mt-3"
|
>
|
||||||
disabled={storingInProgress}
|
+
|
||||||
>
|
</button>
|
||||||
Rechnung {!!booking.bill ? 'Updaten' : 'Erstellen'}
|
<label className="flabel inline">Zusätzliche Kosten</label>
|
||||||
</button>
|
</div>
|
||||||
</form>
|
{additionalCosts.map((_, index) => {
|
||||||
)}
|
return (
|
||||||
|
<>
|
||||||
|
<div className="mb-3" key={`label${index}`}>
|
||||||
|
<button
|
||||||
|
className="ibtn btn-gray mr-3"
|
||||||
|
onClick={(event) => onRemoveAdditionalCost(event, index)}
|
||||||
|
title="Entfernen"
|
||||||
|
>
|
||||||
|
-
|
||||||
|
</button>
|
||||||
|
<label className="flabel inline">{`Kostenpunkt ${
|
||||||
|
index + 1
|
||||||
|
}`}</label>
|
||||||
|
</div>
|
||||||
|
<div className="ml-10 mb-3" key={`input{index}`}>
|
||||||
|
<Input
|
||||||
|
label={`Name`}
|
||||||
|
name={`additionalCostName${index}`}
|
||||||
|
key={`additionalCostName${index}`}
|
||||||
|
value={additionalCosts[index].name}
|
||||||
|
onChange={(event) => {
|
||||||
|
const newAdditonalCosts = [...additionalCosts]
|
||||||
|
newAdditonalCosts[index] = {
|
||||||
|
value: newAdditonalCosts[index].value,
|
||||||
|
name: event.target.value,
|
||||||
|
}
|
||||||
|
setAdditionalCosts(newAdditonalCosts)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
label={`Betrag`}
|
||||||
|
name={`additionalCostValue${index}`}
|
||||||
|
key={`additionalCostValue${index}`}
|
||||||
|
value={additionalCosts[index].value}
|
||||||
|
type="number"
|
||||||
|
onChange={(event) => {
|
||||||
|
const newAdditonalCosts = [...additionalCosts]
|
||||||
|
newAdditonalCosts[index] = {
|
||||||
|
name: newAdditonalCosts[index].name,
|
||||||
|
value: Number(event.target.value),
|
||||||
|
}
|
||||||
|
setAdditionalCosts(newAdditonalCosts)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
<Input label="Summe" name="total" readOnly value={total} />
|
||||||
|
</div>
|
||||||
|
<Select
|
||||||
|
label="Status"
|
||||||
|
name={status}
|
||||||
|
value={status}
|
||||||
|
onChange={(e) => setStatus(e.target.value as BILL_STATUS)}
|
||||||
|
>
|
||||||
|
{billStatusOptions}
|
||||||
|
</Select>
|
||||||
|
{storingError && (
|
||||||
|
<div className="error-message flex-grow mt-6">{storingError}</div>
|
||||||
|
)}
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
className="btn btn-blue mt-3"
|
||||||
|
disabled={storingInProgress}
|
||||||
|
>
|
||||||
|
Rechnung {!!booking.bill ? 'Updaten' : 'Erstellen'}
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
)}
|
||||||
</Layout>
|
</Layout>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
BookingBillPage.auth = true;
|
BookingBillPage.auth = true
|
||||||
|
|
||||||
export default BookingBillPage;
|
export default BookingBillPage
|
||||||
|
|||||||
@@ -9,13 +9,9 @@ import { getBookingStatus, patchBooking } from '../../../../helpers/booking'
|
|||||||
import { daysFormatFrontend } from '../../../../helpers/date'
|
import { daysFormatFrontend } from '../../../../helpers/date'
|
||||||
import { BOOKING_STATUS } from '../../../../db/enums'
|
import { BOOKING_STATUS } from '../../../../db/enums'
|
||||||
|
|
||||||
export const getServerSideProps = getServerSideBooking;
|
export const getServerSideProps = getServerSideBooking
|
||||||
|
|
||||||
function ShowBookingAdmin({
|
function ShowBookingAdmin({ booking: bookingProp }: { booking: Booking }) {
|
||||||
booking: bookingProp,
|
|
||||||
}: {
|
|
||||||
booking: Booking
|
|
||||||
}) {
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const [booking, setBooking] = useState(bookingProp)
|
const [booking, setBooking] = useState(bookingProp)
|
||||||
const [storingBooking, setStoringBooking] = useState(false)
|
const [storingBooking, setStoringBooking] = useState(false)
|
||||||
@@ -41,43 +37,43 @@ function ShowBookingAdmin({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Layout>
|
<Layout>
|
||||||
<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.days)}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<strong>Bucher:</strong> {booking.name}
|
<strong>Bucher:</strong> {booking.name}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<strong>Buchungsstatus:</strong> {getBookingStatus(booking.status)}
|
<strong>Buchungsstatus:</strong> {getBookingStatus(booking.status)}
|
||||||
</div>
|
</div>
|
||||||
{storingBookingError && (
|
{storingBookingError && (
|
||||||
<div className="error-message flex-grow">{storingBookingError}</div>
|
<div className="error-message flex-grow">{storingBookingError}</div>
|
||||||
)}
|
)}
|
||||||
<div className="my-6">
|
<div className="my-6">
|
||||||
<button
|
<button
|
||||||
onClick={() => onStoreBooking(true)}
|
onClick={() => onStoreBooking(true)}
|
||||||
className="btn btn-blue"
|
className="btn btn-blue"
|
||||||
disabled={storingBooking}
|
disabled={storingBooking}
|
||||||
>
|
>
|
||||||
Buchung Bestätigen
|
Buchung Bestätigen
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={() => onStoreBooking(false)}
|
onClick={() => onStoreBooking(false)}
|
||||||
className="btn btn-red"
|
className="btn btn-red"
|
||||||
disabled={storingBooking}
|
disabled={storingBooking}
|
||||||
>
|
>
|
||||||
Buchung Abweisen
|
Buchung Abweisen
|
||||||
</button>
|
</button>
|
||||||
<Link href={`${router.asPath}/bill`}>
|
<Link href={`${router.asPath}/bill`}>
|
||||||
<a className="btn btn-gray">Rechnung</a>
|
<a className="btn btn-gray">Rechnung</a>
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</Layout>
|
</Layout>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
ShowBookingAdmin.auth = true;
|
ShowBookingAdmin.auth = true
|
||||||
|
|
||||||
export default ShowBookingAdmin;
|
export default ShowBookingAdmin
|
||||||
|
|||||||
@@ -1,20 +1,20 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import { useSession } from 'next-auth/react'
|
import { useSession } from 'next-auth/react'
|
||||||
import Layout from '../../components/layout';
|
import Layout from '../../components/layout'
|
||||||
import Denied from '../../components/denied';
|
import Denied from '../../components/denied'
|
||||||
import { daysFormatFrontend } from '../../helpers/date'
|
import { daysFormatFrontend } from '../../helpers/date'
|
||||||
|
|
||||||
import { getServerSideRecentBookings } from '../../lib/getServerSideProps'
|
import { getServerSideRecentBookings } from '../../lib/getServerSideProps'
|
||||||
|
|
||||||
export const getServerSideProps = getServerSideRecentBookings;
|
export const getServerSideProps = getServerSideRecentBookings
|
||||||
|
|
||||||
function AdminRecentBookings({ bookings }) {
|
function AdminRecentBookings({ bookings }) {
|
||||||
const { data: session, status} = useSession();
|
const { data: session, status } = useSession()
|
||||||
|
|
||||||
if (typeof window !== 'undefined' && status === "loading") return null;
|
if (typeof window !== 'undefined' && status === 'loading') return null
|
||||||
|
|
||||||
if (!bookings) return null;
|
if (!bookings) return null
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Layout>
|
<Layout>
|
||||||
@@ -71,4 +71,4 @@ function AdminRecentBookings({ bookings }) {
|
|||||||
|
|
||||||
AdminRecentBookings.auth = true
|
AdminRecentBookings.auth = true
|
||||||
|
|
||||||
export default AdminRecentBookings;
|
export default AdminRecentBookings
|
||||||
|
|||||||
@@ -1,20 +1,20 @@
|
|||||||
import { NextApiRequest, NextApiResponse } from 'next'
|
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 { MongoDBAdapter } from "@next-auth/mongodb-adapter"
|
import { MongoDBAdapter } from '@next-auth/mongodb-adapter'
|
||||||
import { MONGO_URI, MONGODB_OPTIONS } from "../../../db"
|
import { MONGO_URI, MONGODB_OPTIONS } from '../../../db'
|
||||||
import { MongoClient } from "mongodb";
|
import { MongoClient } from 'mongodb'
|
||||||
|
|
||||||
let client: MongoClient;
|
let client: MongoClient
|
||||||
|
|
||||||
async function getMongoClient() {
|
async function getMongoClient() {
|
||||||
if (!client) {
|
if (!client) {
|
||||||
client = new MongoClient(MONGO_URI, MONGODB_OPTIONS);
|
client = new MongoClient(MONGO_URI, MONGODB_OPTIONS)
|
||||||
await client.connect();
|
await client.connect()
|
||||||
}
|
}
|
||||||
|
|
||||||
return client;
|
return client
|
||||||
}
|
}
|
||||||
|
|
||||||
export default async function auth(req: NextApiRequest, res: NextApiResponse) {
|
export default async function auth(req: NextApiRequest, res: NextApiResponse) {
|
||||||
@@ -24,17 +24,15 @@ export default async function auth(req: NextApiRequest, res: NextApiResponse) {
|
|||||||
providers: [
|
providers: [
|
||||||
EmailProvider({
|
EmailProvider({
|
||||||
server: {
|
server: {
|
||||||
host: "smtp.sendgrid.net",
|
host: 'smtp.sendgrid.net',
|
||||||
port: 587,
|
port: 587,
|
||||||
auth: {
|
auth: {
|
||||||
user: "apikey",
|
user: 'apikey',
|
||||||
pass: process.env.SENDGRID_API_KEY,
|
pass: process.env.SENDGRID_API_KEY,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
from: process.env.FROM_EMAIL
|
from: process.env.FROM_EMAIL,
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import { Bill } from '../../../../db/bill'
|
|||||||
import { createBill, patchBill } from '../../../../db/index'
|
import { createBill, patchBill } from '../../../../db/index'
|
||||||
|
|
||||||
export default async function billHandler(req, res): Promise<void> {
|
export default async function billHandler(req, res): Promise<void> {
|
||||||
|
|
||||||
const {
|
const {
|
||||||
method,
|
method,
|
||||||
query: { uuid: uuids },
|
query: { uuid: uuids },
|
||||||
|
|||||||
@@ -41,28 +41,28 @@ export default function ShowBooking({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Layout>
|
<Layout>
|
||||||
<div>
|
<div>
|
||||||
<strong>Buchungsstatus:</strong> {getBookingStatus(booking.status)}
|
<strong>Buchungsstatus:</strong> {getBookingStatus(booking.status)}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<strong>Buchungszeitraum:</strong> {daysFormatFrontend(booking.days)}
|
||||||
|
</div>
|
||||||
|
{storingBookingError && (
|
||||||
|
<div className="error-message flex-grow">{storingBookingError}</div>
|
||||||
|
)}
|
||||||
|
{[BOOKING_STATUS.CONFIRMED, BOOKING_STATUS.REQUESTED].includes(
|
||||||
|
booking.status
|
||||||
|
) && (
|
||||||
|
<div className="my-6">
|
||||||
|
<button
|
||||||
|
onClick={onCancelBooking}
|
||||||
|
className="btn btn-red"
|
||||||
|
disabled={storingBooking}
|
||||||
|
>
|
||||||
|
Buchung Stornieren
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
)}
|
||||||
<strong>Buchungszeitraum:</strong> {daysFormatFrontend(booking.days)}
|
</Layout>
|
||||||
</div>
|
|
||||||
{storingBookingError && (
|
|
||||||
<div className="error-message flex-grow">{storingBookingError}</div>
|
|
||||||
)}
|
|
||||||
{[BOOKING_STATUS.CONFIRMED, BOOKING_STATUS.REQUESTED].includes(
|
|
||||||
booking.status
|
|
||||||
) && (
|
|
||||||
<div className="my-6">
|
|
||||||
<button
|
|
||||||
onClick={onCancelBooking}
|
|
||||||
className="btn btn-red"
|
|
||||||
disabled={storingBooking}
|
|
||||||
>
|
|
||||||
Buchung Stornieren
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</Layout>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,37 +20,38 @@ export default function ShowBookingStored({ booking }: { booking: Booking }) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Layout>
|
<Layout>
|
||||||
<h3 className="thanks mb-3 mt-6 text-lg">Vielen Dank für die Buchungsanfrage</h3>
|
<h3 className="thanks mb-3 mt-6 text-lg">
|
||||||
<p className="mb-6">
|
Vielen Dank für die Buchungsanfrage
|
||||||
Nach Prüfung bestätigen wir die Buchung zeitnah per E-Mail.
|
</h3>
|
||||||
</p>
|
<p className="mb-6">
|
||||||
<p>
|
Nach Prüfung bestätigen wir die Buchung zeitnah per E-Mail.
|
||||||
Den{' '}
|
</p>
|
||||||
<Link href={`/bookings/${booking.uuid}`}>
|
<p>
|
||||||
<a className="link underline">Link</a>
|
Den{' '}
|
||||||
</Link>{' '}
|
<Link href={`/bookings/${booking.uuid}`}>
|
||||||
zur Buchung schicken wir Dir auch per E-Mail. Dort kann die Buchung
|
<a className="link underline">Link</a>
|
||||||
auch jederzeit storniert werden.
|
</Link>{' '}
|
||||||
</p>
|
zur Buchung schicken wir Dir auch per E-Mail. Dort kann die Buchung auch
|
||||||
{!storedBookingData && !bookingDataStored && (
|
jederzeit storniert werden.
|
||||||
<div className="mt-6">
|
</p>
|
||||||
<p>
|
{!storedBookingData && !bookingDataStored && (
|
||||||
Sollen deine Buchungsdaten für die nächste Buchung in{' '}
|
<div className="mt-6">
|
||||||
<strong>deinem Browser</strong> gespeichert werden?
|
<p>
|
||||||
</p>
|
Sollen deine Buchungsdaten für die nächste Buchung in{' '}
|
||||||
<button onClick={store} className="mt-3 ml-0 btn btn-blue">
|
<strong>deinem Browser</strong> gespeichert werden?
|
||||||
Ja, bitte speichern
|
</p>
|
||||||
</button>
|
<button onClick={store} className="mt-3 ml-0 btn btn-blue">
|
||||||
</div>
|
Ja, bitte speichern
|
||||||
)}
|
</button>
|
||||||
{bookingDataStored === true && (
|
</div>
|
||||||
<div className="mt-6">
|
)}
|
||||||
<p className="info-message">
|
{bookingDataStored === true && (
|
||||||
Ok, deine Buchungsdaten wurden für die nächste Buchung
|
<div className="mt-6">
|
||||||
gespeichert.
|
<p className="info-message">
|
||||||
</p>
|
Ok, deine Buchungsdaten wurden für die nächste Buchung gespeichert.
|
||||||
</div>
|
</p>
|
||||||
)}
|
</div>
|
||||||
</Layout>
|
)}
|
||||||
|
</Layout>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import Layout from '../components/layout'
|
|||||||
export default function TermsPage({ source }) {
|
export default function TermsPage({ source }) {
|
||||||
return (
|
return (
|
||||||
<Layout>
|
<Layout>
|
||||||
<MDXRemote {...source} components={{...mdComponents}} />
|
<MDXRemote {...source} components={{ ...mdComponents }} />
|
||||||
</Layout>
|
</Layout>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import Layout from '../components/layout'
|
|||||||
export default function Home() {
|
export default function Home() {
|
||||||
const hello = 'fooo'
|
const hello = 'fooo'
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Layout>
|
<Layout>
|
||||||
<div className="mt-6 sm:text-center">
|
<div className="mt-6 sm:text-center">
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ export default function TermsPage({ source }) {
|
|||||||
return (
|
return (
|
||||||
<Layout>
|
<Layout>
|
||||||
<div className="text-gray-700">
|
<div className="text-gray-700">
|
||||||
<MDXRemote {...source} components={{...mdComponents}}/>
|
<MDXRemote {...source} components={{ ...mdComponents }} />
|
||||||
</div>
|
</div>
|
||||||
</Layout>
|
</Layout>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ import Layout from '../components/layout'
|
|||||||
export default function TermsPage({ source }) {
|
export default function TermsPage({ source }) {
|
||||||
return (
|
return (
|
||||||
<Layout>
|
<Layout>
|
||||||
<div className="text-gray-700" >
|
<div className="text-gray-700">
|
||||||
<MDXRemote {...source} components={{...mdComponents}} />
|
<MDXRemote {...source} components={{ ...mdComponents }} />
|
||||||
</div>
|
</div>
|
||||||
</Layout>
|
</Layout>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
{
|
{
|
||||||
"extends": [
|
"extends": ["config:base", ":dependencyDashboard"],
|
||||||
"config:base",
|
|
||||||
":dependencyDashboard"
|
|
||||||
],
|
|
||||||
"schedule": "every weekend",
|
"schedule": "every weekend",
|
||||||
"packageRules": [
|
"packageRules": [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,11 +1,7 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "es5",
|
"target": "es5",
|
||||||
"lib": [
|
"lib": ["dom", "dom.iterable", "esnext"],
|
||||||
"dom",
|
|
||||||
"dom.iterable",
|
|
||||||
"esnext"
|
|
||||||
],
|
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"strict": false,
|
"strict": false,
|
||||||
@@ -20,12 +16,6 @@
|
|||||||
"jsx": "preserve",
|
"jsx": "preserve",
|
||||||
"incremental": true
|
"incremental": true
|
||||||
},
|
},
|
||||||
"include": [
|
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
|
||||||
"next-env.d.ts",
|
"exclude": ["node_modules"]
|
||||||
"**/*.ts",
|
|
||||||
"**/*.tsx"
|
|
||||||
],
|
|
||||||
"exclude": [
|
|
||||||
"node_modules"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user