feat: SW-276 SW-565 Updated UI

This commit is contained in:
Hrishikesh Vaipurkar
2024-10-09 12:21:13 +02:00
parent 9dbd10afdd
commit ad42440817
10 changed files with 268 additions and 91 deletions

View File

@@ -1,9 +1,15 @@
.container { .container {
display: grid; display: flex;
grid-template-columns: repeat(4, auto); justify-content: space-between;
align-items: center; align-items: center;
} }
.counterContainer {
.textCenter { display: flex;
text-align: center; justify-content: flex-end;
align-items: center;
gap: 20px;
}
.counterBtn {
width: 40px;
height: 40px;
} }

View File

@@ -5,7 +5,9 @@ import { useIntl } from "react-intl"
import { guestsRoomsStore } from "@/stores/guests-rooms" import { guestsRoomsStore } from "@/stores/guests-rooms"
import { MinusIcon, PlusIcon } from "@/components/Icons"
import Button from "@/components/TempDesignSystem/Button" import Button from "@/components/TempDesignSystem/Button"
import Body from "@/components/TempDesignSystem/Text/Body"
import Caption from "@/components/TempDesignSystem/Text/Caption" import Caption from "@/components/TempDesignSystem/Text/Caption"
import styles from "./adult-selector.module.css" import styles from "./adult-selector.module.css"
@@ -50,26 +52,42 @@ export default function AdultSelector({ roomIndex = 0 }: AdultSelectorProps) {
return ( return (
<section className={styles.container}> <section className={styles.container}>
<Caption>{adultsLabel}</Caption> <Caption color="uiTextHighContrast" textTransform="bold">
<Button {adultsLabel}
onClick={() => { </Caption>
decreaseAdultsCount(roomIndex) <div className={styles.counterContainer}>
}} <Button
intent="text" className={styles.counterBtn}
size="small" intent="elevated"
> onClick={() => {
- decreaseAdultsCount(roomIndex)
</Button> }}
<span className={styles.textCenter}>{adults}</span> size="small"
<Button theme="base"
onClick={() => { variant="icon"
increaseAdultsCount(roomIndex) wrapping={true}
}} disabled={adults == 1}
intent="text" >
size="small" <MinusIcon color="burgundy" />
> </Button>
+ <Body color="textHighContrast" textAlign="center">
</Button> {adults}
</Body>
<Button
className={styles.counterBtn}
onClick={() => {
increaseAdultsCount(roomIndex)
}}
intent="elevated"
variant="icon"
theme="base"
wrapping={true}
size="small"
disabled={adults == 6}
>
<PlusIcon color="burgundy" />
</Button>
</div>
</section> </section>
) )
} }

View File

