feat: add mobile summary

This commit is contained in:
Christel Westerberg
2024-11-07 11:26:49 +01:00
parent c8ce61c855
commit 66b2dc0c78
19 changed files with 345 additions and 116 deletions

View File

@@ -45,7 +45,7 @@
.iconWrapper {
position: relative;
top: var(--Spacing-x1);
z-index: 2;
z-index: 1;
}
.circle {

View File

@@ -38,7 +38,7 @@
.iconWrapper {
position: relative;
top: var(--Spacing-x1);
z-index: 2;
z-index: 1;
}
.circle {

View File

@@ -0,0 +1,49 @@
.wrapper {
display: grid;
grid-template-rows: 0fr 7.5em;
transition: 0.5s ease-in-out;
border-top: 1px solid var(--Base-Border-Subtle);
background: var(--Base-Surface-Primary-light-Normal);
align-content: end;
}
.bottomSheet {
display: grid;
grid-template-columns: 1fr auto;
padding: var(--Spacing-x2) var(--Spacing-x3) var(--Spacing-x5)
var(--Spacing-x3);
justify-content: space-between;
width: auto;
align-items: flex-start;
transition: 0.5s ease-in-out;
}
.priceDetails {
display: block;
border: none;
background: none;
text-align: start;
opacity: 1;
transition:
opacity 0.5s ease-in-out,
padding 0.5s ease-in-out;
}
.wrapper[data-open="true"] {
grid-template-rows: 1fr 7.5em;
}
.wrapper[data-open="true"] .bottomSheet {
grid-template-columns: 0fr 1fr;
}
.wrapper[data-open="true"] .priceDetails {
opacity: 0;
padding: 0;
}
.content,
.priceDetails {
overflow: hidden;
}

View File

@@ -0,0 +1,55 @@
"use client"
import { PropsWithChildren, useState } from "react"
import { useIntl } from "react-intl"
import { useEnterDetailsStore } from "@/stores/enter-details"
import Button from "@/components/TempDesignSystem/Button"
import Caption from "@/components/TempDesignSystem/Text/Caption"
import Subtitle from "@/components/TempDesignSystem/Text/Subtitle"
import { formatNumber } from "@/utils/format"
import styles from "./bottomSheet.module.css"
export function SummaryBottomSheet({ children }: PropsWithChildren) {
const intl = useIntl()
const { isSummaryOpen, toggleSummaryOpen, totalPrice } = useEnterDetailsStore(
(state) => ({
isSummaryOpen: state.isSummaryOpen,
toggleSummaryOpen: state.toggleSummaryOpen,
totalPrice: state.totalPrice,
})
)
return (
<div className={styles.wrapper} data-open={isSummaryOpen}>
<div className={styles.content}>{children}</div>
<div className={styles.bottomSheet}>
<button
data-open={isSummaryOpen}
onClick={toggleSummaryOpen}
className={styles.priceDetails}
>
<Caption>{intl.formatMessage({ id: "Total price" })}:</Caption>
<Subtitle>
{intl.formatMessage(
{ id: "{amount} {currency}" },
{
amount: formatNumber(totalPrice.local.price),
currency: totalPrice.local.currency,
}
)}
</Subtitle>
<Caption color="baseTextHighContrast" type="underline">
{intl.formatMessage({ id: "See details" })}
</Caption>
</button>
<Button intent="primary" size="large" type="submit">
{intl.formatMessage({ id: "Complete booking" })}
</Button>
</div>
</div>
)
}

View File

@@ -6,7 +6,7 @@ import { useIntl } from "react-intl"
import { dt } from "@/lib/dt"
import { useEnterDetailsStore } from "@/stores/enter-details"
import { ArrowRightIcon } from "@/components/Icons"
import { ArrowRightIcon, CloseIcon } from "@/components/Icons"
import Divider from "@/components/TempDesignSystem/Divider"
import Link from "@/components/TempDesignSystem/Link"
import Body from "@/components/TempDesignSystem/Text/Body"
@@ -36,20 +36,25 @@ export default function Summary({
const [chosenBreakfast, setChosenBreakfast] = useState<
BreakfastPackage | BreakfastPackageEnum.NO_BREAKFAST
>()
const [totalPrice, setTotalPrice] = useState({
local: parsePrice(room.localPrice.price),
euro: parsePrice(room.euroPrice.price),
})
const intl = useIntl()
const lang = useLang()
const { fromDate, toDate, bedType, breakfast } = useEnterDetailsStore(
(state) => ({
fromDate: state.roomData.fromDate,
toDate: state.roomData.toDate,
bedType: state.userData.bedType,
breakfast: state.userData.breakfast,
})
)
const {
fromDate,
toDate,
bedType,
breakfast,
setTotalPrice,
totalPrice,
toggleSummaryOpen,
} = useEnterDetailsStore((state) => ({
fromDate: state.roomData.fromDate,
toDate: state.roomData.toDate,
bedType: state.userData.bedType,
breakfast: state.userData.breakfast,
toggleSummaryOpen: state.toggleSummaryOpen,
setTotalPrice: state.setTotalPrice,
totalPrice: state.totalPrice,
}))
const diff = dt(toDate).diff(fromDate, "days")
@@ -70,21 +75,48 @@ export default function Summary({
setChosenBreakfast(breakfast)
if (breakfast === BreakfastPackageEnum.NO_BREAKFAST) {
setTotalPrice({
local: parsePrice(room.localPrice.price),
euro: parsePrice(room.euroPrice.price),
local: {
price: parsePrice(room.localPrice.price),
currency: room.localPrice.currency!,
},
euro: {
price: parsePrice(room.euroPrice.price),
currency: room.euroPrice.currency!,
},
})
} else {
setTotalPrice({
local:
parsePrice(room.localPrice.price) +
parsePrice(breakfast.localPrice.totalPrice),
euro:
parsePrice(room.euroPrice.price) +
parsePrice(breakfast.requestedPrice.totalPrice),
local: {
price:
parsePrice(room.localPrice.price) +
parsePrice(breakfast.localPrice.totalPrice),
currency: room.localPrice.currency!,
},
euro: {
price:
parsePrice(room.euroPrice.price) +
parsePrice(breakfast.requestedPrice.totalPrice),
currency: room.euroPrice.currency!,
},
})
}
}
}, [bedType, breakfast, room.localPrice, room.euroPrice])
}, [bedType, breakfast, room.localPrice, room.euroPrice, setTotalPrice])
useEffect(() => {
setTotalPrice({
local: {
price: parsePrice(room.localPrice.price),
currency: room.localPrice.currency!,
},
euro: {
price: parsePrice(room.euroPrice.price),
currency: room.euroPrice.currency!,
},
})
}, [room.localPrice, room.euroPrice, setTotalPrice])
const showToggleButton = true
return (
<section className={styles.summary}>
@@ -95,6 +127,7 @@ export default function Summary({
<ArrowRightIcon color="peach80" height={15} width={15} />
{dt(toDate).locale(lang).format("ddd, D MMM")} ({nights})
</Body>
{showToggleButton ? <CloseIcon onClick={toggleSummaryOpen} /> : null}
</header>
<Divider color="primaryLightSubtle" />
<div className={styles.addOns}>
@@ -203,8 +236,8 @@ export default function Summary({
{intl.formatMessage(
{ id: "{amount} {currency}" },
{
amount: intl.formatNumber(totalPrice.local),
currency: room.localPrice.currency,
amount: intl.formatNumber(totalPrice.local.price),
currency: totalPrice.local.currency,
}
)}
</Body>
@@ -213,14 +246,14 @@ export default function Summary({
{intl.formatMessage(
{ id: "{amount} {currency}" },
{
amount: intl.formatNumber(totalPrice.euro),
currency: room.euroPrice.currency,
amount: intl.formatNumber(totalPrice.euro.price),
currency: totalPrice.euro.currency,
}
)}
</Caption>
</div>
</div>
<Divider color="primaryLightSubtle" />
<Divider className={styles.bottomDivider} color="primaryLightSubtle" />
</div>
</section>
)

View File

@@ -38,3 +38,13 @@
flex-direction: column;
gap: var(--Spacing-x2);
}
.bottomDivider {
display: none;
}
@media screen and (min-width: 1367px) {
.bottomDivider {
display: block;
}
}