From 653cccaddb548853b74ec2d0b4c058819a74c410 Mon Sep 17 00:00:00 2001 From: Arvid Norlin Date: Fri, 24 May 2024 14:04:54 +0200 Subject: [PATCH 01/10] feat: add more generic Select component --- .../DynamicContent/OverviewTable/index.tsx | 67 ++++++---------- .../TempDesignSystem/Form/Select/index.tsx | 79 +++++++++++++++++++ .../Form/Select/select.module.css | 57 +++++++++++++ .../TempDesignSystem/Form/Select/select.ts | 11 +++ 4 files changed, 169 insertions(+), 45 deletions(-) create mode 100644 components/TempDesignSystem/Form/Select/index.tsx create mode 100644 components/TempDesignSystem/Form/Select/select.module.css create mode 100644 components/TempDesignSystem/Form/Select/select.ts diff --git a/components/Loyalty/Blocks/DynamicContent/OverviewTable/index.tsx b/components/Loyalty/Blocks/DynamicContent/OverviewTable/index.tsx index dfc89237f..796733837 100644 --- a/components/Loyalty/Blocks/DynamicContent/OverviewTable/index.tsx +++ b/components/Loyalty/Blocks/DynamicContent/OverviewTable/index.tsx @@ -1,6 +1,7 @@ "use client" import { Fragment, useState } from "react" +import { type Key } from "react-aria-components" import { Minus } from "react-feather" import { Lang } from "@/constants/languages" @@ -9,6 +10,7 @@ import { _ } from "@/lib/translation" import CheckCircle from "@/components/Icons/CheckCircle" import ChevronDown from "@/components/Icons/ChevronDown" import Image from "@/components/Image" +import Select from "@/components/TempDesignSystem/Form/Select" import Title from "@/components/Title" import levelsData from "./data/EN.json" @@ -114,16 +116,18 @@ export default function OverviewTable() { const [selectedLevelB, setSelectedLevelB] = useState(getLevelByTier(2)) // TODO Come up with a nice wat to make these two a single reusable function - function handleSelectChangeA(event: React.ChangeEvent) { - const tier = parseInt(event.target.value) - const level = getLevelByTier(tier) - setSelectedLevelA(level) + function handleSelectChangeA(key: Key) { + if (typeof key === "number") { + const level = getLevelByTier(key) + setSelectedLevelA(level) + } } - function handleSelectChangeB(event: React.ChangeEvent) { - const tier = parseInt(event.target.value) - const level = getLevelByTier(tier) - setSelectedLevelB(level) + function handleSelectChangeB(key: Key) { + if (typeof key === "number") { + const level = getLevelByTier(key) + setSelectedLevelB(level) + } } const levelOptions = levelsData.levels.map((level) => ({ @@ -149,9 +153,11 @@ export default function OverviewTable() {
) => void -} -// TODO: replace with Select component from TempDesignSystem -function Select({ options, defaultOption, onChange }: SelectProps) { - return ( -
- - - - - -
- ) -} - function LevelSummary({ level }: LevelSummaryProps) { return (
diff --git a/components/TempDesignSystem/Form/Select/index.tsx b/components/TempDesignSystem/Form/Select/index.tsx new file mode 100644 index 000000000..95a5b4d68 --- /dev/null +++ b/components/TempDesignSystem/Form/Select/index.tsx @@ -0,0 +1,79 @@ +"use client" +import { useRef } from "react" +import { + Button, + type Key, + Label, + ListBox, + ListBoxItem, + Popover, + Select as ReactAriaSelect, + SelectValue, +} from "react-aria-components" + +import SelectChevron from "../SelectChevron" + +import styles from "./select.module.css" + +import type { SelectProps } from "./select" + +export default function Select({ + "aria-label": ariaLabel, + items, + label, + name, + onSelect, + placeholder, + value, + defaultSelectedKey, +}: SelectProps) { + const divRef = useRef(null) + + function handleOnSelect(key: Key) { + onSelect(key) + } + + return ( +
+ + + + + + {items.map((item) => ( + + {item.label} + + ))} + + + +
+ ) +} diff --git a/components/TempDesignSystem/Form/Select/select.module.css b/components/TempDesignSystem/Form/Select/select.module.css new file mode 100644 index 000000000..c1e7d1bc6 --- /dev/null +++ b/components/TempDesignSystem/Form/Select/select.module.css @@ -0,0 +1,57 @@ +.date { + position: relative; +} + +.label { + color: var(--Base-Text-UI-Placeholder); + font-family: var(--ff-fira-sans); + font-size: var(--typography-Footnote-Regular-fontSize); + font-weight: 400; + position: absolute; + left: 1.6rem; +} + +.select { + display: flex; + flex-direction: column; + gap: 0.4rem; +} + +.input { + align-items: end; + background-color: var(--some-white-color, #fff); + border: 1px solid var(--Base-Input-Controls-Border-Normal, #b8a79a); + border-radius: 0.8rem; + color: var(--some-black-color, #757575); + display: grid; + font-family: var(--ff-fira-sans); + font-size: 1.6rem; + font-weight: 400; + gap: 1rem; + grid-template-columns: 1fr auto; + height: 5.6rem; + /* letter-spacing: -1.5%; */ + line-height: 2.4rem; + padding: 0.8rem 1.6rem; +} + +.popover { + background-color: var(--some-white-color, #fff); + border: var(--border); + border-radius: var(--radius); + overflow: auto; + width: 100%; +} + +.listBox { + padding: 1.6rem 1.6rem 1.6rem 0.8rem; +} + +.listBoxItem { + padding: 0 0.8rem; +} + +.listBoxItem[data-selected="true"], +.listBoxItem[data-focused="true"] { + background-color: rgba(75, 75, 75, 0.2); +} diff --git a/components/TempDesignSystem/Form/Select/select.ts b/components/TempDesignSystem/Form/Select/select.ts new file mode 100644 index 000000000..e29fef48f --- /dev/null +++ b/components/TempDesignSystem/Form/Select/select.ts @@ -0,0 +1,11 @@ +import type { Key } from "react-aria-components" + +export interface SelectProps + extends Omit, "onSelect"> { + items: { label: string; value: Key }[] + label: string + name: string + onSelect: (key: Key) => void + placeholder?: string + defaultSelectedKey: Key +} From 52b927b684ea4033fe7030e397de7d27e7480feb Mon Sep 17 00:00:00 2001 From: Arvid Norlin Date: Fri, 24 May 2024 15:23:29 +0200 Subject: [PATCH 02/10] extract BenefitCard component --- .../OverviewTable/BenefitCard.tsx | 64 +++++++++++++++ .../DynamicContent/OverviewTable/index.tsx | 81 +++---------------- 2 files changed, 76 insertions(+), 69 deletions(-) create mode 100644 components/Loyalty/Blocks/DynamicContent/OverviewTable/BenefitCard.tsx diff --git a/components/Loyalty/Blocks/DynamicContent/OverviewTable/BenefitCard.tsx b/components/Loyalty/Blocks/DynamicContent/OverviewTable/BenefitCard.tsx new file mode 100644 index 000000000..256f205d3 --- /dev/null +++ b/components/Loyalty/Blocks/DynamicContent/OverviewTable/BenefitCard.tsx @@ -0,0 +1,64 @@ +import { ChevronDown, Minus } from "react-feather" + +import CheckCircle from "@/components/Icons/CheckCircle" +import Title from "@/components/Title" + +import styles from "./overviewTable.module.css" + +import { + BenefitCardProps, + BenefitValueProps, +} from "@/types/components/loyalty/blocks" + +function BenefitValue({ benefit }: BenefitValueProps) { + if (!benefit.unlocked) { + return + } + if (!benefit.value) { + return + } + return ( +
+ {benefit.value} + {benefit.valueDetails && ( + + {benefit.valueDetails} + + )} +
+ ) +} + +export default function BenefitCard({ + comparedValues, + title, + description, +}: BenefitCardProps) { + return ( +
+
+
+ +
+ + {title} + + + + +
+
+

{description}

+
+
+
+
+ +
+
+ +
+
+
+ ) +} diff --git a/components/Loyalty/Blocks/DynamicContent/OverviewTable/index.tsx b/components/Loyalty/Blocks/DynamicContent/OverviewTable/index.tsx index 796733837..fbe937b7a 100644 --- a/components/Loyalty/Blocks/DynamicContent/OverviewTable/index.tsx +++ b/components/Loyalty/Blocks/DynamicContent/OverviewTable/index.tsx @@ -1,25 +1,21 @@ "use client" -import { Fragment, useState } from "react" +import { Dispatch, Fragment, SetStateAction, useState } from "react" import { type Key } from "react-aria-components" -import { Minus } from "react-feather" import { Lang } from "@/constants/languages" import { _ } from "@/lib/translation" -import CheckCircle from "@/components/Icons/CheckCircle" -import ChevronDown from "@/components/Icons/ChevronDown" import Image from "@/components/Image" import Select from "@/components/TempDesignSystem/Form/Select" import Title from "@/components/Title" import levelsData from "./data/EN.json" +import BenefitCard from "./BenefitCard" import styles from "./overviewTable.module.css" import { - BenefitCardProps, - BenefitValueProps, ComparisonLevel, LevelSummaryProps, OverviewTableTitleProps, @@ -115,18 +111,14 @@ export default function OverviewTable() { const [selectedLevelA, setSelectedLevelA] = useState(getLevelByTier(1)) const [selectedLevelB, setSelectedLevelB] = useState(getLevelByTier(2)) - // TODO Come up with a nice wat to make these two a single reusable function - function handleSelectChangeA(key: Key) { - if (typeof key === "number") { - const level = getLevelByTier(key) - setSelectedLevelA(level) - } - } - - function handleSelectChangeB(key: Key) { - if (typeof key === "number") { - const level = getLevelByTier(key) - setSelectedLevelB(level) + function handleSelectChange( + callback: Dispatch> + ) { + return (key: Key) => { + if (typeof key === "number") { + const level = getLevelByTier(key) + callback(level) + } } } @@ -157,7 +149,7 @@ export default function OverviewTable() { label={"Level"} items={levelOptions} defaultSelectedKey={selectedLevelA.tier} - onSelect={handleSelectChangeA} + onSelect={handleSelectChange(setSelectedLevelA)} /> ) } - -function BenefitCard({ comparedValues, title, description }: BenefitCardProps) { - return ( -
-
-
- -
- - {title} - - - - -
-
-

{description}

-
-
-
-
- -
-
- -
-
-
- ) -} - -function BenefitValue({ benefit }: BenefitValueProps) { - if (!benefit.unlocked) { - return - } - if (!benefit.value) { - return - } - return ( -
- {benefit.value} - {benefit.valueDetails && ( - - {benefit.valueDetails} - - )} -
- ) -} From 7b206947bcf1de7e7d53457b771a144400be365b Mon Sep 17 00:00:00 2001 From: Arvid Norlin Date: Mon, 27 May 2024 10:09:05 +0200 Subject: [PATCH 03/10] feat: add markup for additional viewport sizes --- components/ContentType/LoyaltyPage.tsx | 8 +- components/ContentType/loyaltyPage.module.css | 5 +- .../DynamicContent/OverviewTable/index.tsx | 151 ++++++++++++------ .../OverviewTable/overviewTable.module.css | 62 ++++++- 4 files changed, 173 insertions(+), 53 deletions(-) diff --git a/components/ContentType/LoyaltyPage.tsx b/components/ContentType/LoyaltyPage.tsx index a7e3d07ad..f66940761 100644 --- a/components/ContentType/LoyaltyPage.tsx +++ b/components/ContentType/LoyaltyPage.tsx @@ -8,10 +8,12 @@ import styles from "./loyaltyPage.module.css" export default async function LoyaltyPage() { const loyaltyPage = await serverClient().contentstack.loyaltyPage.get() - + const hasSidebar = !!loyaltyPage.sidebar.length return ( -
- {loyaltyPage.sidebar ? : null} +
+ {hasSidebar && } {loyaltyPage.blocks ? : null} diff --git a/components/ContentType/loyaltyPage.module.css b/components/ContentType/loyaltyPage.module.css index d6b3c2533..54d62222f 100644 --- a/components/ContentType/loyaltyPage.module.css +++ b/components/ContentType/loyaltyPage.module.css @@ -13,9 +13,12 @@ } @media screen and (min-width: 950px) { + .withLeftSidebar { + grid-template-columns: 30rem 1fr; + } + .content { gap: 2.7rem; - grid-template-columns: 30rem 1fr; padding-bottom: 17.5rem; padding-left: 2.4rem; padding-right: 2.4rem; diff --git a/components/Loyalty/Blocks/DynamicContent/OverviewTable/index.tsx b/components/Loyalty/Blocks/DynamicContent/OverviewTable/index.tsx index fbe937b7a..9317e11e1 100644 --- a/components/Loyalty/Blocks/DynamicContent/OverviewTable/index.tsx +++ b/components/Loyalty/Blocks/DynamicContent/OverviewTable/index.tsx @@ -128,57 +128,114 @@ export default function OverviewTable() { })) return ( -
-
- -

- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do - eiusmod tempor incididunt ut labore et dolore magna aliqua. Arcu risus - quis varius quam quisque id diam vel. Rhoncus urna neque viverra - justo. Mattis aliquam faucibus purus in massa. Id cursus metus aliquam - eleifend mi in nulla posuere. -

-
-
-
-
-
-
- + level.tier === selectedLevelA.tier + ) as ComparisonLevel + } + /> +
+
+ - level.tier === selectedLevelB.tier - ) as ComparisonLevel - } - /> + {createComparison(selectedLevelA, selectedLevelB)} +
+
+
+
+
+
+
+ + level.tier === selectedLevelB.tier + ) as ComparisonLevel + } + /> +
+
+
- level.tier === selectedLevelA.tier - ) as ComparisonLevel - } - /> -
-
- - level.tier === selectedLevelA.tier - ) as ComparisonLevel - } - /> -
-
- - level.tier === selectedLevelC.tier - ) as ComparisonLevel - } - /> -
-
- -
+
+
+ +

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do + eiusmod tempor incididunt ut labore et dolore magna aliqua. Arcu risus + quis varius quam quisque id diam vel. Rhoncus urna neque viverra + justo. Mattis aliquam faucibus purus in massa. Id cursus metus aliquam + eleifend mi in nulla posuere. +

- +
+
+
+ + level.tier === selectedLevelB.tier + ) as ComparisonLevel + } + /> +
+
+ +
+
+
+
+ + level.tier === selectedLevelB.tier + ) as ComparisonLevel + } + /> +
+
+