@@ -1,9 +1,15 @@
"use client"
import { useFormContext } from "react-hook-form" import { useFormContext } from "react-hook-form"
import { useIntl } from "react-intl" import { useIntl } from "react-intl"
import { guestsRoomsStore } from "@/stores/guests-rooms" import { guestsRoomsStore } from "@/stores/guests-rooms"
import { ErrorCircleIcon } from "@/components/Icons"
import Select from "@/components/TempDesignSystem/Select" import Select from "@/components/TempDesignSystem/Select"
import Caption from "@/components/TempDesignSystem/Text/Caption"
import styles from "./child-selector.module.css"
import { BedTypeEnum } from "@/types/components/bookingWidget/enums" import { BedTypeEnum } from "@/types/components/bookingWidget/enums"
import { import {
@@ -96,36 +102,43 @@ export default function ChildInfoSelector({
return ( return (
<> <>
<div> <div key={index} className={styles.childInfoContainer}>
<Select <div>
required={true}
items={ageList}
label={ageLabel}
aria-label={ageLabel}
value={child.age}
onSelect={(key) => {
updateSelectedAge(parseInt(key.toString()))
}}
name={`rooms.${roomIndex}.children.${index}.age`}
placeholder={ageLabel}
/>
{isValidated && child.age < 0 ? <span>{ageReqdErrMsg}</span> : null}
</div>
<div>
{child.age !== -1 ? (
<Select <Select
items={getAvailableBeds(child.age)} required={true}
label={bedLabel} items={ageList}
aria-label={bedLabel} label={ageLabel}
value={child.bed} aria-label={ageLabel}
value={child.age}
onSelect={(key) => { onSelect={(key) => {
updateSelectedBed(parseInt(key.toString())) updateSelectedAge(parseInt(key.toString()))
}} }}
name={`rooms.${roomIndex}.children.${index}.age`} name={`rooms.${roomIndex}.children.${index}.age`}
placeholder={bedLabel} placeholder={ageLabel}
/> />
) : null} </div>
<div>
{child.age !== -1 ? (
<Select
items={getAvailableBeds(child.age)}
label={bedLabel}
aria-label={bedLabel}
value={child.bed}
onSelect={(key) => {
updateSelectedBed(parseInt(key.toString()))
}}
name={`rooms.${roomIndex}.children.${index}.age`}
placeholder={bedLabel}
/>
) : null}
</div>
</div> </div>
{isValidated && child.age < 0 ? (
<Caption color="red" className={styles.error}>
<ErrorCircleIcon color="red" />
{intl.formatMessage({ id: "Child age is required" })}
</Caption>
) : null}
</> </>
) )
} }

View File

@@ -1,8 +1,21 @@
.container { .container {
display: grid; display: flex;
grid-template-columns: repeat(4, auto); justify-content: space-between;
align-items: center; align-items: center;
} }
.captionBold {
font-weight: 600;
}
.counterContainer {
display: flex;
justify-content: flex-end;
align-items: center;
gap: 20px;
}
.counterBtn {
width: 40px;
height: 40px;
}
.childInfoContainer { .childInfoContainer {
display: grid; display: grid;
@@ -10,6 +23,8 @@
grid-template-columns: 1fr 2fr; grid-template-columns: 1fr 2fr;
} }
.textCenter { .error {
text-align: center; display: flex;
align-items: center;
gap: var(--Spacing-x1);
} }

View File

@@ -1,9 +1,13 @@
"use client"
import { useFormContext } from "react-hook-form" import { useFormContext } from "react-hook-form"
import { useIntl } from "react-intl" import { useIntl } from "react-intl"
import { guestsRoomsStore } from "@/stores/guests-rooms" import { guestsRoomsStore } from "@/stores/guests-rooms"
import { MinusIcon, PlusIcon } from "@/components/Icons"
import Button from "@/components/TempDesignSystem/Button" import Button from "@/components/TempDesignSystem/Button"
import Body from "@/components/TempDesignSystem/Text/Body"
import Caption from "@/components/TempDesignSystem/Text/Caption" import Caption from "@/components/TempDesignSystem/Text/Caption"
import ChildInfoSelector from "./ChildInfoSelector" import ChildInfoSelector from "./ChildInfoSelector"
@@ -40,31 +44,50 @@ export default function ChildSelector({ roomIndex = 0 }: ChildSelectorProps) {
return ( return (
<> <>
<section className={styles.container}> <section className={styles.container}>
<Caption>{childrenLabel}</Caption> <Caption color="uiTextHighContrast" textTransform="bold">
<Button {childrenLabel}
intent="text" </Caption>
size="small" <div className={styles.counterContainer}>
onClick={() => decreaseChildrenCount(roomIndex)} <Button
> className={styles.counterBtn}
- intent="elevated"
</Button> onClick={() => {
<span className={styles.textCenter}>{children.length}</span> decreaseChildrenCount(roomIndex)
<Button }}
intent="text" size="small"
size="small" theme="base"
onClick={() => increaseChildrenCount(roomIndex)} variant="icon"
> wrapping={true}
+ disabled={children.length == 0}
</Button> >
<MinusIcon color="burgundy" />
</Button>
<Body color="textHighContrast" textAlign="center">
{children.length}
</Body>
<Button
className={styles.counterBtn}
onClick={() => {
increaseChildrenCount(roomIndex)
}}
intent="elevated"
variant="icon"
theme="base"
wrapping={true}
size="small"
disabled={children.length == 5}
>
<PlusIcon color="burgundy" />
</Button>
</div>
</section> </section>
{children.map((child, index) => ( {children.map((child, index) => (
<div key={index} className={styles.childInfoContainer}> <ChildInfoSelector
<ChildInfoSelector roomIndex={roomIndex}
roomIndex={roomIndex} index={index}
index={index} child={child}
child={child} key={index}
/> />
</div>
))} ))}
</> </>
) )

View File

@@ -4,6 +4,7 @@ import { useIntl } from "react-intl"
import { guestsRoomsStore } from "@/stores/guests-rooms" import { guestsRoomsStore } from "@/stores/guests-rooms"
import { guestRoomsSchema } from "../Forms/BookingWidget/schema" import { guestRoomsSchema } from "../Forms/BookingWidget/schema"
import { CloseLarge } from "../Icons"
import Button from "../TempDesignSystem/Button" import Button from "../TempDesignSystem/Button"
import Divider from "../TempDesignSystem/Divider" import Divider from "../TempDesignSystem/Divider"
import Subtitle from "../TempDesignSystem/Text/Subtitle" import Subtitle from "../TempDesignSystem/Text/Subtitle"
@@ -30,10 +31,15 @@ export default function GuestsRoomsPicker({
return ( return (
<> <>
<header className={styles.header}>
<button type="button" className={styles.close} onClick={closePicker}>
<CloseLarge />
</button>
</header>
{guestsData.map((room, index) => ( {guestsData.map((room, index) => (
<section className={styles.roomContainer} key={index}> <section className={styles.roomContainer} key={index}>
<section className={styles.roomDetailsContainer}> <section className={styles.roomDetailsContainer}>
<Subtitle> <Subtitle type="two" className={styles.roomHeading}>
{roomLabel} {index + 1} {roomLabel} {index + 1}
</Subtitle> </Subtitle>
<AdultSelector roomIndex={index} /> <AdultSelector roomIndex={index} />
@@ -45,7 +51,7 @@ export default function GuestsRoomsPicker({
Remove Room Remove Room
</Button> </Button>
) : null} */} ) : null} */}
<Divider /> <Divider color="primaryLightSubtle" />
</section> </section>
))} ))}
<footer className={styles.footer}> <footer className={styles.footer}>
@@ -55,7 +61,24 @@ export default function GuestsRoomsPicker({
Add Room Add Room
</Button> </Button>
) : null} */} ) : null} */}
<Button onClick={closePicker} disabled={isInValid}> <Button
onClick={closePicker}
disabled={isInValid}
className={styles.hideOnMobile}
intent="tertiary"
theme="base"
size="small"
>
{doneLabel}
</Button>
<Button
onClick={closePicker}
disabled={isInValid}
className={styles.hideOnDesktop}
intent="tertiary"
theme="base"
size="large"
>
{doneLabel} {doneLabel}
</Button> </Button>
</footer> </footer>

