Merged in chore/booking-flow-cleaning (pull request #3354)
chore: Clean booking-flow * Clean booking-flow * Fix type issue Approved-by: Joakim Jäderberg Approved-by: Linus Flood
This commit is contained in:
@@ -11,7 +11,7 @@ import type { ComponentProps, ReactNode } from "react"
|
|||||||
export function BookingFlowProviders({ children }: { children: ReactNode }) {
|
export function BookingFlowProviders({ children }: { children: ReactNode }) {
|
||||||
const user = useBookingFlowUser()
|
const user = useBookingFlowUser()
|
||||||
const isLinkedUser =
|
const isLinkedUser =
|
||||||
!!user.data && user.data.type === "partner-sas" && user.data.isLinked
|
!!user.data && user.data.type === "partner" && user.data.isLinked
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<BookingFlowContextProvider
|
<BookingFlowContextProvider
|
||||||
@@ -53,7 +53,7 @@ function useBookingFlowUser(): BookingFlowUser {
|
|||||||
return {
|
return {
|
||||||
state: "loaded",
|
state: "loaded",
|
||||||
data: {
|
data: {
|
||||||
type: "partner-sas",
|
type: "partner",
|
||||||
partnerLoyaltyNumber: `EB${euroBonusProfile.eurobonusNumber}`,
|
partnerLoyaltyNumber: `EB${euroBonusProfile.eurobonusNumber}`,
|
||||||
firstName: euroBonusProfile.firstName || null,
|
firstName: euroBonusProfile.firstName || null,
|
||||||
lastName: euroBonusProfile.lastName || null,
|
lastName: euroBonusProfile.lastName || null,
|
||||||
|
|||||||
25
packages/booking-flow/README.md
Normal file
25
packages/booking-flow/README.md
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
# @scandic-hotels/booking-flow
|
||||||
|
|
||||||
|
Shared package containing the hotel booking flow functionality used by `scandic-web` and partner sites.
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
To use the booking flow, two main contexts must be set up: `BookingFlowConfig` and `BookingFlowContext`. Both receive injected values from the consuming app.
|
||||||
|
|
||||||
|
**`BookingFlowConfig`** is static configuration that controls features and behavior (e.g. booking codes enabled), while **`BookingFlowContext`** is dynamic state provided by the consuming site (e.g. user authentication status).
|
||||||
|
|
||||||
|
The **config** sets up both a server side and client side context provider. You can use `getBookingFlowConfig` server side and `useBookingFlowConfig` client side to access the config values.
|
||||||
|
|
||||||
|
The **context** is only provided client side, and can be accessed using the `useBookingFlowContext` hook.
|
||||||
|
|
||||||
|
There's also some setup required for **tRPC** to work with the booking flow. See the [tRPC context](../trpc/lib/context.ts) and how it's used in the consuming apps for details.
|
||||||
|
|
||||||
|
## Translations
|
||||||
|
|
||||||
|
Translations for the booking flow components work similarly to other parts of the app, using `react-intl`. See [translations.md](../../docs/translations.md) for more information on how translations are set up in the apps.
|
||||||
|
|
||||||
|
We currently do not dependency inject any translation messages from the consuming apps, so for now all booking-flow translation messages for the different sites are included in all app bundles. This should be improved in the future.
|
||||||
|
|
||||||
|
## Other
|
||||||
|
|
||||||
|
Components that are currently exported but are intended for external use should probably move to design-system or similar in the future.
|
||||||
@@ -33,6 +33,7 @@ export const useGetPointsCurrency = () => {
|
|||||||
case "partner-sas":
|
case "partner-sas":
|
||||||
return CurrencyEnum.EUROBONUS
|
return CurrencyEnum.EUROBONUS
|
||||||
default:
|
default:
|
||||||
|
const _exhaustiveCheck: never = config.variant
|
||||||
throw new Error(`Unknown variant: ${config.variant}`)
|
throw new Error(`Unknown variant: ${config.variant}`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ type BaseUser = {
|
|||||||
|
|
||||||
export type BookingFlowUser =
|
export type BookingFlowUser =
|
||||||
| (BaseUser & {
|
| (BaseUser & {
|
||||||
type: "partner-sas"
|
type: "partner"
|
||||||
partnerLoyaltyNumber: `EB${string}`
|
partnerLoyaltyNumber: string
|
||||||
isLinked: boolean
|
isLinked: boolean
|
||||||
})
|
})
|
||||||
| (BaseUser & {
|
| (BaseUser & {
|
||||||
|
|||||||
@@ -55,17 +55,23 @@ export function getErrorMessage(
|
|||||||
"Multi-room booking is not available with this booking code.",
|
"Multi-room booking is not available with this booking code.",
|
||||||
})
|
})
|
||||||
case bookingWidgetErrors.MULTIROOM_REWARD_NIGHT_UNAVAILABLE:
|
case bookingWidgetErrors.MULTIROOM_REWARD_NIGHT_UNAVAILABLE:
|
||||||
return variant === "partner-sas"
|
switch (variant) {
|
||||||
? intl.formatMessage({
|
case "scandic":
|
||||||
id: "partnerSas.error.multiroomRewardNightUnavailable",
|
return intl.formatMessage({
|
||||||
defaultMessage:
|
|
||||||
"Multi-room bookings are not available with EuroBonus points.",
|
|
||||||
})
|
|
||||||
: intl.formatMessage({
|
|
||||||
id: "error.multiroomRewardNightUnavailable",
|
id: "error.multiroomRewardNightUnavailable",
|
||||||
defaultMessage:
|
defaultMessage:
|
||||||
"Multi-room booking is not available with reward night.",
|
"Multi-room booking is not available with reward night.",
|
||||||
})
|
})
|
||||||
|
case "partner-sas":
|
||||||
|
return intl.formatMessage({
|
||||||
|
id: "partnerSas.error.multiroomRewardNightUnavailable",
|
||||||
|
defaultMessage:
|
||||||
|
"Multi-room bookings are not available with EuroBonus points.",
|
||||||
|
})
|
||||||
|
default:
|
||||||
|
const _exhaustiveCheck: never = variant
|
||||||
|
throw new Error(`Unknown variant: ${variant}`)
|
||||||
|
}
|
||||||
case bookingWidgetErrors.CODE_VOUCHER_REWARD_NIGHT_UNAVAILABLE:
|
case bookingWidgetErrors.CODE_VOUCHER_REWARD_NIGHT_UNAVAILABLE:
|
||||||
return intl.formatMessage({
|
return intl.formatMessage({
|
||||||
id: "error.codeVoucherRewardNightUnavailable",
|
id: "error.codeVoucherRewardNightUnavailable",
|
||||||
|
|||||||
@@ -165,6 +165,9 @@ function getRewardMessage(config: BookingFlowConfig, intl: IntlShape): string {
|
|||||||
id: "bookingWidget.reward.rewardNight",
|
id: "bookingWidget.reward.rewardNight",
|
||||||
defaultMessage: "Reward Night",
|
defaultMessage: "Reward Night",
|
||||||
})
|
})
|
||||||
|
default:
|
||||||
|
const _exhaustiveCheck: never = config.variant
|
||||||
|
throw new Error(`Unknown variant: ${config.variant}`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,15 +25,19 @@ function Message() {
|
|||||||
const intl = useIntl()
|
const intl = useIntl()
|
||||||
const config = useBookingFlowConfig()
|
const config = useBookingFlowConfig()
|
||||||
|
|
||||||
if (config.variant === "partner-sas") {
|
switch (config.variant) {
|
||||||
return intl.formatMessage({
|
case "partner-sas":
|
||||||
id: "signup.toGetTheScandicMemberPrice",
|
return intl.formatMessage({
|
||||||
defaultMessage: "Enter ID or join to get the Scandic Friends price.",
|
id: "signup.toGetTheScandicMemberPrice",
|
||||||
})
|
defaultMessage: "Enter ID or join to get the Scandic Friends price.",
|
||||||
|
})
|
||||||
|
case "scandic":
|
||||||
|
return intl.formatMessage({
|
||||||
|
id: "signup.joinOrLoginForMemberPricing",
|
||||||
|
defaultMessage: "Join or log in while booking for member pricing.",
|
||||||
|
})
|
||||||
|
default:
|
||||||
|
const _exhaustiveCheck: never = config.variant
|
||||||
|
throw new Error(`Unknown variant: ${config.variant}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
return intl.formatMessage({
|
|
||||||
id: "signup.joinOrLoginForMemberPricing",
|
|
||||||
defaultMessage: "Join or log in while booking for member pricing.",
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// TODO should probably not need to export this outside package after moving entire booking flow
|
|
||||||
import { create } from "zustand"
|
import { create } from "zustand"
|
||||||
|
|
||||||
export enum BookingCodeFilterEnum {
|
export enum BookingCodeFilterEnum {
|
||||||
|
|||||||
@@ -242,7 +242,6 @@ export function serializeBookingSearchParams(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO duplicated until full booking flow is migrated to booking-flow package
|
|
||||||
export type DetailsBooking = {
|
export type DetailsBooking = {
|
||||||
hotelId: string
|
hotelId: string
|
||||||
fromDate: string
|
fromDate: string
|
||||||
|
|||||||
@@ -13,16 +13,17 @@ import type { TrackingUserData } from "../../types"
|
|||||||
export const userTrackingInfo = safeProtectedProcedure.query(async function ({
|
export const userTrackingInfo = safeProtectedProcedure.query(async function ({
|
||||||
ctx,
|
ctx,
|
||||||
}) {
|
}) {
|
||||||
if (ctx.app === "partner-sas") {
|
switch (ctx.app) {
|
||||||
const scandicUserToken = await ctx.getScandicUserToken()
|
case "partner-sas": {
|
||||||
return getSasEurobonusUserTrackingData(ctx.session, scandicUserToken)
|
const scandicUserToken = await ctx.getScandicUserToken()
|
||||||
|
return getSasEurobonusUserTrackingData(ctx.session, scandicUserToken)
|
||||||
|
}
|
||||||
|
case "scandic-web":
|
||||||
|
return getScandicFriendsUserTrackingData(ctx.session)
|
||||||
|
default:
|
||||||
|
const _exhaustiveCheck: never = ctx.app
|
||||||
|
return { loginStatus: "Error" } as const
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx.app === "scandic-web") {
|
|
||||||
return getScandicFriendsUserTrackingData(ctx.session)
|
|
||||||
}
|
|
||||||
|
|
||||||
return { loginStatus: "Error" } as const
|
|
||||||
})
|
})
|
||||||
|
|
||||||
async function getScandicFriendsUserTrackingData(session: Session | null) {
|
async function getScandicFriendsUserTrackingData(session: Session | null) {
|
||||||
|
|||||||
Reference in New Issue
Block a user