feat: refactor NewDates, clean up legacy code
This reverts commit 0c7836fa59.
This commit is contained in:
@@ -1,3 +1,7 @@
|
||||
.dialog {
|
||||
max-width: 690px;
|
||||
}
|
||||
|
||||
.links {
|
||||
display: grid;
|
||||
gap: var(--Space-x05);
|
||||
|
||||
@@ -8,7 +8,7 @@ import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||
|
||||
import { useMyStayStore } from "@/stores/my-stay"
|
||||
|
||||
import Modal from "@/components/HotelReservation/MyStay/ReferenceCard/Modal"
|
||||
import Modal from "@/components/HotelReservation/MyStay/Modal"
|
||||
|
||||
import styles from "./customerSupport.module.css"
|
||||
|
||||
@@ -30,7 +30,7 @@ export default function CustomerSupportModal() {
|
||||
|
||||
return (
|
||||
<Modal>
|
||||
<Dialog>
|
||||
<Dialog className={styles.dialog}>
|
||||
{({ close }) => (
|
||||
<Modal.Content>
|
||||
<Modal.Content.Header handleClose={close} title={title}>
|
||||
|
||||
@@ -15,4 +15,5 @@
|
||||
|
||||
.text {
|
||||
color: var(--Text-Interactive-Default);
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { useIntl } from "react-intl"
|
||||
|
||||
import { useMyStayStore } from "@/stores/my-stay"
|
||||
|
||||
import Modal from "@/components/HotelReservation/MyStay/ReferenceCard/Modal"
|
||||
import Modal from "@/components/HotelReservation/MyStay/Modal"
|
||||
import Alert from "@/components/TempDesignSystem/Alert"
|
||||
|
||||
import { AlertTypeEnum } from "@/types/enums/alert"
|
||||
|
||||
@@ -7,7 +7,7 @@ import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||
import { dt } from "@/lib/dt"
|
||||
import { useMyStayStore } from "@/stores/my-stay"
|
||||
|
||||
import Modal from "@/components/HotelReservation/MyStay/ReferenceCard/Modal"
|
||||
import Modal from "@/components/HotelReservation/MyStay/Modal"
|
||||
import useLang from "@/hooks/useLang"
|
||||
|
||||
import CancelStayPriceContainer from "../CancelStayPriceContainer"
|
||||
|
||||
@@ -7,7 +7,7 @@ import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||
import { trpc } from "@/lib/trpc/client"
|
||||
import { useMyStayStore } from "@/stores/my-stay"
|
||||
|
||||
import Modal from "@/components/HotelReservation/MyStay/ReferenceCard/Modal"
|
||||
import Modal from "@/components/HotelReservation/MyStay/Modal"
|
||||
import { toast } from "@/components/TempDesignSystem/Toasts"
|
||||
import useLang from "@/hooks/useLang"
|
||||
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
.dialog {
|
||||
max-width: 690px;
|
||||
}
|
||||
|
||||
.modalText {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
@@ -2,11 +2,13 @@
|
||||
import { Dialog, DialogTrigger } from "react-aria-components"
|
||||
import { useIntl } from "react-intl"
|
||||
|
||||
import Modal from "@/components/HotelReservation/MyStay/ReferenceCard/Modal"
|
||||
import Modal from "@/components/HotelReservation/MyStay/Modal"
|
||||
|
||||
import Alerts from "./Alerts"
|
||||
import Steps from "./Steps"
|
||||
|
||||
import styles from "./cancelStay.module.css"
|
||||
|
||||
export default function CancelStay() {
|
||||
const intl = useIntl()
|
||||
return (
|
||||
@@ -15,7 +17,7 @@ export default function CancelStay() {
|
||||
{intl.formatMessage({ defaultMessage: "Cancel stay" })}
|
||||
</Modal.Button>
|
||||
<Modal>
|
||||
<Dialog>
|
||||
<Dialog className={styles.dialog}>
|
||||
{({ close }) => (
|
||||
<Alerts closeModal={close}>
|
||||
<Steps closeModal={close} />
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"use client"
|
||||
import { useIntl } from "react-intl"
|
||||
|
||||
import Modal from "@/components/HotelReservation/MyStay/ReferenceCard/Modal"
|
||||
import Modal from "@/components/HotelReservation/MyStay/Modal"
|
||||
import Alert from "@/components/TempDesignSystem/Alert"
|
||||
|
||||
import { AlertTypeEnum } from "@/types/enums/alert"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"use client"
|
||||
import { useIntl } from "react-intl"
|
||||
|
||||
import Modal from "@/components/HotelReservation/MyStay/ReferenceCard/Modal"
|
||||
import Modal from "@/components/HotelReservation/MyStay/Modal"
|
||||
import Alert from "@/components/TempDesignSystem/Alert"
|
||||
|
||||
import { AlertTypeEnum } from "@/types/enums/alert"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"use client"
|
||||
import { useIntl } from "react-intl"
|
||||
|
||||
import Modal from "@/components/HotelReservation/MyStay/ReferenceCard/Modal"
|
||||
import Modal from "@/components/HotelReservation/MyStay/Modal"
|
||||
import Alert from "@/components/TempDesignSystem/Alert"
|
||||
|
||||
import { AlertTypeEnum } from "@/types/enums/alert"
|
||||
|
||||
@@ -5,7 +5,7 @@ import { dt } from "@/lib/dt"
|
||||
import { trpc } from "@/lib/trpc/client"
|
||||
import { useMyStayStore } from "@/stores/my-stay"
|
||||
|
||||
import Modal from "@/components/HotelReservation/MyStay/ReferenceCard/Modal"
|
||||
import Modal from "@/components/HotelReservation/MyStay/Modal"
|
||||
import PriceContainer from "@/components/HotelReservation/MyStay/ReferenceCard/PriceContainer"
|
||||
import Divider from "@/components/TempDesignSystem/Divider"
|
||||
import { toast } from "@/components/TempDesignSystem/Toasts"
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
.button {
|
||||
background-color: var(--Main-Grey-White);
|
||||
border-color: var(--Scandic-Beige-40);
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
border-radius: var(--Corner-radius-Medium);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
min-width: 0; /* allow shrinkage */
|
||||
height: 60px;
|
||||
padding: var(--Spacing-x1) var(--Spacing-x2);
|
||||
transition: border-color 200ms ease;
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
"use client"
|
||||
|
||||
import { Button as ButtonRAC } from "react-aria-components"
|
||||
|
||||
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
|
||||
import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||
|
||||
import styles from "./calendarButton.module.css"
|
||||
|
||||
interface CalendarButtonProps {
|
||||
text: string
|
||||
onClick: () => void
|
||||
}
|
||||
|
||||
export default function CalendarButton({ text, onClick }: CalendarButtonProps) {
|
||||
return (
|
||||
<ButtonRAC onPress={onClick} className={styles.button}>
|
||||
<Typography variant="Body/Paragraph/mdRegular">
|
||||
<span>{text}</span>
|
||||
</Typography>
|
||||
<MaterialIcon icon="calendar_today" />
|
||||
</ButtonRAC>
|
||||
)
|
||||
}
|
||||
@@ -1,39 +1,33 @@
|
||||
"use client"
|
||||
import { useState } from "react"
|
||||
import { createPortal } from "react-dom"
|
||||
import { useFormContext } from "react-hook-form"
|
||||
import {
|
||||
Button as ButtonRAC,
|
||||
Dialog,
|
||||
DialogTrigger,
|
||||
} from "react-aria-components"
|
||||
import { useFormContext, useWatch } from "react-hook-form"
|
||||
import { useIntl } from "react-intl"
|
||||
|
||||
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
|
||||
import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||
|
||||
import { dt } from "@/lib/dt"
|
||||
import { useMyStayStore } from "@/stores/my-stay"
|
||||
|
||||
import DatePickerSingleDesktop from "@/components/DatePicker/Single/Desktop"
|
||||
import DatePickerSingleMobile from "@/components/DatePicker/Single/Mobile"
|
||||
import Modal from "@/components/Modal"
|
||||
import Caption from "@/components/TempDesignSystem/Text/Caption"
|
||||
import Modal from "@/components/HotelReservation/MyStay/Modal"
|
||||
import useLang from "@/hooks/useLang"
|
||||
|
||||
import CalendarButton from "./CalendarButton"
|
||||
|
||||
import styles from "./newDates.module.css"
|
||||
|
||||
import type { DateRange } from "react-day-picker"
|
||||
|
||||
export default function NewDates() {
|
||||
const { checkInDate, checkOutDate } = useMyStayStore((state) => ({
|
||||
checkInDate: state.mainRoom.checkInDate,
|
||||
checkOutDate: state.mainRoom.checkOutDate,
|
||||
}))
|
||||
|
||||
const [showCheckInDatePicker, setShowCheckInDatePicker] = useState(false)
|
||||
const [showCheckOutDatePicker, setShowCheckOutDatePicker] = useState(false)
|
||||
const [selectedDates, setSelectedDates] = useState<DateRange>(() => ({
|
||||
from: dt(checkInDate).startOf("day").toDate(),
|
||||
to: dt(checkOutDate).startOf("day").toDate(),
|
||||
}))
|
||||
interface NewDatesProps {
|
||||
checkInDate: Date
|
||||
checkOutDate: Date
|
||||
}
|
||||
|
||||
export default function NewDates({ checkInDate, checkOutDate }: NewDatesProps) {
|
||||
const intl = useIntl()
|
||||
const lang = useLang()
|
||||
|
||||
const { setValue } = useFormContext()
|
||||
|
||||
// Calculate default number of days between check-in and check-out
|
||||
@@ -41,147 +35,111 @@ export default function NewDates() {
|
||||
.startOf("day")
|
||||
.diff(dt(checkInDate).startOf("day"), "days")
|
||||
|
||||
function showCheckInPicker() {
|
||||
// Update selected dates before showing picker
|
||||
setSelectedDates((prev) => ({
|
||||
from: prev.from ?? dt(checkInDate).startOf("day").toDate(),
|
||||
to: prev.to ?? dt(checkOutDate).startOf("day").toDate(),
|
||||
}))
|
||||
setShowCheckInDatePicker(true)
|
||||
setShowCheckOutDatePicker(false)
|
||||
const fromDate = useWatch({ name: "checkInDate" })
|
||||
const toDate = useWatch({ name: "checkOutDate" })
|
||||
|
||||
function handleSelectDate(date: Date, name: "checkInDate" | "checkOutDate") {
|
||||
setValue(name, dt(date).format("YYYY-MM-DD"))
|
||||
}
|
||||
|
||||
function showCheckOutPicker() {
|
||||
// Update selected dates before showing picker
|
||||
setSelectedDates((prev) => ({
|
||||
from: prev.from ?? dt(checkInDate).startOf("day").toDate(),
|
||||
to: prev.to ?? dt(checkOutDate).startOf("day").toDate(),
|
||||
}))
|
||||
setShowCheckOutDatePicker(true)
|
||||
setShowCheckInDatePicker(false)
|
||||
}
|
||||
|
||||
function handleCheckInDateSelect(date: Date) {
|
||||
const newCheckIn = dt(date).startOf("day")
|
||||
const currentCheckOut = dt(selectedDates.to).startOf("day")
|
||||
|
||||
// Calculate new check-out date based on defaultDaysBetween, only if new check-in is after current check-out
|
||||
const newCheckOut = newCheckIn.isSameOrAfter(currentCheckOut)
|
||||
? newCheckIn.add(defaultDaysBetween, "days")
|
||||
: currentCheckOut
|
||||
|
||||
// Update selected dates state first
|
||||
const newDates = {
|
||||
from: newCheckIn.toDate(),
|
||||
to: newCheckOut.toDate(),
|
||||
function handleSelectCheckInDate(checkIn: Date) {
|
||||
handleSelectDate(checkIn, "checkInDate")
|
||||
if (dt(checkIn).isSameOrAfter(toDate)) {
|
||||
handleSelectDate(
|
||||
dt(checkIn).add(defaultDaysBetween, "days").toDate(),
|
||||
"checkOutDate"
|
||||
)
|
||||
}
|
||||
setSelectedDates(newDates)
|
||||
|
||||
// Then update form values
|
||||
setValue("checkInDate", newCheckIn.format("YYYY-MM-DD"))
|
||||
setValue("checkOutDate", newCheckOut.format("YYYY-MM-DD"))
|
||||
}
|
||||
|
||||
function handleCheckOutDateSelect(date: Date) {
|
||||
const newCheckOut = dt(date).startOf("day")
|
||||
const currentCheckIn = dt(selectedDates.from).startOf("day")
|
||||
|
||||
// Only adjust check-in if new check-out is before current check-in
|
||||
const newCheckIn = newCheckOut.isBefore(currentCheckIn)
|
||||
? newCheckOut.subtract(defaultDaysBetween, "days")
|
||||
: currentCheckIn
|
||||
|
||||
// Update selected dates state
|
||||
const newDates = {
|
||||
from: newCheckIn.toDate(),
|
||||
to: newCheckOut.toDate(),
|
||||
function handleSelectCheckOutDate(checkOut: Date) {
|
||||
handleSelectDate(checkOut, "checkOutDate")
|
||||
if (dt(checkOut).isSameOrBefore(fromDate)) {
|
||||
handleSelectDate(
|
||||
dt(checkOut).subtract(defaultDaysBetween, "days").toDate(),
|
||||
"checkInDate"
|
||||
)
|
||||
}
|
||||
setSelectedDates(newDates)
|
||||
|
||||
// Then update form values
|
||||
setValue("checkInDate", newCheckIn.format("YYYY-MM-DD"))
|
||||
setValue("checkOutDate", newCheckOut.format("YYYY-MM-DD"))
|
||||
}
|
||||
|
||||
const fromDate = selectedDates.from ?? dt(checkInDate).toDate()
|
||||
const toDate = selectedDates.to ?? dt(checkOutDate).toDate()
|
||||
const checkInLabel = intl.formatMessage({ defaultMessage: "Check-in" })
|
||||
const checkOutLabel = intl.formatMessage({ defaultMessage: "Check-out" })
|
||||
|
||||
const checkInText = dt(fromDate).locale(lang).format("dddd, DD MMM, YYYY")
|
||||
const checkOutText = dt(toDate).locale(lang).format("dddd, DD MMM, YYYY")
|
||||
return (
|
||||
<>
|
||||
<div className={styles.container}>
|
||||
<div className={styles.checkInDate}>
|
||||
<Caption color="uiTextHighContrast" type="bold">
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Check-in",
|
||||
})}
|
||||
</Caption>
|
||||
<Typography variant="Body/Supporting text (caption)/smBold">
|
||||
<span className={styles.textDefault}>{checkInLabel}</span>
|
||||
</Typography>
|
||||
|
||||
<CalendarButton
|
||||
text={dt(selectedDates.from ?? new Date())
|
||||
.locale(lang)
|
||||
.format("dddd, DD MMM, YYYY")}
|
||||
onClick={showCheckInPicker}
|
||||
/>
|
||||
<DialogTrigger>
|
||||
<ButtonRAC className={styles.trigger}>
|
||||
<Typography variant="Body/Paragraph/mdRegular">
|
||||
<span>{checkInText}</span>
|
||||
</Typography>
|
||||
<MaterialIcon icon="calendar_today" />
|
||||
</ButtonRAC>
|
||||
<Modal>
|
||||
<Dialog>
|
||||
{({ close }) => (
|
||||
<>
|
||||
<DatePickerSingleDesktop
|
||||
close={close}
|
||||
handleOnSelect={handleSelectCheckInDate}
|
||||
selectedDate={fromDate}
|
||||
startMonth={fromDate}
|
||||
/>
|
||||
<DatePickerSingleMobile
|
||||
close={close}
|
||||
handleOnSelect={handleSelectCheckInDate}
|
||||
hideHeader
|
||||
selectedDate={fromDate}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</Dialog>
|
||||
</Modal>
|
||||
</DialogTrigger>
|
||||
</div>
|
||||
<div className={styles.checkOutDate}>
|
||||
<Caption color="uiTextHighContrast" type="bold">
|
||||
{intl.formatMessage({
|
||||
defaultMessage: "Check-out",
|
||||
})}
|
||||
</Caption>
|
||||
|
||||
<CalendarButton
|
||||
text={dt(selectedDates.to ?? new Date())
|
||||
.locale(lang)
|
||||
.format("dddd, DD MMM, YYYY")}
|
||||
onClick={showCheckOutPicker}
|
||||
/>
|
||||
<div className={styles.checkOutDate}>
|
||||
<Typography variant="Body/Supporting text (caption)/smBold">
|
||||
<span className={styles.textDefault}>{checkOutLabel}</span>
|
||||
</Typography>
|
||||
|
||||
<DialogTrigger>
|
||||
<ButtonRAC className={styles.trigger}>
|
||||
<Typography variant="Body/Paragraph/mdRegular">
|
||||
<span>{checkOutText}</span>
|
||||
</Typography>
|
||||
<MaterialIcon icon="calendar_today" />
|
||||
</ButtonRAC>
|
||||
<Modal>
|
||||
<Dialog>
|
||||
{({ close }) => (
|
||||
<>
|
||||
<DatePickerSingleDesktop
|
||||
close={close}
|
||||
handleOnSelect={handleSelectCheckOutDate}
|
||||
selectedDate={toDate}
|
||||
startMonth={toDate}
|
||||
/>
|
||||
<DatePickerSingleMobile
|
||||
close={close}
|
||||
handleOnSelect={handleSelectCheckOutDate}
|
||||
hideHeader
|
||||
selectedDate={toDate}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</Dialog>
|
||||
</Modal>
|
||||
</DialogTrigger>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{showCheckInDatePicker &&
|
||||
createPortal(
|
||||
<Modal
|
||||
isOpen={showCheckInDatePicker}
|
||||
onToggle={() => setShowCheckInDatePicker(!showCheckInDatePicker)}
|
||||
>
|
||||
<DatePickerSingleDesktop
|
||||
close={() => setShowCheckInDatePicker(false)}
|
||||
handleOnSelect={handleCheckInDateSelect}
|
||||
selectedDate={fromDate}
|
||||
startMonth={fromDate}
|
||||
/>
|
||||
<DatePickerSingleMobile
|
||||
close={() => setShowCheckInDatePicker(false)}
|
||||
handleOnSelect={handleCheckInDateSelect}
|
||||
selectedDate={fromDate}
|
||||
hideHeader
|
||||
/>
|
||||
</Modal>,
|
||||
document.body
|
||||
)}
|
||||
|
||||
{showCheckOutDatePicker &&
|
||||
createPortal(
|
||||
<Modal
|
||||
isOpen={showCheckOutDatePicker}
|
||||
onToggle={() => setShowCheckOutDatePicker(!showCheckOutDatePicker)}
|
||||
>
|
||||
<DatePickerSingleDesktop
|
||||
close={() => setShowCheckOutDatePicker(false)}
|
||||
handleOnSelect={handleCheckOutDateSelect}
|
||||
selectedDate={toDate}
|
||||
startMonth={toDate}
|
||||
/>
|
||||
<DatePickerSingleMobile
|
||||
close={() => setShowCheckOutDatePicker(false)}
|
||||
handleOnSelect={handleCheckOutDateSelect}
|
||||
selectedDate={toDate}
|
||||
hideHeader
|
||||
/>
|
||||
</Modal>,
|
||||
document.body
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -13,3 +13,23 @@
|
||||
flex-direction: column;
|
||||
gap: var(--Spacing-x1);
|
||||
}
|
||||
|
||||
.trigger {
|
||||
align-items: center;
|
||||
background-color: var(--Main-Grey-White);
|
||||
border-color: var(--Scandic-Beige-40);
|
||||
border-radius: var(--Corner-radius-Medium);
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
display: flex;
|
||||
height: 60px;
|
||||
justify-content: space-between;
|
||||
min-width: 0;
|
||||
/* allow shrinkage */
|
||||
padding: var(--Spacing-x1) var(--Spacing-x2);
|
||||
transition: border-color 200ms ease;
|
||||
}
|
||||
|
||||
.textDefault {
|
||||
color: var(--Text-Default);
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import { useIntl } from "react-intl"
|
||||
import { dt } from "@/lib/dt"
|
||||
import { useMyStayStore } from "@/stores/my-stay"
|
||||
|
||||
import Modal from "@/components/HotelReservation/MyStay/ReferenceCard/Modal"
|
||||
import Modal from "@/components/HotelReservation/MyStay/Modal"
|
||||
import { toast } from "@/components/TempDesignSystem/Toasts"
|
||||
|
||||
import NoAvailability from "./Alerts/NoAvailability"
|
||||
@@ -62,7 +62,7 @@ export default function Form({
|
||||
/>
|
||||
<Modal.Content.Body>
|
||||
{noAvailability && <NoAvailability />}
|
||||
<NewDates />
|
||||
<NewDates checkInDate={checkInDate} checkOutDate={checkOutDate} />
|
||||
</Modal.Content.Body>
|
||||
<Modal.Content.Footer>
|
||||
<Modal.Content.Footer.Secondary onClick={closeModal}>
|
||||
|
||||
@@ -4,7 +4,7 @@ import { useIntl } from "react-intl"
|
||||
|
||||
import { useMyStayStore } from "@/stores/my-stay"
|
||||
|
||||
import Modal from "@/components/HotelReservation/MyStay/ReferenceCard/Modal"
|
||||
import Modal from "@/components/HotelReservation/MyStay/Modal"
|
||||
|
||||
import { dateHasPassed } from "../utils"
|
||||
import Alerts from "./Alerts"
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
import { DialogTrigger } from "react-aria-components"
|
||||
import { useIntl } from "react-intl"
|
||||
|
||||
import Modal from "@/components/HotelReservation/MyStay/Modal"
|
||||
import CustomerSupportModal from "@/components/HotelReservation/MyStay/ReferenceCard/Actions/CustomerSupportModal"
|
||||
import Modal from "@/components/HotelReservation/MyStay/ReferenceCard/Modal"
|
||||
|
||||
export default function CustomerSupport() {
|
||||
const intl = useIntl()
|
||||
|
||||
@@ -34,15 +34,21 @@
|
||||
}
|
||||
|
||||
.guaranteeCostText {
|
||||
align-items: flex-end;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.baseTextHighContrast {
|
||||
color: var(--Base-Text-High-contrast);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.textDefault {
|
||||
color: var(--Text-Default);
|
||||
}
|
||||
|
||||
@media screen and (min-width: 768px) {
|
||||
.guaranteeCostText {
|
||||
align-items: flex-end;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
.dialog {
|
||||
max-width: 690px;
|
||||
}
|
||||
@@ -6,11 +6,13 @@ import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||
|
||||
import { useMyStayStore } from "@/stores/my-stay"
|
||||
|
||||
import Modal from "@/components/HotelReservation/MyStay/ReferenceCard/Modal"
|
||||
import Modal from "@/components/HotelReservation/MyStay/Modal"
|
||||
|
||||
import { dateHasPassed } from "../utils"
|
||||
import Form from "./Form"
|
||||
|
||||
import styles from "./guarantee.module.css"
|
||||
|
||||
export default function GuaranteeLateArrival() {
|
||||
const intl = useIntl()
|
||||
|
||||
@@ -41,7 +43,7 @@ export default function GuaranteeLateArrival() {
|
||||
<DialogTrigger>
|
||||
<Modal.Button icon="check">{text}</Modal.Button>
|
||||
<Modal>
|
||||
<Dialog>
|
||||
<Dialog className={styles.dialog}>
|
||||
{({ close }) => (
|
||||
<Modal.Content>
|
||||
<Modal.Content.Header handleClose={close} title={text}>
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
background-color: var(--Surface-Primary-OnSurface-Default);
|
||||
border-radius: var(--Corner-radius-md);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--Space-x2);
|
||||
justify-content: center;
|
||||
padding: var(--Space-x15) var(--Space-x3);
|
||||
@@ -27,3 +26,9 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 768px) {
|
||||
.container {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||
|
||||
import { useMyStayStore } from "@/stores/my-stay"
|
||||
|
||||
import Modal from "@/components/HotelReservation/MyStay/ReferenceCard/Modal"
|
||||
import Modal from "@/components/HotelReservation/MyStay/Modal"
|
||||
|
||||
import Actions from "./Actions"
|
||||
import Info from "./Info"
|
||||
|
||||
@@ -24,7 +24,8 @@
|
||||
|
||||
.dialog {
|
||||
display: grid;
|
||||
gap: var(--Space-x3);
|
||||
flex: 1;
|
||||
gap: var(--Space-x2);
|
||||
}
|
||||
|
||||
.header {
|
||||
@@ -47,6 +48,16 @@
|
||||
|
||||
.content {
|
||||
display: grid;
|
||||
gap: var(--Space-x3);
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: var(--Space-x2);
|
||||
}
|
||||
|
||||
@media screen and (min-width: 768px) {
|
||||
.dialog {
|
||||
gap: var(--Space-x3);
|
||||
}
|
||||
|
||||
.content {
|
||||
gap: var(--Space-x3);
|
||||
grid-template-columns: 1fr 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
border-radius: var(--Corner-radius-rounded);
|
||||
color: var(--Text-Interactive-Default);
|
||||
display: flex;
|
||||
height: 48px;
|
||||
justify-content: center;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
.button {
|
||||
align-items: center;
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
gap: var(--Space-x1);
|
||||
padding: var(--Space-x1) 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.text {
|
||||
color: var(--Text-Interactive-Default);
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
"use client"
|
||||
import { Button as ButtonRAC } from "react-aria-components"
|
||||
|
||||
import {
|
||||
MaterialIcon,
|
||||
type MaterialIconProps,
|
||||
} from "@scandic-hotels/design-system/Icons/MaterialIcon"
|
||||
import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||
|
||||
import styles from "./button.module.css"
|
||||
|
||||
interface ButtonProps extends React.PropsWithChildren {
|
||||
icon: MaterialIconProps["icon"]
|
||||
isDisabled?: boolean
|
||||
}
|
||||
|
||||
export default function Button({
|
||||
children,
|
||||
icon,
|
||||
isDisabled = false,
|
||||
}: ButtonProps) {
|
||||
return (
|
||||
<ButtonRAC className={styles.button} isDisabled={isDisabled}>
|
||||
<MaterialIcon color="Icon/Interactive/Default" icon={icon} />
|
||||
<Typography variant="Body/Paragraph/mdBold">
|
||||
<span className={styles.text}>{children}</span>
|
||||
</Typography>
|
||||
</ButtonRAC>
|
||||
)
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
.content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--Spacing-x3);
|
||||
max-height: 70vh;
|
||||
overflow-y: auto;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 768px) {
|
||||
.content {
|
||||
width: 640px;
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
import styles from "./body.module.css"
|
||||
|
||||
export default function Body({ children }: React.PropsWithChildren) {
|
||||
return <div className={styles.content}>{children}</div>
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
.footer {
|
||||
border-top: 1px solid var(--Base-Border-Subtle);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding-top: var(--Spacing-x3);
|
||||
width: 100%;
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
import Button from "@/components/TempDesignSystem/Button"
|
||||
|
||||
import styles from "./footer.module.css"
|
||||
|
||||
import type { ButtonHTMLAttributes, PropsWithChildren } from "react"
|
||||
import type { ButtonProps as ReactAriaButtonProps } from "react-aria-components"
|
||||
|
||||
import type { ButtonProps as _ButtonProps } from "@/components/TempDesignSystem/Button/button"
|
||||
|
||||
export default function Footer({ children }: PropsWithChildren) {
|
||||
return <footer className={styles.footer}>{children}</footer>
|
||||
}
|
||||
|
||||
interface ButtonProps extends PropsWithChildren {
|
||||
intent?: _ButtonProps["intent"]
|
||||
onClick?: ReactAriaButtonProps["onPress"]
|
||||
type?: ButtonHTMLAttributes<HTMLButtonElement>["type"]
|
||||
}
|
||||
|
||||
interface PrimaryButtonProps extends ButtonProps {
|
||||
disabled?: boolean
|
||||
form?: string
|
||||
}
|
||||
|
||||
Footer.Primary = function PrimaryButton({
|
||||
children,
|
||||
disabled = false,
|
||||
form,
|
||||
intent = "primary",
|
||||
onClick,
|
||||
type = "button",
|
||||
}: PrimaryButtonProps) {
|
||||
return (
|
||||
<Button
|
||||
disabled={disabled}
|
||||
form={form}
|
||||
intent={intent}
|
||||
onClick={onClick}
|
||||
theme="base"
|
||||
type={type}
|
||||
>
|
||||
{children}
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
|
||||
Footer.Secondary = function SecondaryButton({
|
||||
children,
|
||||
intent = "text",
|
||||
onClick,
|
||||
type = "button",
|
||||
}: ButtonProps) {
|
||||
return (
|
||||
<Button
|
||||
color="burgundy"
|
||||
intent={intent}
|
||||
onClick={onClick}
|
||||
theme="base"
|
||||
type={type}
|
||||
>
|
||||
{children}
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
.header {
|
||||
display: grid;
|
||||
gap: var(--Space-x05) var(--Space-x2);
|
||||
grid-template-columns: 1fr auto;
|
||||
}
|
||||
|
||||
.close {
|
||||
align-items: center;
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 0;
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
import { Button as ButtonRAC } from "react-aria-components"
|
||||
|
||||
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
|
||||
|
||||
import Subtitle from "@/components/TempDesignSystem/Text/Subtitle"
|
||||
|
||||
import styles from "./header.module.css"
|
||||
|
||||
interface HeaderProps extends React.PropsWithChildren {
|
||||
handleClose: () => void
|
||||
title: string
|
||||
}
|
||||
|
||||
export default function Header({ children, handleClose, title }: HeaderProps) {
|
||||
return (
|
||||
<header className={styles.header}>
|
||||
<Subtitle>{title}</Subtitle>
|
||||
<ButtonRAC className={styles.close} onPress={handleClose}>
|
||||
<MaterialIcon icon="close" color="Icon/Interactive/Placeholder" />
|
||||
</ButtonRAC>
|
||||
{children}
|
||||
</header>
|
||||
)
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import Body from "./Body"
|
||||
import Footer from "./Footer"
|
||||
import Header from "./Header"
|
||||
|
||||
import styles from "./modalContent.module.css"
|
||||
|
||||
import type { PropsWithChildren } from "react"
|
||||
|
||||
export default function ModalContent({ children }: PropsWithChildren) {
|
||||
return <div className={styles.container}>{children}</div>
|
||||
}
|
||||
|
||||
ModalContent.Body = Body
|
||||
ModalContent.Footer = Footer
|
||||
ModalContent.Header = Header
|
||||
@@ -1,4 +0,0 @@
|
||||
.container {
|
||||
display: grid;
|
||||
gap: var(--Space-x3);
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
import { Modal as ModalRAC, ModalOverlay } from "react-aria-components"
|
||||
|
||||
import Button from "./Button"
|
||||
import ModalContent from "./ModalContent"
|
||||
|
||||
import styles from "./modal.module.css"
|
||||
|
||||
export default function Modal({ children }: React.PropsWithChildren) {
|
||||
return (
|
||||
<ModalOverlay className={styles.overlay} isDismissable>
|
||||
<ModalRAC className={styles.modal}>{children}</ModalRAC>
|
||||
</ModalOverlay>
|
||||
)
|
||||
}
|
||||
|
||||
Modal.Button = Button
|
||||
Modal.Content = ModalContent
|
||||
@@ -1,70 +0,0 @@
|
||||
.overlay {
|
||||
background: rgba(0, 0, 0, 0.4);
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
position: fixed;
|
||||
right: 0;
|
||||
top: 0;
|
||||
width: 100dvw;
|
||||
z-index: var(--default-modal-overlay-z-index);
|
||||
|
||||
&[data-entering] {
|
||||
animation: overlay-fade 200ms;
|
||||
}
|
||||
|
||||
&[data-exiting] {
|
||||
animation: overlay-fade 150ms reverse ease-in;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes overlay-fade {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.modal {
|
||||
background: var(--UI-Input-Controls-Surface-Normal);
|
||||
border-top-left-radius: var(--Corner-radius-Large);
|
||||
border-top-right-radius: var(--Corner-radius-Large);
|
||||
max-height: 95dvh;
|
||||
overflow-y: auto;
|
||||
padding: var(--Space-x3);
|
||||
position: absolute;
|
||||
z-index: var(--default-modal-z-index);
|
||||
|
||||
&[data-entering] {
|
||||
animation: modal-anim 200ms;
|
||||
}
|
||||
|
||||
&[data-exiting] {
|
||||
animation: modal-anim 150ms reverse ease-in;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes modal-anim {
|
||||
from {
|
||||
transform: translateY(100%);
|
||||
}
|
||||
|
||||
to {
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 768px) {
|
||||
.overlay {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.modal {
|
||||
border-radius: var(--Corner-radius-Large);
|
||||
width: min(690px, 100dvw);
|
||||
}
|
||||
}
|
||||
@@ -33,8 +33,8 @@ export default function PriceContainer({
|
||||
{totalChildren > 0 ? `, ${childrenText}` : ""}
|
||||
</Caption>
|
||||
</div>
|
||||
<div className={styles.price}>
|
||||
<Subtitle color="burgundy" type="one">
|
||||
<div className={styles.wrapper}>
|
||||
<Subtitle className={styles.price} color="burgundy" type="one">
|
||||
{price}
|
||||
</Subtitle>
|
||||
</div>
|
||||
|
||||
@@ -15,8 +15,12 @@
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.price {
|
||||
.wrapper {
|
||||
padding-left: var(--Spacing-x2);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.price {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user