Merged in fix/STAY-135 (pull request #3368)
Fix/STAY-135 & STAY-127 * fix: make quantity and delivery separate steps in mobile * fix: update design for delivery step in ancillary flow * fix: add error state for missing time * fix: only allow points or cash payment for ancillaries * fix: break out stepper to design system * fix: update design of select quantity step in add ancillaries flow * fix: add error states for quantity * fix: handle insufficient points case * fix: update stepper to include optional disabledMessage tooltip * fix: handle validations * fix: change name to camel case Approved-by: Bianca Widstam Approved-by: Chuma Mcphoy (We Ahead)
This commit is contained in:
@@ -4,8 +4,7 @@ import { useFormContext } from "react-hook-form"
|
||||
import { useIntl } from "react-intl"
|
||||
|
||||
import Caption from "@scandic-hotels/design-system/Caption"
|
||||
|
||||
import Counter from "../Counter"
|
||||
import Stepper from "@scandic-hotels/design-system/Stepper"
|
||||
|
||||
import styles from "./adult-selector.module.css"
|
||||
|
||||
@@ -42,7 +41,7 @@ export default function AdultSelector({
|
||||
<Caption color="uiTextHighContrast" type="bold">
|
||||
{adultsLabel}
|
||||
</Caption>
|
||||
<Counter
|
||||
<Stepper
|
||||
count={currentAdults}
|
||||
handleOnDecrease={decreaseAdultsCount}
|
||||
handleOnIncrease={increaseAdultsCount}
|
||||
|
||||
@@ -4,8 +4,8 @@ import { useFormContext } from "react-hook-form"
|
||||
import { useIntl } from "react-intl"
|
||||
|
||||
import Caption from "@scandic-hotels/design-system/Caption"
|
||||
import Stepper from "@scandic-hotels/design-system/Stepper"
|
||||
|
||||
import Counter from "../Counter"
|
||||
import ChildInfoSelector from "./ChildInfoSelector"
|
||||
|
||||
import styles from "./child-selector.module.css"
|
||||
@@ -58,7 +58,7 @@ export default function ChildSelector({
|
||||
<Caption color="uiTextHighContrast" type="bold">
|
||||
{childrenLabel}
|
||||
</Caption>
|
||||
<Counter
|
||||
<Stepper
|
||||
count={currentChildren.length}
|
||||
handleOnDecrease={() => {
|
||||
decreaseChildrenCount(roomIndex)
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
"use client"
|
||||
|
||||
import { IconButton } from "@scandic-hotels/design-system/IconButton"
|
||||
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
|
||||
import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||
|
||||
import styles from "./counter.module.css"
|
||||
|
||||
type CounterProps = {
|
||||
count: number
|
||||
handleOnIncrease: () => void
|
||||
handleOnDecrease: () => void
|
||||
disableIncrease: boolean
|
||||
disableDecrease: boolean
|
||||
}
|
||||
|
||||
export default function Counter({
|
||||
count,
|
||||
handleOnIncrease,
|
||||
handleOnDecrease,
|
||||
disableIncrease,
|
||||
disableDecrease,
|
||||
}: CounterProps) {
|
||||
return (
|
||||
<div className={styles.counterContainer}>
|
||||
<IconButton
|
||||
className={styles.counterBtn}
|
||||
onPress={handleOnDecrease}
|
||||
variant="Elevated"
|
||||
isDisabled={disableDecrease}
|
||||
>
|
||||
<MaterialIcon icon="remove" color="CurrentColor" />
|
||||
</IconButton>
|
||||
<Typography variant="Body/Paragraph/mdRegular">
|
||||
<p>{count}</p>
|
||||
</Typography>
|
||||
<IconButton
|
||||
className={styles.counterBtn}
|
||||
onPress={handleOnIncrease}
|
||||
variant="Elevated"
|
||||
isDisabled={disableIncrease}
|
||||
>
|
||||
<MaterialIcon icon="add" color="CurrentColor" />
|
||||
</IconButton>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -5,7 +5,7 @@ import { Typography } from '../Typography'
|
||||
import { TypographyProps } from '../Typography/types'
|
||||
|
||||
interface BadgeProps extends VariantProps<typeof config> {
|
||||
number: number
|
||||
number: string | number
|
||||
}
|
||||
|
||||
export function Badge({ number, color, size }: BadgeProps) {
|
||||
|
||||
@@ -12,9 +12,10 @@ type FocalPoint = {
|
||||
y: number
|
||||
}
|
||||
|
||||
export type ImageProps = NextImageProps & {
|
||||
export type ImageProps = Omit<NextImageProps, 'src'> & {
|
||||
focalPoint?: FocalPoint
|
||||
dimensions?: { width: number; height: number }
|
||||
src: NextImageProps['src'] | undefined
|
||||
}
|
||||
|
||||
// Next/Image adds & instead of ? before the params
|
||||
|
||||
@@ -9,9 +9,17 @@ interface RadioProps extends PropsWithChildren {
|
||||
id?: string
|
||||
isDisabled?: boolean
|
||||
color?: 'Burgundy'
|
||||
wrapping?: boolean
|
||||
}
|
||||
|
||||
export function Radio({ id, value, children, color, isDisabled }: RadioProps) {
|
||||
export function Radio({
|
||||
id,
|
||||
value,
|
||||
children,
|
||||
color,
|
||||
isDisabled,
|
||||
wrapping = true,
|
||||
}: RadioProps) {
|
||||
const inputId = id || `radio-${value}`
|
||||
|
||||
const classNames = variants({
|
||||
@@ -23,10 +31,13 @@ export function Radio({ id, value, children, color, isDisabled }: RadioProps) {
|
||||
id={inputId}
|
||||
value={value}
|
||||
isDisabled={isDisabled}
|
||||
className={cx(styles.container, { [styles.disabled]: isDisabled })}
|
||||
className={cx(styles.container, {
|
||||
[styles.disabled]: isDisabled,
|
||||
[styles.wrapping]: wrapping,
|
||||
})}
|
||||
>
|
||||
<div className={`${styles.radio} ${classNames}`} />
|
||||
<div>{children}</div>
|
||||
{children && <div>{children}</div>}
|
||||
</AriaRadio>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2,10 +2,14 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--Space-x15);
|
||||
padding: var(--Space-x1) 0;
|
||||
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.wrapping {
|
||||
padding: var(--Space-x1) 0;
|
||||
}
|
||||
|
||||
.radio {
|
||||
position: relative;
|
||||
width: 24px;
|
||||
|
||||
58
packages/design-system/lib/components/Stepper/index.tsx
Normal file
58
packages/design-system/lib/components/Stepper/index.tsx
Normal file
@@ -0,0 +1,58 @@
|
||||
import { IconButton } from '../IconButton'
|
||||
import { MaterialIcon } from '../Icons/MaterialIcon'
|
||||
import { Tooltip } from '../Tooltip'
|
||||
import { Typography } from '../Typography'
|
||||
|
||||
import styles from './stepper.module.css'
|
||||
|
||||
type StepperProps = {
|
||||
count: number
|
||||
handleOnIncrease: () => void
|
||||
handleOnDecrease: () => void
|
||||
disableIncrease: boolean
|
||||
disableDecrease: boolean
|
||||
disabledMessage?: string
|
||||
}
|
||||
|
||||
export default function Stepper({
|
||||
count,
|
||||
handleOnIncrease,
|
||||
handleOnDecrease,
|
||||
disableIncrease,
|
||||
disableDecrease,
|
||||
disabledMessage,
|
||||
}: StepperProps) {
|
||||
return (
|
||||
<div className={styles.counterContainer}>
|
||||
<IconButton
|
||||
className={styles.counterBtn}
|
||||
onPress={handleOnDecrease}
|
||||
variant="Elevated"
|
||||
isDisabled={disableDecrease}
|
||||
>
|
||||
<MaterialIcon icon="remove" color="CurrentColor" />
|
||||
</IconButton>
|
||||
<div className={styles.countDisplay}>
|
||||
<Typography variant="Body/Paragraph/mdRegular">
|
||||
<p>{count}</p>
|
||||
</Typography>
|
||||
</div>
|
||||
<Tooltip
|
||||
text={disabledMessage}
|
||||
isVisible={Boolean(disabledMessage && disableIncrease)}
|
||||
position="top"
|
||||
arrow="right"
|
||||
isTouchable
|
||||
>
|
||||
<IconButton
|
||||
className={styles.counterBtn}
|
||||
onPress={handleOnIncrease}
|
||||
variant="Elevated"
|
||||
isDisabled={disableIncrease}
|
||||
>
|
||||
<MaterialIcon icon="add" color="CurrentColor" />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
gap: 20px;
|
||||
gap: var(--Space-x1);
|
||||
color: var(--Text-Interactive-Default);
|
||||
}
|
||||
.counterBtn {
|
||||
@@ -12,3 +12,8 @@
|
||||
.counterBtn:not([disabled]) {
|
||||
box-shadow: 0px 0px 8px 1px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.countDisplay {
|
||||
width: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
@@ -43,6 +43,9 @@ export function Tooltip<P extends TooltipPosition>({
|
||||
|
||||
function handleToggle() {
|
||||
setIsActive((prevState) => !prevState)
|
||||
setTimeout(() => {
|
||||
setIsActive(false)
|
||||
}, 3000)
|
||||
}
|
||||
|
||||
function handleKeyDown(event: React.KeyboardEvent<HTMLDivElement>) {
|
||||
|
||||
@@ -44,6 +44,10 @@
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.top.arrowRight {
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.tooltip::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
|
||||
@@ -276,7 +276,7 @@
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: block;
|
||||
src: url(/_static/shared/fonts/material-symbols/rounded-b1df8938.woff2)
|
||||
src: url(/_static/shared/fonts/material-symbols/rounded-3e10d67b.woff2)
|
||||
format('woff2');
|
||||
}
|
||||
|
||||
|
||||
@@ -165,6 +165,7 @@
|
||||
"./Payment/PaymentMethodIcon": "./lib/components/Payment/PaymentMethodIcon.tsx",
|
||||
"./PointsRateCard": "./lib/components/RateCard/Points/index.tsx",
|
||||
"./Progress": "./lib/components/Progress/index.tsx",
|
||||
"./Radio": "./lib/components/Radio/index.tsx",
|
||||
"./RegularRateCard": "./lib/components/RateCard/Regular/index.tsx",
|
||||
"./Select": "./lib/components/Select/index.tsx",
|
||||
"./SidePeek": "./lib/components/SidePeek/index.tsx",
|
||||
@@ -172,6 +173,7 @@
|
||||
"./SidePeekSelfControlled": "./lib/components/SidePeek/SelfControlled.tsx",
|
||||
"./SkeletonShimmer": "./lib/components/SkeletonShimmer/index.tsx",
|
||||
"./StaticMap": "./lib/components/StaticMap/index.tsx",
|
||||
"./Stepper": "./lib/components/Stepper/index.tsx",
|
||||
"./Subtitle": "./lib/components/Subtitle/index.tsx",
|
||||
"./Switch": "./lib/components/Switch/index.tsx",
|
||||
"./Table": "./lib/components/Table/index.tsx",
|
||||
|
||||
@@ -496,6 +496,7 @@ export const ancillaryPackagesSchema = z
|
||||
translatedCategoryName: ancillary.categoryName,
|
||||
internalCategoryName: ancillary.internalCategoryName,
|
||||
requiresQuantity: getRequiresQuantity(item.id),
|
||||
unitName: item.unitName,
|
||||
})),
|
||||
}))
|
||||
.filter((ancillary) => ancillary.ancillaryContent.length > 0)
|
||||
|
||||
Reference in New Issue
Block a user