feat: add summary card
This commit is contained in:
@@ -7,7 +7,6 @@ import { dt } from "@/lib/dt"
|
||||
import DatePicker from "@/components/DatePicker"
|
||||
import { SearchIcon } from "@/components/Icons"
|
||||
import Button from "@/components/TempDesignSystem/Button"
|
||||
import Body from "@/components/TempDesignSystem/Text/Body"
|
||||
import Caption from "@/components/TempDesignSystem/Text/Caption"
|
||||
|
||||
import Input from "./Input"
|
||||
|
||||
@@ -2,8 +2,10 @@
|
||||
align-items: center;
|
||||
display: grid;
|
||||
margin: 0 auto;
|
||||
max-width: var(--max-width-navigation);
|
||||
width: 100%;
|
||||
width: min(
|
||||
calc(100dvw - (var(--Spacing-x2) * 2)),
|
||||
var(--max-width-navigation)
|
||||
);
|
||||
}
|
||||
|
||||
.form {
|
||||
@@ -32,7 +34,8 @@
|
||||
padding: var(--Spacing-x-one-and-half) var(--Spacing-x2)
|
||||
var(--Spacing-x-one-and-half) var(--Spacing-x1);
|
||||
}
|
||||
|
||||
.full {
|
||||
padding: var(--Spacing-x1) var(--Spacing-x5);
|
||||
padding: var(--Spacing-x1) 0;
|
||||
}
|
||||
}
|
||||
|
||||
165
components/HotelReservation/EnterDetails/Summary/index.tsx
Normal file
165
components/HotelReservation/EnterDetails/Summary/index.tsx
Normal file
@@ -0,0 +1,165 @@
|
||||
import { dt } from "@/lib/dt"
|
||||
|
||||
import { ArrowRightIcon, ChevronRightSmallIcon } from "@/components/Icons"
|
||||
import Divider from "@/components/TempDesignSystem/Divider"
|
||||
import Link from "@/components/TempDesignSystem/Link"
|
||||
import Body from "@/components/TempDesignSystem/Text/Body"
|
||||
import Caption from "@/components/TempDesignSystem/Text/Caption"
|
||||
import { getIntl } from "@/i18n"
|
||||
import { getLang } from "@/i18n/serverContext"
|
||||
|
||||
import styles from "./summary.module.css"
|
||||
|
||||
// TEMP
|
||||
const rooms = [
|
||||
{
|
||||
adults: 1,
|
||||
type: "Cozy cabin",
|
||||
},
|
||||
]
|
||||
|
||||
export default async function Summary() {
|
||||
const intl = await getIntl()
|
||||
const lang = getLang()
|
||||
|
||||
const fromDate = dt().locale(lang).format("ddd, D MMM")
|
||||
const toDate = dt().add(1, "day").locale(lang).format("ddd, D MMM")
|
||||
const diff = dt(toDate).diff(fromDate, "days")
|
||||
|
||||
const totalAdults = rooms.reduce((total, room) => total + room.adults, 0)
|
||||
|
||||
const adults = intl.formatMessage(
|
||||
{ id: "booking.adults" },
|
||||
{ totalAdults: totalAdults }
|
||||
)
|
||||
const nights = intl.formatMessage(
|
||||
{ id: "booking.nights" },
|
||||
{ totalNights: diff }
|
||||
)
|
||||
|
||||
const addOns = [
|
||||
{
|
||||
price: intl.formatMessage({ id: "Included" }),
|
||||
title: intl.formatMessage({ id: "King bed" }),
|
||||
},
|
||||
{
|
||||
price: intl.formatMessage({ id: "Included" }),
|
||||
title: intl.formatMessage({ id: "Breakfast buffet" }),
|
||||
},
|
||||
]
|
||||
|
||||
const mappedRooms = Array.from(
|
||||
rooms
|
||||
.reduce((acc, room) => {
|
||||
const currentRoom = acc.get(room.type)
|
||||
acc.set(room.type, {
|
||||
total: currentRoom ? currentRoom.total + 1 : 1,
|
||||
type: room.type,
|
||||
})
|
||||
return acc
|
||||
}, new Map())
|
||||
.values()
|
||||
)
|
||||
|
||||
return (
|
||||
<section className={styles.summary}>
|
||||
<header>
|
||||
<Body textTransform="bold">
|
||||
{mappedRooms.map(
|
||||
(room, idx) =>
|
||||
`${room.total} x ${room.type}${mappedRooms.length > 1 && idx + 1 !== mappedRooms.length ? ", " : ""}`
|
||||
)}
|
||||
</Body>
|
||||
<Body className={styles.date} color="textMediumContrast">
|
||||
{fromDate}
|
||||
<ArrowRightIcon color="uiTextMediumContrast" height={15} width={15} />
|
||||
{toDate}
|
||||
</Body>
|
||||
<Link
|
||||
className={styles.link}
|
||||
color="baseButtonTextOnFillNormal"
|
||||
href="#"
|
||||
variant="icon"
|
||||
>
|
||||
{intl.formatMessage({ id: "See room details" })}
|
||||
<ChevronRightSmallIcon
|
||||
color="baseButtonTextOnFillNormal"
|
||||
height={20}
|
||||
width={20}
|
||||
/>
|
||||
</Link>
|
||||
</header>
|
||||
<Divider color="primaryLightSubtle" />
|
||||
<div className={styles.addOns}>
|
||||
<div className={styles.entry}>
|
||||
<Caption color="uiTextMediumContrast">
|
||||
{`${nights}, ${adults}`}
|
||||
</Caption>
|
||||
<Caption color="uiTextHighContrast">
|
||||
{intl.formatMessage(
|
||||
{ id: "{amount} {currency}" },
|
||||
{ amount: "4536", currency: "SEK" }
|
||||
)}
|
||||
</Caption>
|
||||
</div>
|
||||
{addOns.map((addOn) => (
|
||||
<div className={styles.entry} key={addOn.title}>
|
||||
<Caption color="uiTextMediumContrast">{addOn.title}</Caption>
|
||||
<Caption color="uiTextHighContrast">{addOn.price}</Caption>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<Divider color="primaryLightSubtle" />
|
||||
<div className={styles.total}>
|
||||
<div>
|
||||
<div className={styles.entry}>
|
||||
<Body textTransform="bold">
|
||||
{intl.formatMessage({ id: "Total incl VAT" })}
|
||||
</Body>
|
||||
<Body textTransform="bold">
|
||||
{intl.formatMessage(
|
||||
{ id: "{amount} {currency}" },
|
||||
{ amount: "4686", currency: "SEK" }
|
||||
)}
|
||||
</Body>
|
||||
</div>
|
||||
<div className={styles.entry}>
|
||||
<Caption color="uiTextMediumContrast">
|
||||
{intl.formatMessage({ id: "Approx." })}
|
||||
</Caption>
|
||||
<Caption color="uiTextMediumContrast">
|
||||
{intl.formatMessage(
|
||||
{ id: "{amount} {currency}" },
|
||||
{ amount: "455", currency: "EUR" }
|
||||
)}
|
||||
</Caption>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className={styles.entry}>
|
||||
<Body color="red" textTransform="bold">
|
||||
{intl.formatMessage({ id: "Member price" })}
|
||||
</Body>
|
||||
<Body color="red" textTransform="bold">
|
||||
{intl.formatMessage(
|
||||
{ id: "{amount} {currency}" },
|
||||
{ amount: "4219", currency: "SEK" }
|
||||
)}
|
||||
</Body>
|
||||
</div>
|
||||
<div className={styles.entry}>
|
||||
<Caption color="uiTextMediumContrast">
|
||||
{intl.formatMessage({ id: "Approx." })}
|
||||
</Caption>
|
||||
<Caption color="uiTextMediumContrast">
|
||||
{intl.formatMessage(
|
||||
{ id: "{amount} {currency}" },
|
||||
{ amount: "412", currency: "EUR" }
|
||||
)}
|
||||
</Caption>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
.summary {
|
||||
background-color: var(--Main-Grey-White);
|
||||
border: 1px solid var(--Primary-Light-On-Surface-Divider-subtle);
|
||||
border-radius: var(--Corner-radius-Large);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--Spacing-x2);
|
||||
padding: var(--Spacing-x2);
|
||||
}
|
||||
|
||||
.date {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
gap: var(--Spacing-x1);
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.link {
|
||||
margin-top: var(--Spacing-x1);
|
||||
}
|
||||
|
||||
.addOns {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--Spacing-x1);
|
||||
}
|
||||
|
||||
.entry {
|
||||
display: flex;
|
||||
gap: var(--Spacing-x-half);
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.total {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--Spacing-x2);
|
||||
}
|
||||
@@ -36,15 +36,18 @@
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.hotelSelectionHeader {
|
||||
padding: var(--Spacing-x4) var(--Spacing-x5);
|
||||
padding: var(--Spacing-x4) 0;
|
||||
}
|
||||
|
||||
.hotelSelectionHeaderWrapper {
|
||||
flex-direction: row;
|
||||
gap: var(--Spacing-x6);
|
||||
max-width: var(--max-width-navigation);
|
||||
margin: 0 auto;
|
||||
width: 100%;
|
||||
/* simulates padding on viewport smaller than --max-width-navigation */
|
||||
width: min(
|
||||
calc(100dvw - (var(--Spacing-x2) * 2)),
|
||||
var(--max-width-navigation)
|
||||
);
|
||||
}
|
||||
|
||||
.titleContainer > h1 {
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
"use client"
|
||||
import styles from "./summary.module.css"
|
||||
|
||||
export default function Summary() {
|
||||
return <div className={styles.wrapper}>Summary TBI</div>
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
.wrapper {
|
||||
}
|
||||
@@ -71,3 +71,8 @@
|
||||
.baseButtonTertiaryOnFillNormal * {
|
||||
fill: var(--Base-Button-Tertiary-On-Fill-Normal);
|
||||
}
|
||||
|
||||
.baseButtonTextOnFillNormal,
|
||||
.baseButtonTextOnFillNormal * {
|
||||
fill: var(--Base-Button-Text-On-Fill-Normal);
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ const config = {
|
||||
variants: {
|
||||
color: {
|
||||
baseButtonTertiaryOnFillNormal: styles.baseButtonTertiaryOnFillNormal,
|
||||
baseButtonTextOnFillNormal: styles.baseButtonTextOnFillNormal,
|
||||
baseIconLowContrast: styles.baseIconLowContrast,
|
||||
black: styles.black,
|
||||
blue: styles.blue,
|
||||
|
||||
@@ -107,6 +107,10 @@
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.baseButtonTextOnFillNormal {
|
||||
color: var(--Base-Button-Text-On-Fill-Normal);
|
||||
}
|
||||
|
||||
.black {
|
||||
color: #000;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ export const linkVariants = cva(styles.link, {
|
||||
true: styles.active,
|
||||
},
|
||||
color: {
|
||||
baseButtonTextOnFillNormal: styles.baseButtonTextOnFillNormal,
|
||||
black: styles.black,
|
||||
burgundy: styles.burgundy,
|
||||
none: "",
|
||||
|
||||
Reference in New Issue
Block a user