2023-01-20 15:31:04 +01:00
|
|
|
import { Dayjs } from 'dayjs'
|
2023-01-21 15:17:21 +01:00
|
|
|
import { v4 } from 'uuid'
|
2023-01-20 15:31:04 +01:00
|
|
|
import dayjs from './dayjs'
|
2023-01-28 10:51:46 +01:00
|
|
|
import { all, run } from './database'
|
2021-11-24 00:00:22 +01:00
|
|
|
|
2022-11-21 18:50:59 +01:00
|
|
|
const RESERVATION_AVAILABLE_WITHIN_DAYS = 7
|
|
|
|
|
|
2022-10-23 11:55:47 +02:00
|
|
|
export interface User {
|
|
|
|
|
username: string
|
|
|
|
|
password: string
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-24 00:00:22 +01:00
|
|
|
export interface Opponent {
|
|
|
|
|
id: string
|
|
|
|
|
name: string
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface DateRange {
|
2023-01-20 15:31:04 +01:00
|
|
|
start: Dayjs
|
|
|
|
|
end: Dayjs
|
2021-11-24 00:00:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export class Reservation {
|
2023-01-21 15:17:21 +01:00
|
|
|
public readonly id: string
|
2022-10-23 11:55:47 +02:00
|
|
|
public readonly user: User
|
2021-11-24 00:00:22 +01:00
|
|
|
public readonly dateRange: DateRange
|
|
|
|
|
public readonly opponent: Opponent
|
|
|
|
|
public readonly possibleDates: Dayjs[]
|
|
|
|
|
public booked = false
|
|
|
|
|
|
2022-10-23 11:55:47 +02:00
|
|
|
constructor(
|
|
|
|
|
user: User,
|
|
|
|
|
dateRange: DateRange,
|
|
|
|
|
opponent: Opponent,
|
2023-01-21 15:17:21 +01:00
|
|
|
possibleDates?: Dayjs[],
|
|
|
|
|
id = v4()
|
2022-10-23 11:55:47 +02:00
|
|
|
) {
|
2023-01-21 15:17:21 +01:00
|
|
|
this.id = id
|
2022-10-23 11:55:47 +02:00
|
|
|
this.user = user
|
2021-11-24 00:00:22 +01:00
|
|
|
this.dateRange = dateRange
|
|
|
|
|
this.opponent = opponent
|
2022-10-23 11:55:47 +02:00
|
|
|
this.possibleDates = possibleDates || this.createPossibleDates()
|
2021-11-24 00:00:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private createPossibleDates(): Dayjs[] {
|
|
|
|
|
const possibleDates: Dayjs[] = []
|
|
|
|
|
|
|
|
|
|
const { start, end } = this.dateRange
|
|
|
|
|
|
2021-11-28 13:06:52 +01:00
|
|
|
let possibleDate = dayjs(start).second(0).millisecond(0)
|
2021-11-24 00:00:22 +01:00
|
|
|
while (possibleDate.isSameOrBefore(end)) {
|
|
|
|
|
possibleDates.push(possibleDate)
|
|
|
|
|
possibleDate = possibleDate.add(15, 'minute')
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return possibleDates
|
|
|
|
|
}
|
2021-11-27 13:11:09 +01:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Method to check if a reservation is available for reservation in the system
|
|
|
|
|
* @returns is reservation date within 7 days
|
|
|
|
|
*/
|
|
|
|
|
public isAvailableForReservation(): boolean {
|
2021-11-28 13:06:52 +01:00
|
|
|
return (
|
|
|
|
|
Math.ceil(this.dateRange.start.diff(dayjs(), 'days', true)) <=
|
|
|
|
|
RESERVATION_AVAILABLE_WITHIN_DAYS
|
|
|
|
|
)
|
2021-11-27 13:11:09 +01:00
|
|
|
}
|
2022-03-29 22:41:44 +02:00
|
|
|
|
2022-10-23 11:55:47 +02:00
|
|
|
public getAllowedReservationDate(): Dayjs {
|
|
|
|
|
return this.dateRange.start
|
|
|
|
|
.hour(0)
|
|
|
|
|
.minute(0)
|
|
|
|
|
.second(0)
|
|
|
|
|
.millisecond(0)
|
|
|
|
|
.subtract(RESERVATION_AVAILABLE_WITHIN_DAYS, 'days')
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public toString() {
|
|
|
|
|
return JSON.stringify(this.format())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public format() {
|
|
|
|
|
return {
|
|
|
|
|
user: {
|
|
|
|
|
username: this.user.username,
|
2023-01-20 15:31:04 +01:00
|
|
|
password: this.user.password,
|
2022-10-23 11:55:47 +02:00
|
|
|
},
|
|
|
|
|
opponent: this.opponent,
|
|
|
|
|
booked: this.booked,
|
|
|
|
|
possibleDates: this.possibleDates.map((date) => date.format()),
|
|
|
|
|
dateRange: {
|
|
|
|
|
start: this.dateRange.start.format(),
|
|
|
|
|
end: this.dateRange.end.format(),
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public serializeToJson(): SerializedReservation {
|
2022-03-29 22:41:44 +02:00
|
|
|
return {
|
2022-10-23 11:55:47 +02:00
|
|
|
user: this.user,
|
2022-03-29 22:41:44 +02:00
|
|
|
opponent: this.opponent,
|
|
|
|
|
booked: this.booked,
|
|
|
|
|
possibleDates: this.possibleDates.map((date) => date.format()),
|
|
|
|
|
dateRange: {
|
|
|
|
|
start: this.dateRange.start.format(),
|
|
|
|
|
end: this.dateRange.end.format(),
|
2022-10-23 11:55:47 +02:00
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static deserializeFromJson(
|
|
|
|
|
serializedData: SerializedReservation
|
|
|
|
|
): Reservation {
|
|
|
|
|
const start = dayjs(serializedData.dateRange.start)
|
|
|
|
|
const end = dayjs(serializedData.dateRange.end)
|
|
|
|
|
return new Reservation(
|
|
|
|
|
serializedData.user,
|
|
|
|
|
{ start, end },
|
|
|
|
|
serializedData.opponent,
|
|
|
|
|
Reservation.deserializePossibleDates(serializedData.possibleDates)
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static deserializePossibleDates(dates: string[]): Dayjs[] {
|
|
|
|
|
return dates.map((date) => dayjs(date))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static async save(res: Reservation) {
|
2023-01-28 10:51:46 +01:00
|
|
|
await run(
|
2022-10-23 11:55:47 +02:00
|
|
|
`
|
|
|
|
|
INSERT INTO reservations
|
|
|
|
|
(
|
2023-01-21 16:01:38 +01:00
|
|
|
id,
|
2022-10-23 11:55:47 +02:00
|
|
|
username,
|
|
|
|
|
password,
|
|
|
|
|
date_range_start,
|
|
|
|
|
date_range_end,
|
|
|
|
|
opponent_id,
|
|
|
|
|
opponent_name
|
|
|
|
|
)
|
|
|
|
|
VALUES
|
|
|
|
|
(
|
|
|
|
|
?,
|
|
|
|
|
?,
|
|
|
|
|
?,
|
|
|
|
|
?,
|
|
|
|
|
?,
|
2023-01-21 15:17:21 +01:00
|
|
|
?,
|
2022-10-23 11:55:47 +02:00
|
|
|
?
|
|
|
|
|
)
|
|
|
|
|
`,
|
|
|
|
|
[
|
2023-01-21 15:17:21 +01:00
|
|
|
res.id,
|
2022-10-23 11:55:47 +02:00
|
|
|
res.user.username,
|
|
|
|
|
res.user.password,
|
2023-01-21 16:01:38 +01:00
|
|
|
res.dateRange.start.format('YYYY-MM-DD HH:mm:ss'),
|
|
|
|
|
res.dateRange.end.format('YYYY-MM-DD HH:mm:ss'),
|
2022-10-23 11:55:47 +02:00
|
|
|
res.opponent.id,
|
|
|
|
|
res.opponent.name,
|
|
|
|
|
]
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-21 15:17:21 +01:00
|
|
|
public static async delete(res: Reservation) {
|
2023-01-28 10:51:46 +01:00
|
|
|
await run(
|
2023-01-21 15:17:21 +01:00
|
|
|
`
|
|
|
|
|
DELETE FROM reservations
|
2023-01-30 08:59:06 +01:00
|
|
|
WHERE id = ?
|
2023-01-21 15:17:21 +01:00
|
|
|
`,
|
2023-01-28 10:51:46 +01:00
|
|
|
[res.id]
|
2023-01-21 15:17:21 +01:00
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static async fetchById(id: string): Promise<Reservation | null> {
|
2023-01-28 10:51:46 +01:00
|
|
|
const response = await all<SqlReservation>(
|
2022-10-23 11:55:47 +02:00
|
|
|
`
|
|
|
|
|
SELECT *
|
|
|
|
|
FROM reservations
|
2022-11-29 22:51:28 +01:00
|
|
|
WHERE id = ?;
|
2022-10-23 11:55:47 +02:00
|
|
|
`,
|
|
|
|
|
[id]
|
|
|
|
|
)
|
|
|
|
|
|
2023-01-28 10:51:46 +01:00
|
|
|
if (response.length === 1) {
|
|
|
|
|
const sqlReservation = response[0]
|
2022-10-23 11:55:47 +02:00
|
|
|
const res = new Reservation(
|
|
|
|
|
{
|
|
|
|
|
username: sqlReservation.username,
|
|
|
|
|
password: sqlReservation.password,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
start: dayjs(sqlReservation.date_range_start),
|
|
|
|
|
end: dayjs(sqlReservation.date_range_end),
|
|
|
|
|
},
|
2023-01-21 15:17:21 +01:00
|
|
|
{ id: sqlReservation.opponent_id, name: sqlReservation.opponent_name },
|
|
|
|
|
undefined,
|
2023-01-28 10:51:46 +01:00
|
|
|
sqlReservation.id
|
2022-10-23 11:55:47 +02:00
|
|
|
)
|
|
|
|
|
return res
|
2022-03-29 22:41:44 +02:00
|
|
|
}
|
2022-10-23 11:55:47 +02:00
|
|
|
|
|
|
|
|
return null
|
2022-03-29 22:41:44 +02:00
|
|
|
}
|
2022-11-29 22:51:28 +01:00
|
|
|
|
|
|
|
|
public static async fetchFirst(): Promise<Reservation | null> {
|
2023-01-28 10:51:46 +01:00
|
|
|
const response = await all<SqlReservation>(
|
2022-11-29 22:51:28 +01:00
|
|
|
`
|
|
|
|
|
SELECT *
|
|
|
|
|
FROM reservations
|
|
|
|
|
ORDER BY date_range_start DESC
|
|
|
|
|
LIMIT 1;
|
|
|
|
|
`
|
|
|
|
|
)
|
|
|
|
|
|
2023-01-28 10:51:46 +01:00
|
|
|
if (response.length === 1) {
|
|
|
|
|
const sqlReservation = response[0]
|
2022-11-29 22:51:28 +01:00
|
|
|
const res = new Reservation(
|
|
|
|
|
{
|
|
|
|
|
username: sqlReservation.username,
|
|
|
|
|
password: sqlReservation.password,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
start: dayjs(sqlReservation.date_range_start),
|
|
|
|
|
end: dayjs(sqlReservation.date_range_end),
|
|
|
|
|
},
|
2023-01-21 15:17:21 +01:00
|
|
|
{ id: sqlReservation.opponent_id, name: sqlReservation.opponent_name },
|
|
|
|
|
undefined,
|
2023-01-28 10:51:46 +01:00
|
|
|
sqlReservation.id
|
2022-11-29 22:51:28 +01:00
|
|
|
)
|
|
|
|
|
return res
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null
|
|
|
|
|
}
|
2023-01-21 15:17:21 +01:00
|
|
|
|
2023-01-28 10:51:46 +01:00
|
|
|
public static async fetchByDate(
|
|
|
|
|
date: Dayjs,
|
|
|
|
|
limit = 20
|
|
|
|
|
): Promise<Reservation[]> {
|
|
|
|
|
const response = await all<SqlReservation>(
|
2023-01-21 15:17:21 +01:00
|
|
|
`
|
|
|
|
|
SELECT *
|
|
|
|
|
FROM reservations
|
|
|
|
|
WHERE DATE_FORMAT(DATE_SUB(date_range_start, INTERVAL 7 DAY), '%Y-%m-%d) = ?
|
|
|
|
|
ORDER BY date_range_start DESC
|
|
|
|
|
LIMIT ?;
|
|
|
|
|
`,
|
2023-01-28 10:51:46 +01:00
|
|
|
[date.format('YYYY-MM-DD'), limit]
|
2023-01-21 15:17:21 +01:00
|
|
|
)
|
|
|
|
|
|
2023-01-28 10:51:46 +01:00
|
|
|
if (response.length > 0) {
|
|
|
|
|
return response.map(
|
|
|
|
|
(sqlReservation) =>
|
|
|
|
|
new Reservation(
|
|
|
|
|
{
|
|
|
|
|
username: sqlReservation.username,
|
|
|
|
|
password: sqlReservation.password,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
start: dayjs(sqlReservation.date_range_start),
|
|
|
|
|
end: dayjs(sqlReservation.date_range_end),
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: sqlReservation.opponent_id,
|
|
|
|
|
name: sqlReservation.opponent_name,
|
|
|
|
|
},
|
|
|
|
|
undefined,
|
|
|
|
|
sqlReservation.id
|
|
|
|
|
)
|
|
|
|
|
)
|
2023-01-21 15:17:21 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return []
|
|
|
|
|
}
|
2021-11-24 00:00:22 +01:00
|
|
|
}
|
2022-10-23 11:55:47 +02:00
|
|
|
|
|
|
|
|
export interface SerializedDateRange {
|
|
|
|
|
start: string
|
|
|
|
|
end: string
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface SerializedReservation {
|
|
|
|
|
user: User
|
|
|
|
|
opponent: Opponent
|
|
|
|
|
booked: boolean
|
|
|
|
|
possibleDates: string[]
|
|
|
|
|
dateRange: SerializedDateRange
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface SqlReservation {
|
2023-01-21 15:17:21 +01:00
|
|
|
id: string
|
2022-10-23 11:55:47 +02:00
|
|
|
username: string
|
|
|
|
|
password: string
|
|
|
|
|
date_range_start: string
|
|
|
|
|
date_range_end: string
|
|
|
|
|
opponent_id: string
|
|
|
|
|
opponent_name: string
|
|
|
|
|
}
|