View File

@@ -1,14 +1,13 @@
.container { .container {
overflow: hidden; overflow: hidden;
position: relative; position: relative;
z-index: 10;
&[data-isopen="true"] { &[data-isopen="true"] {
overflow: visible; overflow: visible;
} }
} }
.roomContainer { .roomContainer {
display: grid; display: grid;
gap: var(--Spacing-x1); gap: var(--Spacing-x2);
} }
.roomDetailsContainer { .roomDetailsContainer {
display: grid; display: grid;
@@ -17,14 +16,9 @@
} }
.hideWrapper { .hideWrapper {
background-color: var(--Main-Grey-White); background-color: var(--Main-Grey-White);
border-radius: var(--Corner-radius-Medium); }
box-shadow: 0px 16px 24px 0px rgba(0, 0, 0, 0.08); .roomHeading {
padding: var(--Spacing-x-one-and-half); margin-bottom: var(--Spacing-x1);
position: absolute;
/** BookingWidget padding + border-width */
top: calc(100% + var(--Spacing-x2) + 1px);
width: 360px;
max-width: 100vw; /* for small screens having view port width of 320px */
} }
.btn { .btn {
background: none; background: none;
@@ -41,5 +35,83 @@
display: grid; display: grid;
gap: var(--Spacing-x1); gap: var(--Spacing-x1);
grid-template-columns: auto; grid-template-columns: auto;
margin-top: 10px; margin-top: var(--Spacing-x2);
}
@media screen and (max-width: 1366px) {
.hideWrapper {
bottom: 0;
left: 0;
overflow: auto;
position: fixed;
right: 0;
top: 100%;
transition: top 300ms ease;
z-index: 10002;
}
.container[data-isopen="true"] .hideWrapper {
top: 0;
}
.header {
background-color: var(--Main-Grey-White);
display: grid;
padding: var(--Spacing-x3) var(--Spacing-x2);
}
.close {
background: none;
border: none;
cursor: pointer;
display: flex;
justify-self: flex-end;
padding: 0;
}
.roomContainer {
padding: 0 var(--Spacing-x2);
}
.footer {
background: linear-gradient(
180deg,
rgba(255, 255, 255, 0) 7.5%,
#ffffff 82.5%
);
padding: var(--Spacing-x1) var(--Spacing-x2) var(--Spacing-x7);
position: absolute;
bottom: 0;
width: 100%;
z-index: 10;
}
.footer button {
width: 100%;
}
.footer .hideOnMobile {
display: none;
}
}
@media screen and (min-width: 1367px) {
.hideWrapper {
border-radius: var(--Corner-radius-Large);
box-shadow: 0px 0px 14px 6px rgba(0, 0, 0, 0.1);
left: calc((var(--Spacing-x1) + var(--Spacing-x2)) * -1);
max-width: calc(100vw - 20px);
padding: var(--Spacing-x2) var(--Spacing-x3);
position: absolute;
top: calc(100% + var(--Spacing-x2) + 1px + var(--Spacing-x4));
width: 360px;
}
.header {
display: none;
}
.footer .hideOnDesktop {
display: none;
}
} }

