From 310a5a7a68cffb99d72d92ee41c540b4a445c5d0 Mon Sep 17 00:00:00 2001 From: Tobias Johansson Date: Tue, 25 Mar 2025 17:27:09 +0100 Subject: [PATCH] fixes --- .../lib/components/Icons/CheckCircle.tsx | 17 + .../{ => Campaign}/Campaign.stories.tsx | 52 ++- .../components/RateCard/Campaign/index.tsx | 151 +++++++ .../RateCard/{ => Code}/Code.stories.tsx | 60 +-- .../lib/components/RateCard/Code/index.tsx | 122 +++++ .../NoRateAvailable.stories.tsx | 62 +++ .../RateCard/NoRateAvailable/index.tsx | 63 +++ .../RateCard/{ => Points}/Points.stories.tsx | 41 +- .../lib/components/RateCard/Points/index.tsx | 113 +++++ .../lib/components/RateCard/RateCard.tsx | 416 ------------------ .../components/RateCard/Regular.stories.tsx | 38 -- .../RateCard/Regular/Regular.stories.tsx | 99 +++++ .../lib/components/RateCard/Regular/index.tsx | 117 +++++ .../lib/components/RateCard/index.tsx | 1 - .../components/RateCard/rate-card.module.css | 75 +++- .../lib/components/RateCard/types.ts | 4 +- packages/design-system/package.json | 6 +- 17 files changed, 914 insertions(+), 523 deletions(-) create mode 100644 packages/design-system/lib/components/Icons/CheckCircle.tsx rename packages/design-system/lib/components/RateCard/{ => Campaign}/Campaign.stories.tsx (64%) create mode 100644 packages/design-system/lib/components/RateCard/Campaign/index.tsx rename packages/design-system/lib/components/RateCard/{ => Code}/Code.stories.tsx (68%) create mode 100644 packages/design-system/lib/components/RateCard/Code/index.tsx create mode 100644 packages/design-system/lib/components/RateCard/NoRateAvailable/NoRateAvailable.stories.tsx create mode 100644 packages/design-system/lib/components/RateCard/NoRateAvailable/index.tsx rename packages/design-system/lib/components/RateCard/{ => Points}/Points.stories.tsx (70%) create mode 100644 packages/design-system/lib/components/RateCard/Points/index.tsx delete mode 100644 packages/design-system/lib/components/RateCard/RateCard.tsx delete mode 100644 packages/design-system/lib/components/RateCard/Regular.stories.tsx create mode 100644 packages/design-system/lib/components/RateCard/Regular/Regular.stories.tsx create mode 100644 packages/design-system/lib/components/RateCard/Regular/index.tsx delete mode 100644 packages/design-system/lib/components/RateCard/index.tsx diff --git a/packages/design-system/lib/components/Icons/CheckCircle.tsx b/packages/design-system/lib/components/Icons/CheckCircle.tsx new file mode 100644 index 000000000..654be6283 --- /dev/null +++ b/packages/design-system/lib/components/Icons/CheckCircle.tsx @@ -0,0 +1,17 @@ +import { SVGProps } from 'react' + +export default function CheckCircleIcon(props: SVGProps) { + return ( + + + + ) +} diff --git a/packages/design-system/lib/components/RateCard/Campaign.stories.tsx b/packages/design-system/lib/components/RateCard/Campaign/Campaign.stories.tsx similarity index 64% rename from packages/design-system/lib/components/RateCard/Campaign.stories.tsx rename to packages/design-system/lib/components/RateCard/Campaign/Campaign.stories.tsx index f5a0c6fb7..882d9a390 100644 --- a/packages/design-system/lib/components/RateCard/Campaign.stories.tsx +++ b/packages/design-system/lib/components/RateCard/Campaign/Campaign.stories.tsx @@ -1,10 +1,9 @@ import type { Meta, StoryObj } from '@storybook/react' +import CampaignRateCard from '.' -import { RateCard } from './RateCard' - -const meta: Meta = { +const meta: Meta = { title: 'Components/RateCard/Campaign', - component: RateCard, + component: CampaignRateCard, decorators: [ (Story) => (
@@ -13,18 +12,25 @@ const meta: Meta = { ), ], argTypes: { - title: { control: 'text' }, + rateTitle: { control: 'text' }, + paymentTerm: { control: 'text' }, + bannerText: { control: 'text' }, + rate: { control: 'object' }, + memberRate: { control: 'object' }, + referenceRate: { control: 'object' }, + comparisonRate: { control: 'object' }, + approximateRate: { control: 'object' }, }, } export default meta -type Story = StoryObj +type Story = StoryObj export const Default: Story = { args: { - variant: 'Campaign', - title: 'NON-REFUNDABLE / PAY NOW', + rateTitle: 'NON-REFUNDABLE', + paymentTerm: 'PAY NOW', bannerText: 'Campaign ∙ Breakfast included', rate: { label: "Valentine's Special", @@ -32,20 +38,22 @@ export const Default: Story = { unit: 'EUR/NIGHT', }, approximateRate: { - price: '198 EUR', + price: '198', label: 'Approx.', + unit: 'EUR', }, referenceRate: { - price: '249 EUR', + price: '249', label: 'Lowest past price (last 30 days)', + unit: 'EUR', }, }, } export const Package: Story = { args: { - variant: 'Campaign', - title: 'NON-REFUNDABLE / PAY NOW', + rateTitle: 'NON-REFUNDABLE', + paymentTerm: 'PAY NOW', bannerText: 'WDCPHG ∙ Breakfast included', rate: { label: 'Luxurious wine & dine in Copenhagen', @@ -53,16 +61,17 @@ export const Package: Story = { unit: 'EUR/NIGHT', }, approximateRate: { - price: '1989 EUR', + price: '1989', label: 'Approx.', + unit: 'EUR', }, }, } export const CampaignLoggedIn: Story = { args: { - variant: 'Campaign', - title: 'NON-REFUNDABLE / PAY NOW', + rateTitle: 'NON-REFUNDABLE', + paymentTerm: 'PAY NOW', bannerText: 'SUM2025 ∙ Breakfast included', rate: { label: 'Luxurious wine & dine in Copenhagen', @@ -70,8 +79,9 @@ export const CampaignLoggedIn: Story = { unit: 'EUR/NIGHT', }, approximateRate: { - price: '198 EUR', + price: '198', label: 'Approx.', + unit: 'EUR', }, comparisonRate: { price: '249', @@ -83,8 +93,8 @@ export const CampaignLoggedIn: Story = { export const CampaignOmnibus: Story = { args: { - variant: 'Campaign', - title: 'NON-REFUNDABLE / PAY NOW', + rateTitle: 'NON-REFUNDABLE', + paymentTerm: 'PAY NOW', bannerText: 'WDCPHG ∙ Breakfast included', rate: { label: 'Luxurious wine & dine in Copenhagen', @@ -97,12 +107,14 @@ export const CampaignOmnibus: Story = { unit: 'EUR/NIGHT', }, approximateRate: { - price: '198 EUR', + price: '198', label: 'Approx.', + unit: 'EUR', }, referenceRate: { - price: '101 EUR', + price: '101', label: 'Lowest past price (last 30 days)', + unit: 'EUR', }, }, } diff --git a/packages/design-system/lib/components/RateCard/Campaign/index.tsx b/packages/design-system/lib/components/RateCard/Campaign/index.tsx new file mode 100644 index 000000000..197fc88e2 --- /dev/null +++ b/packages/design-system/lib/components/RateCard/Campaign/index.tsx @@ -0,0 +1,151 @@ +import { Typography } from '../../Typography' +import { Rate } from '../types' + +import styles from '../rate-card.module.css' +import { Button } from '../../Button' +import InfoCircleIcon from '../../Icons/InfoCircle' +import { variants } from '../variants' + +interface CampaignRateCardProps { + name: string + value: string + isSelected: boolean + rateTitle: string + paymentTerm: string + bannerText: string + rate: Rate + memberRate?: Rate + referenceRate: Rate + comparisonRate?: Omit + isHighlightedRate?: boolean + approximateRate: Rate + handleChange: () => void + handleTermsClick?: () => void +} + +export default function CampaignRateCard({ + name, + value, + isSelected, + rateTitle, + paymentTerm, + rate, + memberRate, + approximateRate, + comparisonRate, + referenceRate, + bannerText, + isHighlightedRate, + handleChange, + handleTermsClick, +}: CampaignRateCardProps) { + const classNames = variants({ + variant: 'Campaign', + }) + + return ( + + ) +} diff --git a/packages/design-system/lib/components/RateCard/Code.stories.tsx b/packages/design-system/lib/components/RateCard/Code/Code.stories.tsx similarity index 68% rename from packages/design-system/lib/components/RateCard/Code.stories.tsx rename to packages/design-system/lib/components/RateCard/Code/Code.stories.tsx index a40219f90..2dc2ab1db 100644 --- a/packages/design-system/lib/components/RateCard/Code.stories.tsx +++ b/packages/design-system/lib/components/RateCard/Code/Code.stories.tsx @@ -1,10 +1,9 @@ import type { Meta, StoryObj } from '@storybook/react' +import CodeRateCard from '.' -import { RateCard } from './RateCard' - -const meta: Meta = { +const meta: Meta = { title: 'Components/RateCard/Code', - component: RateCard, + component: CodeRateCard, decorators: [ (Story) => (
@@ -13,18 +12,21 @@ const meta: Meta = { ), ], argTypes: { - title: { control: 'text' }, + rateTitle: { control: 'text' }, + paymentTerm: { control: 'text' }, + rate: { control: 'object' }, + approximateRate: { control: 'object' }, }, } export default meta -type Story = StoryObj +type Story = StoryObj export const Default: Story = { args: { - variant: 'Code', - title: 'FREE CANCELLATION / PAY LATER', + rateTitle: 'FREE CANCELLATION', + paymentTerm: 'PAY LATER', bannerText: 'Campaign ∙ Breakfast excluded', rate: { label: "Valentine's Special", @@ -32,16 +34,17 @@ export const Default: Story = { unit: 'EUR/night', }, approximateRate: { - price: '1989 EUR', + price: '1989', label: 'Approx.', + unit: 'EUR', }, }, } export const Voucher: Story = { args: { - variant: 'Code', - title: 'FREE CANCELLATION / PAY LATER', + rateTitle: 'FREE CANCELLATION', + paymentTerm: 'PAY LATER', bannerText: 'VOG ∙ Breakfast included', rate: { label: 'Promotional name here', @@ -53,8 +56,8 @@ export const Voucher: Story = { export const CorporateCheck: Story = { args: { - variant: 'Code', - title: 'FREE CANCELLATION / PAY LATER', + rateTitle: 'FREE CANCELLATION', + paymentTerm: 'PAY LATER', bannerText: 'VOG ∙ Breakfast included', rate: { label: 'Promotional name here', @@ -62,16 +65,17 @@ export const CorporateCheck: Story = { unit: 'SEK', }, approximateRate: { - price: '76 EUR', + price: '76', label: 'Approx.', + unit: 'EUR', }, }, } export const DNumberDefault: Story = { args: { - variant: 'Code', - title: 'FREE CANCELLATION / PAY LATER', + rateTitle: 'FREE CANCELLATION', + paymentTerm: 'PAY LATER', bannerText: 'D0043148 ∙ Breakfast included', rate: { label: 'Helsinki Partners Oy', @@ -79,16 +83,17 @@ export const DNumberDefault: Story = { unit: 'EUR/NIGHT', }, approximateRate: { - price: '76 EUR', + price: '76', label: 'Approx.', + unit: 'EUR', }, }, } export const DNumberHighlightedRate: Story = { args: { - variant: 'Code', - title: 'FREE CANCELLATION / PAY LATER', + rateTitle: 'FREE CANCELLATION', + paymentTerm: 'PAY LATER', bannerText: 'D0043148 ∙ Breakfast included', rate: { label: 'Helsinki Partners Oy', @@ -96,8 +101,9 @@ export const DNumberHighlightedRate: Story = { unit: 'EUR/NIGHT', }, approximateRate: { - price: '76 EUR', + price: '76', label: 'Approx.', + unit: 'EUR', }, isHighlightedRate: true, }, @@ -105,8 +111,8 @@ export const DNumberHighlightedRate: Story = { export const LNumberDefault: Story = { args: { - variant: 'Code', - title: 'NON-REFUNDABLE / PAY NOW', + rateTitle: 'NON-REFUNDABLE', + paymentTerm: 'PAY NOW', bannerText: 'L0043148 ∙ Breakfast included', rate: { label: 'Nordic Team Travel', @@ -114,16 +120,17 @@ export const LNumberDefault: Story = { unit: 'EUR/NIGHT', }, approximateRate: { - price: '76 EUR', + price: '76', label: 'Approx.', + unit: 'EUR', }, }, } export const LNumberStrikethrough: Story = { args: { - variant: 'Code', - title: 'NON-REFUNDABLE / PAY NOW', + rateTitle: 'NON-REFUNDABLE', + paymentTerm: 'PAY NOW', bannerText: 'L0043148 ∙ Breakfast included', rate: { label: 'Nordic Team Travel', @@ -135,8 +142,9 @@ export const LNumberStrikethrough: Story = { unit: 'EUR/NIGHT', }, approximateRate: { - price: '230/218 EUR', + price: '230/218', label: 'Approx.', + unit: 'EUR', }, }, } diff --git a/packages/design-system/lib/components/RateCard/Code/index.tsx b/packages/design-system/lib/components/RateCard/Code/index.tsx new file mode 100644 index 000000000..6a1a2f568 --- /dev/null +++ b/packages/design-system/lib/components/RateCard/Code/index.tsx @@ -0,0 +1,122 @@ +import { Rate } from '../types' + +import styles from '../rate-card.module.css' +import { Typography } from '../../Typography' +import { Button } from '../../Button' +import InfoCircleIcon from '../../Icons/InfoCircle' +import { variants } from '../variants' + +interface CodeRateCardProps { + name: string + value: string + isSelected: boolean + rateTitle: string + paymentTerm: string + rate: Rate + bannerText: string + comparisonRate?: Omit + approximateRate?: Rate + isHighlightedRate?: boolean + handleChange: () => void + handleTermsClick?: () => void +} + +export default function CodeRateCard({ + name, + value, + isSelected, + rateTitle, + paymentTerm, + rate, + approximateRate, + comparisonRate, + bannerText, + isHighlightedRate, + handleChange, + handleTermsClick, +}: CodeRateCardProps) { + const classNames = variants({ + variant: 'Code', + }) + + return ( + + ) +} diff --git a/packages/design-system/lib/components/RateCard/NoRateAvailable/NoRateAvailable.stories.tsx b/packages/design-system/lib/components/RateCard/NoRateAvailable/NoRateAvailable.stories.tsx new file mode 100644 index 000000000..352f58180 --- /dev/null +++ b/packages/design-system/lib/components/RateCard/NoRateAvailable/NoRateAvailable.stories.tsx @@ -0,0 +1,62 @@ +import type { Meta, StoryObj } from '@storybook/react' +import NoRateAvailableCard from '.' + +const meta: Meta = { + title: 'Components/RateCard/NoRateAvailable', + component: NoRateAvailableCard, + decorators: [ + (Story) => ( +
+ +
+ ), + ], + argTypes: { + rateTitle: { control: 'text' }, + paymentTerm: { control: 'text' }, + noPricesAvailableText: { control: 'text' }, + }, +} + +export default meta + +type Story = StoryObj + +export const NoRateAvailable: Story = { + args: { + variant: 'Regular', + rateTitle: 'FREE CANCELLATION', + paymentTerm: 'PAY NOW', + noPricesAvailableText: 'No prices available', + }, +} + +export const NoRateAvailableCampaign: Story = { + args: { + variant: 'Campaign', + rateTitle: 'FREE CANCELLATION', + paymentTerm: 'PAY NOW', + bannerText: 'Campaign ∙ Breakfast included', + noPricesAvailableText: 'No prices available', + }, +} + +export const NoRateAvailableCode: Story = { + args: { + variant: 'Code', + rateTitle: 'FREE CANCELLATION', + paymentTerm: 'PAY NOW', + bannerText: 'WDCPHG ∙ Breakfast included', + noPricesAvailableText: 'No prices available', + }, +} + +export const NoRateAvailablePoints: Story = { + args: { + variant: 'Points', + rateTitle: 'FREE CANCELLATION', + paymentTerm: 'PAY NOW', + bannerText: 'WDCPHG ∙ Breakfast included', + noPricesAvailableText: 'No prices available', + }, +} diff --git a/packages/design-system/lib/components/RateCard/NoRateAvailable/index.tsx b/packages/design-system/lib/components/RateCard/NoRateAvailable/index.tsx new file mode 100644 index 000000000..18392e36d --- /dev/null +++ b/packages/design-system/lib/components/RateCard/NoRateAvailable/index.tsx @@ -0,0 +1,63 @@ +import styles from '../rate-card.module.css' +import { Typography } from '../../Typography' +import { Button } from '../../Button' +import InfoCircleIcon from '../../Icons/InfoCircle' +import { variants } from '../variants' + +interface NoRateAvailableCardProps { + variant: 'Regular' | 'Campaign' | 'Code' | 'Points' + rateTitle: string + paymentTerm: string + bannerText?: string + noPricesAvailableText: string + handleTermsClick?: () => void +} + +export default function NoRateAvailableCard({ + variant, + rateTitle, + paymentTerm, + bannerText, + noPricesAvailableText, + handleTermsClick, +}: NoRateAvailableCardProps) { + const classNames = variants({ + variant, + }) + + return ( +
+ {bannerText && ( + +

{bannerText}

+
+ )} +
+
+ +

+ + {`${rateTitle} / ${paymentTerm}`} +

+
+
+
+
+ +

+ {noPricesAvailableText} +

+
+
+
+
+
+ ) +} diff --git a/packages/design-system/lib/components/RateCard/Points.stories.tsx b/packages/design-system/lib/components/RateCard/Points/Points.stories.tsx similarity index 70% rename from packages/design-system/lib/components/RateCard/Points.stories.tsx rename to packages/design-system/lib/components/RateCard/Points/Points.stories.tsx index df2813e60..e1a6a147d 100644 --- a/packages/design-system/lib/components/RateCard/Points.stories.tsx +++ b/packages/design-system/lib/components/RateCard/Points/Points.stories.tsx @@ -1,10 +1,10 @@ import type { Meta, StoryObj } from '@storybook/react' -import { RateCard } from './RateCard' +import PointsRateCard from '.' -const meta: Meta = { +const meta: Meta = { title: 'Components/RateCard/Points', - component: RateCard, + component: PointsRateCard, decorators: [ (Story) => (
@@ -13,18 +13,25 @@ const meta: Meta = { ), ], argTypes: { - title: { control: 'text' }, + rateTitle: { control: 'text' }, + paymentTerm: { control: 'text' }, + bannerText: { control: 'text' }, + rates: { control: 'object' }, + selectedRate: { control: 'text' }, + onRateSelect: { action: 'onRateSelect' }, + isNotEnoughPoints: { control: 'boolean' }, + notEnoughPointsText: { control: 'text' }, }, } export default meta -type Story = StoryObj +type Story = StoryObj export const Default: Story = { args: { - variant: 'Points', - title: 'FREE CANCELLATION / PAY LATER', + rateTitle: 'FREE CANCELLATION', + paymentTerm: 'PAY LATER', bannerText: 'Reward night ∙ Breakfast included', rates: [ { @@ -34,7 +41,7 @@ export const Default: Story = { { points: '15000', currency: 'PTS', - additionalCurrency: { + additionalPrice: { price: '250', currency: 'EUR', }, @@ -42,7 +49,7 @@ export const Default: Story = { { points: '10000', currency: 'PTS', - additionalCurrency: { + additionalPrice: { price: '500', currency: 'EUR', }, @@ -55,8 +62,8 @@ export const Default: Story = { export const WithDisabledRates: Story = { args: { - variant: 'Points', - title: 'FREE CANCELLATION / PAY LATER', + rateTitle: 'FREE CANCELLATION', + paymentTerm: 'PAY LATER', bannerText: 'Reward night ∙ Breakfast included', rates: [ { @@ -68,7 +75,7 @@ export const WithDisabledRates: Story = { points: '15000', currency: 'PTS', isDisabled: true, - additionalCurrency: { + additionalPrice: { price: '250', currency: 'EUR', }, @@ -76,7 +83,7 @@ export const WithDisabledRates: Story = { { points: '10000', currency: 'PTS', - additionalCurrency: { + additionalPrice: { price: '500', currency: 'EUR', }, @@ -89,8 +96,8 @@ export const WithDisabledRates: Story = { export const NotEnoughPoints: Story = { args: { - variant: 'Points', - title: 'FREE CANCELLATION / PAY LATER', + rateTitle: 'FREE CANCELLATION', + paymentTerm: 'PAY LATER', bannerText: 'Reward night ∙ Breakfast included', rates: [ { @@ -100,7 +107,7 @@ export const NotEnoughPoints: Story = { { points: '15000', currency: 'PTS', - additionalCurrency: { + additionalPrice: { price: '250', currency: 'EUR', }, @@ -108,7 +115,7 @@ export const NotEnoughPoints: Story = { { points: '10000', currency: 'PTS', - additionalCurrency: { + additionalPrice: { price: '500', currency: 'EUR', }, diff --git a/packages/design-system/lib/components/RateCard/Points/index.tsx b/packages/design-system/lib/components/RateCard/Points/index.tsx new file mode 100644 index 000000000..924d75be3 --- /dev/null +++ b/packages/design-system/lib/components/RateCard/Points/index.tsx @@ -0,0 +1,113 @@ +import { Typography } from '../../Typography' +import { RatePointsOption } from '../types' + +import styles from '../rate-card.module.css' +import { Button } from '../../Button' +import InfoCircleIcon from '../../Icons/InfoCircle' +import InfoCircleFilledIcon from '../../Icons/InfoCircleFilled' +import { Radio } from '../../Radio' +import { RadioGroup } from 'react-aria-components' +import { variants } from '../variants' + +interface PointsRateCardProps { + rateTitle: string + paymentTerm: string + bannerText: string + rates: RatePointsOption[] + selectedRate: string | undefined + onRateSelect: (value: string) => void + isNotEnoughPoints?: boolean + notEnoughPointsText?: string + handleTermsClick?: () => void +} + +export default function PointsRateCard({ + rateTitle, + paymentTerm, + bannerText, + rates, + selectedRate, + isNotEnoughPoints, + notEnoughPointsText, + onRateSelect, + handleTermsClick, +}: PointsRateCardProps) { + const classNames = variants({ + variant: 'Points', + }) + + return ( +
+ +

{bannerText}

+
+
+
+ +

+ + {rateTitle} + + {` / ${paymentTerm}`} + +

+
+
+
+ + {rates.map((rate, index) => ( +
+ +
+ +

+ {rate.points}{' '} + + + {rate.currency} {rate.additionalPrice && ' + '} + + +

+
+ {rate.additionalPrice && ( + +

+ {rate.additionalPrice.price}{' '} + + {rate.currency} + +

+
+ )} +
+
+
+ ))} +
+
+ {isNotEnoughPoints ? ( +
+ +

+

+ +
+ {notEnoughPointsText} +

+
+
+ ) : null} +
+
+ ) +} diff --git a/packages/design-system/lib/components/RateCard/RateCard.tsx b/packages/design-system/lib/components/RateCard/RateCard.tsx deleted file mode 100644 index 6c72b1dff..000000000 --- a/packages/design-system/lib/components/RateCard/RateCard.tsx +++ /dev/null @@ -1,416 +0,0 @@ -import { PropsWithChildren } from 'react' -import { Typography } from '../Typography' - -import styles from './rate-card.module.css' -import { variants } from './variants' -import { Rate, RatePointsOption } from './types' -import InfoCircleIcon from '../Icons/InfoCircle' -import { Radio } from '../Radio' -import { RadioGroup } from 'react-aria-components' -import InfoCircleFilledIcon from '../Icons/InfoCircleFilled' -import { Button } from '../Button' - -type RateCardProps = - | RegularRateCardProps - | CampaignRateCardProps - | CodeRateCardProps - | PointsRateCardProps - -export function RateCard(props: PropsWithChildren) { - const classNames = variants({ - variant: props.variant, - }) - - switch (props.variant) { - case 'Campaign': - return - case 'Code': - return - case 'Points': - return - default: - return - } -} - -interface RegularRateCardProps { - variant: 'Regular' - title: string - rate: Rate - memberRate?: Rate - approximateRate: Omit - className?: string - handleTermsClick?: () => void -} - -function RegularRateCard({ - title, - className, - approximateRate, - rate, - handleTermsClick, -}: RegularRateCardProps) { - const [mainTitle, subTitle] = title.split('/').map((part) => part.trim()) - - return ( -
-
-
- -

- - {mainTitle} - {subTitle && ( - {` / ${subTitle}`} - )} -

-
-
-
-
- -

{rate.label}

-
- -

- {rate.price}{' '} - - {rate.unit} - -

-
-
-
- -

{approximateRate.label}

-
- -

{approximateRate.price}

-
-
-
-
-
- ) -} - -// RED CARD - -interface CampaignRateCardProps extends Omit { - variant: 'Campaign' - bannerText: string - comparisonRate?: Omit - referenceRate: Omit - isHighlightedRate?: boolean -} - -function CampaignRateCard({ - title, - rate, - memberRate, - approximateRate, - comparisonRate, - referenceRate, - className, - bannerText, - isHighlightedRate, - handleTermsClick, -}: CampaignRateCardProps) { - const [mainTitle, subTitle] = title.split('/').map((part) => part.trim()) - - return ( -
- -

{bannerText}

-
-
-
- -

- - {mainTitle} - {subTitle && ( - {` / ${subTitle}`} - )} -

-
-
-
-
- -

{rate.label}

-
- -

- {rate.price}{' '} - - {rate.unit} - -

-
-
- {memberRate ? ( -
- -

{memberRate.label}

-
- -

- {memberRate.price}{' '} - - {memberRate.unit} - -

-
-
- ) : null} - {comparisonRate ? ( -
- -

- {rate.price}{' '} - - - {comparisonRate.unit} - - -

-
-
- ) : null} -
- -

{approximateRate.label}

-
- -

{approximateRate.price}

-
-
-
- {referenceRate ? ( -
- -

{referenceRate.label}

-
- -

{referenceRate.price}

-
-
- ) : null} -
-
- ) -} - -// BLUE CARD - -interface CodeRateCardProps - extends Omit { - variant: 'Code' - bannerText: string - comparisonRate?: Omit - approximateRate?: Omit - isHighlightedRate?: boolean -} - -function CodeRateCard({ - title, - rate, - approximateRate, - comparisonRate, - bannerText, - className, - isHighlightedRate, - handleTermsClick, -}: CodeRateCardProps) { - const [mainTitle, subTitle] = title.split('/').map((part) => part.trim()) - - return ( -
- -

{bannerText}

-
-
-
- -

- - {mainTitle} - {subTitle && ( - {` / ${subTitle}`} - )} -

-
-
-
-
- -

{rate.label}

-
- -

- {rate.price}{' '} - - {rate.unit} - -

-
-
- {comparisonRate ? ( -
- -

- {rate.price}{' '} - - - {comparisonRate.unit} - - -

-
-
- ) : null} - {approximateRate ? ( -
- -

{approximateRate.label}

-
- -

{approximateRate.price}

-
-
- ) : null} -
-
-
- ) -} - -// POINTS CARD - -interface PointsRateCardProps { - variant: 'Points' - title: string - bannerText: string - className?: string - rates: RatePointsOption[] - selectedRate: string | undefined - onRateSelect: (value: string) => void - isNotEnoughPoints?: boolean - notEnoughPointsText?: string - handleTermsClick?: () => void -} - -function PointsRateCard({ - title, - bannerText, - className, - rates, - selectedRate, - isNotEnoughPoints, - notEnoughPointsText, - onRateSelect, - handleTermsClick, -}: PointsRateCardProps) { - const [mainTitle, subTitle] = title.split('/').map((part) => part.trim()) - - return ( -
- -

{bannerText}

-
-
-
- -

- - {mainTitle} - {subTitle && ( - {` / ${subTitle}`} - )} -

-
-
-
- - {rates.map((rate, index) => ( -
- -
- -

- {rate.points}{' '} - - - {rate.currency} {rate.additionalCurrency && ' + '} - - -

-
- {rate.additionalCurrency && ( - -

- {rate.additionalCurrency.price}{' '} - - {rate.currency} - -

-
- )} -
-
-
- ))} -
-
- {isNotEnoughPoints ? ( -
- -

-

- -
- {notEnoughPointsText} -

-
-
- ) : null} -
-
- ) -} diff --git a/packages/design-system/lib/components/RateCard/Regular.stories.tsx b/packages/design-system/lib/components/RateCard/Regular.stories.tsx deleted file mode 100644 index a0ad364de..000000000 --- a/packages/design-system/lib/components/RateCard/Regular.stories.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import type { Meta, StoryObj } from '@storybook/react' - -import { RateCard } from './RateCard' - -const meta: Meta = { - title: 'Components/RateCard/Regular', - component: RateCard, - decorators: [ - (Story) => ( -
- -
- ), - ], - argTypes: { - title: { control: 'text' }, - }, -} - -export default meta - -type Story = StoryObj - -export const Regular: Story = { - args: { - variant: 'Regular', - title: 'FREE CANCELLATION / PAY NOW', - rate: { - label: 'Standard Price', - price: '1989', - unit: 'EUR/night', - }, - approximateRate: { - price: '1989 EUR', - label: 'Approx.', - }, - }, -} diff --git a/packages/design-system/lib/components/RateCard/Regular/Regular.stories.tsx b/packages/design-system/lib/components/RateCard/Regular/Regular.stories.tsx new file mode 100644 index 000000000..de56411ce --- /dev/null +++ b/packages/design-system/lib/components/RateCard/Regular/Regular.stories.tsx @@ -0,0 +1,99 @@ +import type { Meta, StoryObj } from '@storybook/react' +import RegularRateCard from '.' + +const meta: Meta = { + title: 'Components/RateCard/Regular', + component: RegularRateCard, + decorators: [ + (Story) => ( +
+ +
+ ), + ], + argTypes: { + rateTitle: { control: 'text' }, + paymentTerm: { control: 'text' }, + rate: { control: 'object' }, + memberRate: { control: 'object' }, + approximateRate: { control: 'object' }, + }, +} + +export default meta + +type Story = StoryObj + +export const Default: Story = { + args: { + name: 'regular', + value: 'regular', + rateTitle: 'FREE CANCELLATION', + paymentTerm: 'PAY NOW', + rate: { + label: 'Standard Price', + price: '198', + unit: 'EUR/NIGHT', + }, + memberRate: { + label: 'Member Price', + price: '190', + unit: 'EUR/NIGHT', + }, + approximateRate: { + price: '198', + label: 'Approx.', + unit: 'EUR', + }, + }, +} + +export const Selected: Story = { + args: { + name: 'regular', + value: 'regular', + isSelected: true, + rateTitle: 'FREE CANCELLATION', + paymentTerm: 'PAY NOW', + rate: { + label: 'Standard Price', + price: '198', + unit: 'EUR/NIGHT', + }, + memberRate: { + label: 'Member Price', + price: '190', + unit: 'EUR/NIGHT', + }, + approximateRate: { + price: '198', + label: 'Approx.', + unit: 'EUR', + }, + }, +} + +export const HidePublicRate: Story = { + args: { + name: 'regular', + value: 'regular', + rateTitle: 'FREE CANCELLATION', + paymentTerm: 'PAY NOW', + rate: { + label: 'Standard Price', + price: '198', + unit: 'EUR/NIGHT', + }, + memberRate: { + label: 'Member Price', + price: '190', + unit: 'EUR/NIGHT', + }, + approximateRate: { + price: '198', + label: 'Approx.', + unit: 'EUR', + }, + hidePublicRate: true, + }, +} diff --git a/packages/design-system/lib/components/RateCard/Regular/index.tsx b/packages/design-system/lib/components/RateCard/Regular/index.tsx new file mode 100644 index 000000000..d6b6bac8a --- /dev/null +++ b/packages/design-system/lib/components/RateCard/Regular/index.tsx @@ -0,0 +1,117 @@ +import { Rate } from '../types' + +import styles from '../rate-card.module.css' +import { Typography } from '../../Typography' +import { Button } from '../../Button' +import InfoCircleIcon from '../../Icons/InfoCircle' +import CheckCircleIcon from '../../Icons/CheckCircle' +import { variants } from '../variants' + +interface RegularRateCardProps { + name: string + value: string + isSelected: boolean + rateTitle: string + paymentTerm: string + rate?: Rate + memberRate?: Rate + approximateRate: Rate + hidePublicRate?: boolean + handleChange: () => void + handleTermsClick?: () => void +} + +export default function RegularRateCard({ + name, + value, + isSelected, + rateTitle, + paymentTerm, + approximateRate, + rate, + memberRate, + hidePublicRate, + handleChange, + handleTermsClick, +}: RegularRateCardProps) { + const classNames = variants({ variant: 'Regular' }) + return ( + + ) +} diff --git a/packages/design-system/lib/components/RateCard/index.tsx b/packages/design-system/lib/components/RateCard/index.tsx deleted file mode 100644 index d516a7c17..000000000 --- a/packages/design-system/lib/components/RateCard/index.tsx +++ /dev/null @@ -1 +0,0 @@ -export { RateCard } from './RateCard' diff --git a/packages/design-system/lib/components/RateCard/rate-card.module.css b/packages/design-system/lib/components/RateCard/rate-card.module.css index 023899390..233a79aac 100644 --- a/packages/design-system/lib/components/RateCard/rate-card.module.css +++ b/packages/design-system/lib/components/RateCard/rate-card.module.css @@ -1,8 +1,49 @@ +.radio { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border: 0; +} + +.checkIcon { + --size: 24px; + width: var(--size); + height: var(--size); + + position: absolute; + top: -10px; + right: -10px; + + background-color: var(--Surface-UI-Fill-Active-Hover); + border-radius: 50%; + color: var(--Scandic-Blue-70); + display: none; +} + .rateCard { + position: relative; background-color: var(--Scandic-Grey-00); border-radius: var(--Corner-radius-md); } +.rateCard:hover { + cursor: pointer; + background-color: var(--Scandic-Grey-10); +} + +.radio:checked ~ .rateCard { + border: 1px solid var(--Scandic-Peach-80, 'black'); +} + +.radio:checked ~ .rateCard .checkIcon { + display: initial; +} + .banner { background-color: var(--Surface-Brand-Primary-1-OnSurface-Accent); border-top-left-radius: var(--Corner-radius-md); @@ -51,6 +92,10 @@ color: var(--Text-Secondary); } +.textDisabled { + color: var(--Text-Interactive-Disabled); +} + .comparisonRate { color: var(--Text-Secondary); display: flex; @@ -92,20 +137,33 @@ background-color: var(--Surface-Brand-Primary-1-Default); } +.variant-campaign:hover { + background-color: var(--Scandic-Peach-20); +} + .variant-campaign .banner { background-color: var(--Surface-Brand-Primary-1-OnSurface-Accent); } .variant-code { - background: var(--Surface-Feedback-Information); + background-color: var(--Surface-Feedback-Information); +} + +.variant-code:hover { + background-color: var(--Scandic-Blue-10); } .variant-code .banner { background-color: var(--Surface-Feedback-Information-Accent); } +.variant-points:hover { + background-color: var(--Scandic-Grey-00); + cursor: default; +} + .variant-points .banner { - background: var(--Surface-Brand-Primary-1-OnSurface-Accent-Secondary); + background-color: var(--Surface-Brand-Primary-1-OnSurface-Accent-Secondary); } .footer { @@ -118,3 +176,16 @@ align-items: center; color: var(--Scandic-Blue-70); } + +.noPricesAvailableContainer { + display: flex; + justify-content: center; + align-items: center; + padding: var(--Space-x2) 0; +} + +.noPricesAvailableText { + padding: var(--Space-x15) var(--Space-x3); + border-radius: var(--Corner-radius-rounded); + background-color: var(--Scandic-Beige-10); +} diff --git a/packages/design-system/lib/components/RateCard/types.ts b/packages/design-system/lib/components/RateCard/types.ts index ca5eabed3..2a112fd66 100644 --- a/packages/design-system/lib/components/RateCard/types.ts +++ b/packages/design-system/lib/components/RateCard/types.ts @@ -8,10 +8,10 @@ export type RatePointsOption = { points: string currency: string isDisabled?: boolean - additionalCurrency?: AdditionalCurrency + additionalPrice?: AdditionalPrice } -type AdditionalCurrency = { +type AdditionalPrice = { price: string currency: string } diff --git a/packages/design-system/package.json b/packages/design-system/package.json index 5c4a5cdab..e2c2a6053 100644 --- a/packages/design-system/package.json +++ b/packages/design-system/package.json @@ -11,7 +11,11 @@ "./Chips": "./dist/components/Chips/index.js", "./Icons": "./dist/components/Icons/index.js", "./Typography": "./dist/components/Typography/index.js", - "./RateCard": "./dist/components/RateCard/index.js", + "./RegularRateCard": "./dist/components/RateCard/Regular/index.js", + "./CampaignRateCard": "./dist/components/RateCard/Campaign/index.js", + "./CodeRateCard": "./dist/components/RateCard/Code/index.js", + "./PointsRateCard": "./dist/components/RateCard/Points/index.js", + "./NoRateAvailableCard": "./dist/components/RateCard/NoRateAvailable/index.js", "./style.css": "./dist/style.css", "./base.css": "./dist/base.css", "./globals.css": "./dist/globals.css",