Merged in fix/BOOK-662-handle-overlapping-dates-timezone (pull request #3319)
Fix/BOOK-662 handle overlapping dates timezone * fix(BOOK-662): handle overlapping dates alerts * fix(BOOK-662): handle overlapping dates alerts * fix(BOOK-662): add test same dates Approved-by: Anton Gunnarsson
This commit is contained in:
@@ -219,8 +219,8 @@ async function MyStay(props: {
|
|||||||
|
|
||||||
hotel.specialAlerts = filterOverlappingDates(
|
hotel.specialAlerts = filterOverlappingDates(
|
||||||
hotel.specialAlerts,
|
hotel.specialAlerts,
|
||||||
dt(fromDate),
|
dt.utc(fromDate),
|
||||||
dt(toDate)
|
dt.utc(toDate)
|
||||||
)
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import { notFound } from "next/navigation"
|
|||||||
|
|
||||||
import { AlertTypeEnum } from "@scandic-hotels/common/constants/alert"
|
import { AlertTypeEnum } from "@scandic-hotels/common/constants/alert"
|
||||||
import { dt } from "@scandic-hotels/common/dt"
|
import { dt } from "@scandic-hotels/common/dt"
|
||||||
import { hasOverlappingDates } from "@scandic-hotels/common/dt/utils/hasOverlappingDates"
|
|
||||||
import { Alert } from "@scandic-hotels/design-system/Alert"
|
import { Alert } from "@scandic-hotels/design-system/Alert"
|
||||||
import { Divider } from "@scandic-hotels/design-system/Divider"
|
import { Divider } from "@scandic-hotels/design-system/Divider"
|
||||||
import { HotelTypeEnum } from "@scandic-hotels/trpc/enums/hotelType"
|
import { HotelTypeEnum } from "@scandic-hotels/trpc/enums/hotelType"
|
||||||
@@ -10,6 +9,7 @@ import { HotelTypeEnum } from "@scandic-hotels/trpc/enums/hotelType"
|
|||||||
import { env } from "../../../env/server"
|
import { env } from "../../../env/server"
|
||||||
import { BookingConfirmationProvider } from "../../providers/BookingConfirmationProvider"
|
import { BookingConfirmationProvider } from "../../providers/BookingConfirmationProvider"
|
||||||
import { getBookingConfirmation } from "../../trpc/memoizedRequests/getBookingConfirmation"
|
import { getBookingConfirmation } from "../../trpc/memoizedRequests/getBookingConfirmation"
|
||||||
|
import { filterOverlappingDates } from "../../utils/SelectRate"
|
||||||
import { SidePanel } from "../SidePanel"
|
import { SidePanel } from "../SidePanel"
|
||||||
import { Confirmation } from "./Confirmation"
|
import { Confirmation } from "./Confirmation"
|
||||||
import { HotelDetails } from "./HotelDetails"
|
import { HotelDetails } from "./HotelDetails"
|
||||||
@@ -50,14 +50,12 @@ export async function BookingConfirmation({
|
|||||||
if (!room) {
|
if (!room) {
|
||||||
return notFound()
|
return notFound()
|
||||||
}
|
}
|
||||||
const validAlerts = hotel.specialAlerts.filter(
|
const validAlerts = filterOverlappingDates(
|
||||||
(alert) =>
|
hotel.specialAlerts.filter((alert) => alert.displayInBookingFlow),
|
||||||
hasOverlappingDates(
|
dt.utc(booking.checkInDate),
|
||||||
alert,
|
dt.utc(booking.checkOutDate)
|
||||||
dt(booking.checkInDate),
|
|
||||||
dt(booking.checkOutDate)
|
|
||||||
) && alert.displayInBookingFlow
|
|
||||||
)
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<BookingConfirmationProvider
|
<BookingConfirmationProvider
|
||||||
bookingCode={booking.bookingCode}
|
bookingCode={booking.bookingCode}
|
||||||
|
|||||||
@@ -2,10 +2,10 @@ import { cookies } from "next/headers"
|
|||||||
|
|
||||||
import { FamilyAndFriendsCodes } from "@scandic-hotels/common/constants/familyAndFriends"
|
import { FamilyAndFriendsCodes } from "@scandic-hotels/common/constants/familyAndFriends"
|
||||||
import { dt } from "@scandic-hotels/common/dt"
|
import { dt } from "@scandic-hotels/common/dt"
|
||||||
import { hasOverlappingDates } from "@scandic-hotels/common/dt/utils/hasOverlappingDates"
|
|
||||||
import { HotelInfoCard } from "@scandic-hotels/design-system/HotelInfoCard"
|
import { HotelInfoCard } from "@scandic-hotels/design-system/HotelInfoCard"
|
||||||
|
|
||||||
import { mapApiImagesToGalleryImages } from "../../misc/imageGallery"
|
import { mapApiImagesToGalleryImages } from "../../misc/imageGallery"
|
||||||
|
import { filterOverlappingDates } from "../../utils/SelectRate"
|
||||||
import FnFNotAllowedAlert from "../FnFNotAllowedAlert"
|
import FnFNotAllowedAlert from "../FnFNotAllowedAlert"
|
||||||
import { HotelDetailsSidePeek } from "../HotelDetailsSidePeek"
|
import { HotelDetailsSidePeek } from "../HotelDetailsSidePeek"
|
||||||
import { AmenitiesSidePeekLabel } from "./AmenititesSidePeekLabel"
|
import { AmenitiesSidePeekLabel } from "./AmenititesSidePeekLabel"
|
||||||
@@ -33,10 +33,10 @@ export async function SelectRate({
|
|||||||
isInValidFNF = cookieStore.get("sc")?.value !== "1"
|
isInValidFNF = cookieStore.get("sc")?.value !== "1"
|
||||||
}
|
}
|
||||||
|
|
||||||
const validAlerts = hotelData.hotel.specialAlerts.filter(
|
const validAlerts = filterOverlappingDates(
|
||||||
(alert) =>
|
hotelData.hotel.specialAlerts.filter((alert) => alert.displayInBookingFlow),
|
||||||
hasOverlappingDates(alert, dt(booking.fromDate), dt(booking.toDate)) &&
|
dt.utc(booking.fromDate),
|
||||||
alert.displayInBookingFlow
|
dt.utc(booking.toDate)
|
||||||
)
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -1,82 +1,8 @@
|
|||||||
import { describe, expect, it } from "vitest"
|
import { describe, expect, it } from "vitest"
|
||||||
|
|
||||||
import { AlertTypeEnum } from "@scandic-hotels/common/constants/alert"
|
|
||||||
import { CurrencyEnum } from "@scandic-hotels/common/constants/currency"
|
import { CurrencyEnum } from "@scandic-hotels/common/constants/currency"
|
||||||
import { dt } from "@scandic-hotels/common/dt"
|
|
||||||
|
|
||||||
import {
|
import { calculateVat, sumPackages, sumPackagesRequestedPrice } from "./index"
|
||||||
calculateVat,
|
|
||||||
filterOverlappingDates,
|
|
||||||
sumPackages,
|
|
||||||
sumPackagesRequestedPrice,
|
|
||||||
} from "./index"
|
|
||||||
|
|
||||||
import type { specialAlertsSchema } from "@scandic-hotels/trpc/routers/hotels/schemas/hotel/specialAlerts"
|
|
||||||
import type { z } from "zod"
|
|
||||||
|
|
||||||
type Alert = z.infer<typeof specialAlertsSchema>[number]
|
|
||||||
|
|
||||||
function makeAlert(start: string, end: string): Alert {
|
|
||||||
return {
|
|
||||||
id: "test-id",
|
|
||||||
name: "Test Alert",
|
|
||||||
heading: "Test Heading",
|
|
||||||
text: "Some text",
|
|
||||||
type: AlertTypeEnum.Alarm,
|
|
||||||
displayInBookingFlow: true,
|
|
||||||
startDate: start,
|
|
||||||
endDate: end,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
describe("filterOverlappingDates", () => {
|
|
||||||
const alert = makeAlert("2025-09-01", "2025-09-10")
|
|
||||||
|
|
||||||
it("shows alert if booking starts inside alert", () => {
|
|
||||||
const result = filterOverlappingDates(
|
|
||||||
[alert],
|
|
||||||
dt("2025-09-05"),
|
|
||||||
dt("2025-09-12")
|
|
||||||
)
|
|
||||||
expect(result).toHaveLength(1)
|
|
||||||
})
|
|
||||||
|
|
||||||
it("shows alert if booking ends inside alert", () => {
|
|
||||||
const result = filterOverlappingDates(
|
|
||||||
[alert],
|
|
||||||
dt("2025-08-28"),
|
|
||||||
dt("2025-09-05")
|
|
||||||
)
|
|
||||||
expect(result).toHaveLength(1)
|
|
||||||
})
|
|
||||||
|
|
||||||
it("shows alert if booking fully contains alert", () => {
|
|
||||||
const result = filterOverlappingDates(
|
|
||||||
[alert],
|
|
||||||
dt("2025-08-28"),
|
|
||||||
dt("2025-09-15")
|
|
||||||
)
|
|
||||||
expect(result).toHaveLength(1)
|
|
||||||
})
|
|
||||||
|
|
||||||
it("shows alert if alert fully contains booking", () => {
|
|
||||||
const result = filterOverlappingDates(
|
|
||||||
[alert],
|
|
||||||
dt("2025-09-03"),
|
|
||||||
dt("2025-09-05")
|
|
||||||
)
|
|
||||||
expect(result).toHaveLength(1)
|
|
||||||
})
|
|
||||||
|
|
||||||
it("does not show alert if no overlap", () => {
|
|
||||||
const result = filterOverlappingDates(
|
|
||||||
[alert],
|
|
||||||
dt("2025-08-01"),
|
|
||||||
dt("2025-08-05")
|
|
||||||
)
|
|
||||||
expect(result).toHaveLength(0)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe("sumPackages", () => {
|
describe("sumPackages", () => {
|
||||||
it("returns 0 price for null packages", () => {
|
it("returns 0 price for null packages", () => {
|
||||||
|
|||||||
38
packages/common/dt/utils/hasOverlappingDates.test.ts
Normal file
38
packages/common/dt/utils/hasOverlappingDates.test.ts
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
import { describe, expect, it } from "vitest"
|
||||||
|
|
||||||
|
import { dt } from "../dt"
|
||||||
|
import { hasOverlappingDates } from "./hasOverlappingDates"
|
||||||
|
|
||||||
|
describe("hasOverlappingDates", () => {
|
||||||
|
const item = { startDate: "2025-09-01", endDate: "2025-09-10" }
|
||||||
|
|
||||||
|
it("returns true if start date is within date range", () => {
|
||||||
|
const result = hasOverlappingDates(item, dt("2025-09-05"), dt("2025-09-12"))
|
||||||
|
expect(result).toBeTruthy()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("returns true if end date is within date range", () => {
|
||||||
|
const result = hasOverlappingDates(item, dt("2025-08-28"), dt("2025-09-05"))
|
||||||
|
expect(result).toBeTruthy()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("returns true if start and end date if match dates exactly", () => {
|
||||||
|
const result = hasOverlappingDates(item, dt("2025-09-01"), dt("2025-09-10"))
|
||||||
|
expect(result).toBeTruthy()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("returns true if start and end date is within date range", () => {
|
||||||
|
const result = hasOverlappingDates(item, dt("2025-08-28"), dt("2025-09-15"))
|
||||||
|
expect(result).toBeTruthy()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("returns true if start and end date is within date range", () => {
|
||||||
|
const result = hasOverlappingDates(item, dt("2025-09-03"), dt("2025-09-05"))
|
||||||
|
expect(result).toBeTruthy()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("return false if no overlap", () => {
|
||||||
|
const result = hasOverlappingDates(item, dt("2025-08-01"), dt("2025-08-05"))
|
||||||
|
expect(result).toBeFalsy()
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -10,8 +10,8 @@ export function hasOverlappingDates(
|
|||||||
fromDate: Date | Dayjs,
|
fromDate: Date | Dayjs,
|
||||||
toDate: Date | Dayjs
|
toDate: Date | Dayjs
|
||||||
) {
|
) {
|
||||||
const startDate = dt(fromDate)
|
const startDate = dt.utc(fromDate)
|
||||||
const endDate = dt(toDate)
|
const endDate = dt.utc(toDate)
|
||||||
|
|
||||||
if (dateRangeItem.endDate && dateRangeItem.startDate) {
|
if (dateRangeItem.endDate && dateRangeItem.startDate) {
|
||||||
const itemStartDate = dt(dateRangeItem.startDate)
|
const itemStartDate = dt(dateRangeItem.startDate)
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { z } from "zod"
|
import { z } from "zod"
|
||||||
|
|
||||||
import { AlertTypeEnum } from "@scandic-hotels/common/constants/alert"
|
import { AlertTypeEnum } from "@scandic-hotels/common/constants/alert"
|
||||||
|
import { dt } from "@scandic-hotels/common/dt"
|
||||||
import { nullableStringValidator } from "@scandic-hotels/common/utils/zod/stringValidator"
|
import { nullableStringValidator } from "@scandic-hotels/common/utils/zod/stringValidator"
|
||||||
|
|
||||||
const specialAlertSchema = z.object({
|
const specialAlertSchema = z.object({
|
||||||
@@ -28,7 +29,7 @@ export const specialAlertsSchema = z
|
|||||||
text: alert.description || null,
|
text: alert.description || null,
|
||||||
type: AlertTypeEnum.Info,
|
type: AlertTypeEnum.Info,
|
||||||
displayInBookingFlow: alert.displayInBookingFlow,
|
displayInBookingFlow: alert.displayInBookingFlow,
|
||||||
endDate: alert.endDate,
|
endDate: dt.utc(alert.endDate).toISOString(),
|
||||||
startDate: alert.startDate,
|
startDate: dt.utc(alert.startDate).toISOString(),
|
||||||
}))
|
}))
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user