Merged in feat(SW-2084)-disable-options-modify-my-stay (pull request #1662)
feat(SW-2084) logic to disable Manage stay options * feat(SW-2084) logic to disable Manage stay options * feat(SW-2084) cleanup logic for checks * feat(SW-2084) check if date has passed * feat(SW-2084) change to datetimeIsInThePast Approved-by: Niclas Edenvin
This commit is contained in:
@@ -11,8 +11,10 @@ import styles from "../actionPanel.module.css"
|
||||
|
||||
export default function AddToCalendarButton({
|
||||
onPress,
|
||||
disabled,
|
||||
}: {
|
||||
onPress: () => void
|
||||
disabled?: boolean
|
||||
}) {
|
||||
const intl = useIntl()
|
||||
|
||||
@@ -25,9 +27,9 @@ export default function AddToCalendarButton({
|
||||
<Button
|
||||
variant="icon"
|
||||
intent="text"
|
||||
theme="base"
|
||||
className={styles.button}
|
||||
onPress={handleAddToCalendar}
|
||||
disabled={disabled}
|
||||
>
|
||||
{intl.formatMessage({ id: "Add to calendar" })}
|
||||
<MaterialIcon icon="calendar_add_on" color="CurrentColor" />
|
||||
|
||||
@@ -26,6 +26,21 @@
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.actionPanel .menu .button:disabled {
|
||||
color: var(--Scandic-Grey-40);
|
||||
}
|
||||
|
||||
.disabledLink {
|
||||
color: var(--Scandic-Grey-40);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: var(--Spacing-x1) 0;
|
||||
width: 100%;
|
||||
}
|
||||
.disabledLink:hover {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.info {
|
||||
width: 100%;
|
||||
background-color: var(--Base-Background-Primary-Normal);
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
"use client"
|
||||
|
||||
import { useMemo } from "react"
|
||||
import { useIntl } from "react-intl"
|
||||
|
||||
import { MaterialIcon } from "@scandic-hotels/design-system/Icons"
|
||||
import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||
|
||||
import { customerService } from "@/constants/currentWebHrefs"
|
||||
import { preliminaryReceipt } from "@/constants/routes/myStay"
|
||||
@@ -20,6 +22,13 @@ import useLang from "@/hooks/useLang"
|
||||
import { trackMyStayPageLink } from "@/utils/tracking"
|
||||
|
||||
import AddToCalendarButton from "./Actions/AddToCalendarButton"
|
||||
import {
|
||||
checkCancelable,
|
||||
checkCanDownloadInvoice,
|
||||
checkDateModifiable,
|
||||
checkGuaranteeable,
|
||||
isDatetimePast,
|
||||
} from "./utils"
|
||||
|
||||
import styles from "./actionPanel.module.css"
|
||||
|
||||
@@ -43,14 +52,42 @@ export default function ActionPanel({ hotel }: ActionPanelProps) {
|
||||
(state) => state.linkedReservationRooms
|
||||
)
|
||||
|
||||
const showCancelStayButton =
|
||||
bookedRoom.isCancelable ||
|
||||
linkedReservationRooms.some((room) => room.isCancelable)
|
||||
const showGuaranteeButton =
|
||||
!bookedRoom.guaranteeInfo && !bookedRoom.isCancelled
|
||||
const {
|
||||
confirmationNumber,
|
||||
checkInDate,
|
||||
checkOutDate,
|
||||
createDateTime,
|
||||
canChangeDate,
|
||||
isPrePaid,
|
||||
} = bookedRoom
|
||||
|
||||
const { confirmationNumber, checkInDate, checkOutDate, createDateTime } =
|
||||
bookedRoom
|
||||
const datetimeIsInThePast = useMemo(
|
||||
() => isDatetimePast(checkInDate),
|
||||
[checkInDate]
|
||||
)
|
||||
|
||||
const isDateModifyable = checkDateModifiable({
|
||||
canChangeDate,
|
||||
datetimeIsInThePast,
|
||||
isCancelled: bookedRoom.isCancelled,
|
||||
isPrePaid,
|
||||
})
|
||||
|
||||
const isCancelable = checkCancelable({
|
||||
bookedRoom,
|
||||
linkedReservationRooms,
|
||||
datetimeIsInThePast,
|
||||
})
|
||||
|
||||
const isGuaranteeable = checkGuaranteeable({
|
||||
bookedRoom,
|
||||
datetimeIsInThePast,
|
||||
})
|
||||
|
||||
const canDownloadInvoice = checkCanDownloadInvoice({
|
||||
isCancelled: bookedRoom.isCancelled,
|
||||
isPrePaid,
|
||||
})
|
||||
|
||||
const calendarEvent: EventAttributes = {
|
||||
busyStatus: "FREE",
|
||||
@@ -102,48 +139,65 @@ export default function ActionPanel({ hotel }: ActionPanelProps) {
|
||||
onClick={handleModifyStay}
|
||||
intent="text"
|
||||
className={styles.button}
|
||||
disabled={!isDateModifyable}
|
||||
>
|
||||
{intl.formatMessage({ id: "Modify dates" })}
|
||||
<MaterialIcon icon="calendar_month" color="CurrentColor" />
|
||||
</Button>
|
||||
{showGuaranteeButton && (
|
||||
<Button
|
||||
variant="icon"
|
||||
onClick={handleGuaranteeLateArrival}
|
||||
intent="text"
|
||||
className={styles.button}
|
||||
>
|
||||
{intl.formatMessage({ id: "Guarantee late arrival" })}
|
||||
<MaterialIcon icon="credit_card" color="CurrentColor" />
|
||||
</Button>
|
||||
)}
|
||||
|
||||
<Button
|
||||
variant="icon"
|
||||
onClick={handleGuaranteeLateArrival}
|
||||
intent="text"
|
||||
className={styles.button}
|
||||
disabled={!isGuaranteeable}
|
||||
>
|
||||
{intl.formatMessage({ id: "Guarantee late arrival" })}
|
||||
<MaterialIcon icon="credit_card" color="CurrentColor" />
|
||||
</Button>
|
||||
|
||||
<AddToCalendar
|
||||
checkInDate={checkInDate}
|
||||
event={calendarEvent}
|
||||
hotelName={hotel.name}
|
||||
renderButton={(onPress) => <AddToCalendarButton onPress={onPress} />}
|
||||
renderButton={(onPress) => (
|
||||
<AddToCalendarButton
|
||||
onPress={onPress}
|
||||
disabled={datetimeIsInThePast}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
<Link
|
||||
href={preliminaryReceipt[lang]}
|
||||
target="_blank"
|
||||
keepSearchParams
|
||||
className={styles.actionLink}
|
||||
onClick={handleDownloadInvoice}
|
||||
>
|
||||
{intl.formatMessage({ id: "Download invoice" })}
|
||||
<MaterialIcon icon="download" color="CurrentColor" />
|
||||
</Link>
|
||||
{showCancelStayButton && (
|
||||
<Button
|
||||
variant="icon"
|
||||
onClick={handleCancelStay}
|
||||
intent="text"
|
||||
className={styles.button}
|
||||
{canDownloadInvoice ? (
|
||||
<Link
|
||||
href={preliminaryReceipt[lang]}
|
||||
target="_blank"
|
||||
keepSearchParams
|
||||
className={styles.actionLink}
|
||||
onClick={handleDownloadInvoice}
|
||||
>
|
||||
{intl.formatMessage({ id: "Cancel stay" })}
|
||||
<MaterialIcon icon="cancel" color="CurrentColor" />
|
||||
</Button>
|
||||
{intl.formatMessage({ id: "Download invoice" })}
|
||||
<MaterialIcon icon="download" color="CurrentColor" />
|
||||
</Link>
|
||||
) : (
|
||||
<div className={styles.disabledLink}>
|
||||
<Typography variant="Body/Paragraph/mdBold">
|
||||
<p>{intl.formatMessage({ id: "Download invoice" })}</p>
|
||||
</Typography>
|
||||
|
||||
<MaterialIcon icon="download" color="CurrentColor" />
|
||||
</div>
|
||||
)}
|
||||
|
||||
<Button
|
||||
variant="icon"
|
||||
onClick={handleCancelStay}
|
||||
intent="text"
|
||||
className={styles.button}
|
||||
disabled={!isCancelable}
|
||||
>
|
||||
{intl.formatMessage({ id: "Cancel stay" })}
|
||||
<MaterialIcon icon="cancel" color="CurrentColor" />
|
||||
</Button>
|
||||
</div>
|
||||
<div className={styles.info}>
|
||||
<div>
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
import { CancellationRuleEnum } from "@/constants/booking"
|
||||
|
||||
import type { Room } from "@/stores/my-stay/myStayRoomDetailsStore"
|
||||
|
||||
interface ModificationConditions {
|
||||
canModify: boolean
|
||||
isNotPast: boolean
|
||||
isNotCancelled: boolean
|
||||
isNotPrePaid: boolean
|
||||
}
|
||||
|
||||
interface GuaranteeConditions {
|
||||
isCancellableBefore6PM: boolean
|
||||
hasNoGuaranteeInfo: boolean
|
||||
isNotCancelled: boolean
|
||||
isNotPast: boolean
|
||||
}
|
||||
|
||||
export function isDatetimePast(date: Date): boolean {
|
||||
return new Date(date) < new Date()
|
||||
}
|
||||
|
||||
export function checkDateModifiable({
|
||||
canChangeDate,
|
||||
datetimeIsInThePast,
|
||||
isCancelled,
|
||||
isPrePaid,
|
||||
}: {
|
||||
canChangeDate: boolean
|
||||
datetimeIsInThePast: boolean
|
||||
isCancelled: boolean
|
||||
isPrePaid: boolean
|
||||
}): boolean {
|
||||
const conditions: ModificationConditions = {
|
||||
canModify: canChangeDate,
|
||||
isNotPast: !datetimeIsInThePast,
|
||||
isNotCancelled: !isCancelled,
|
||||
isNotPrePaid: !isPrePaid,
|
||||
}
|
||||
|
||||
return Object.values(conditions).every(Boolean)
|
||||
}
|
||||
|
||||
export function checkCancelable({
|
||||
bookedRoom,
|
||||
linkedReservationRooms,
|
||||
datetimeIsInThePast,
|
||||
}: {
|
||||
bookedRoom: Room
|
||||
linkedReservationRooms: Room[]
|
||||
datetimeIsInThePast: boolean
|
||||
}): boolean {
|
||||
const hasAnyCancelableRoom =
|
||||
bookedRoom.isCancelable ||
|
||||
linkedReservationRooms.some((room) => room.isCancelable)
|
||||
|
||||
return hasAnyCancelableRoom && !datetimeIsInThePast
|
||||
}
|
||||
|
||||
export function checkGuaranteeable({
|
||||
bookedRoom,
|
||||
datetimeIsInThePast,
|
||||
}: {
|
||||
bookedRoom: Room
|
||||
datetimeIsInThePast: boolean
|
||||
}): boolean {
|
||||
const conditions: GuaranteeConditions = {
|
||||
isCancellableBefore6PM:
|
||||
bookedRoom.rateDefinition.cancellationRule ===
|
||||
CancellationRuleEnum.CancellableBefore6PM,
|
||||
hasNoGuaranteeInfo: !bookedRoom.guaranteeInfo,
|
||||
isNotCancelled: !bookedRoom.isCancelled,
|
||||
isNotPast: !datetimeIsInThePast,
|
||||
}
|
||||
|
||||
return Object.values(conditions).every(Boolean)
|
||||
}
|
||||
|
||||
export function checkCanDownloadInvoice({
|
||||
isCancelled,
|
||||
isPrePaid,
|
||||
}: {
|
||||
isCancelled: boolean
|
||||
isPrePaid: boolean
|
||||
}): boolean {
|
||||
return !isCancelled && isPrePaid
|
||||
}
|
||||
Reference in New Issue
Block a user