View File

@@ -56,6 +56,12 @@ a.text {
outline: none; outline: none;
} }
.elevated,
a.elevated {
border: none;
box-shadow: 0px 0px 8px 1px rgba(0, 0, 0, 0.1);
}
/* VARIANTS */ /* VARIANTS */
.default, .default,
a.default { a.default {

View File

@@ -10,6 +10,7 @@ export const buttonVariants = cva(styles.btn, {
secondary: styles.secondary, secondary: styles.secondary,
tertiary: styles.tertiary, tertiary: styles.tertiary,
text: styles.text, text: styles.text,
elevated: styles.elevated,
}, },
size: { size: {
small: styles.small, small: styles.small,

View File

@@ -10,7 +10,7 @@ p.caption {
.bold { .bold {
font-family: var(--typography-Caption-Bold-fontFamily); font-family: var(--typography-Caption-Bold-fontFamily);
font-size: var(--typography-Caption-Bold-fontSize); font-size: var(--typography-Caption-Bold-fontSize);
font-weight: var(--typography-Caption-Bold-fontWeight); font-weight: 500; /* var(--typography-Caption-Bold-fontWeight); /* Commented till figma values are fixed to 500 instead of medium */
letter-spacing: var(--typography-Caption-Bold-letterSpacing); letter-spacing: var(--typography-Caption-Bold-letterSpacing);
line-height: var(--typography-Caption-Bold-lineHeight); line-height: var(--typography-Caption-Bold-lineHeight);
text-decoration: var(--typography-Caption-Bold-textDecoration); text-decoration: var(--typography-Caption-Bold-textDecoration);