Skip to content

Commit f56398d

Browse files
authored
Merge pull request #14229 from guardian/tf-choice-cards-refactor
refactor choice cards
2 parents 08af564 + 5eec6ac commit f56398d

File tree

2 files changed

+91
-117
lines changed

2 files changed

+91
-117
lines changed

dotcom-rendering/src/components/marketing/banners/designableBanner/DesignableBanner.tsx

Lines changed: 14 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ import type {
2323
Image,
2424
} from '@guardian/support-dotcom-components/dist/shared/types';
2525
import type { ChoiceCard } from '@guardian/support-dotcom-components/dist/shared/types/props/choiceCards';
26-
import type { Dispatch, SetStateAction } from 'react';
2726
import { useEffect, useState } from 'react';
2827
import {
2928
removeMediaRulePrefix,
@@ -111,16 +110,16 @@ const buildChoiceCardSettings = (
111110

112111
const buildUrlForThreeTierChoiceCards = (
113112
baseUrl: string,
114-
selectedProduct: ChoiceCard['product'],
115-
destinationUrl?: string | null,
113+
selectedChoiceCard: ChoiceCard,
116114
) => {
115+
const { destinationUrl, product } = selectedChoiceCard;
117116
const url = destinationUrl?.trim() ?? baseUrl;
118-
return selectedProduct.supportTier === 'OneOff'
117+
return product.supportTier === 'OneOff'
119118
? url
120119
: addChoiceCardsProductParams(
121120
url,
122-
selectedProduct.supportTier,
123-
selectedProduct.ratePlan,
121+
product.supportTier,
122+
product.ratePlan,
124123
);
125124
};
126125

@@ -164,27 +163,10 @@ const DesignableBanner: ReactComponent<BannerRenderProps> = ({
164163

165164
const choiceCards = getChoiceCards(isTabletOrAbove, choiceCardsSettings);
166165
const defaultChoiceCard = choiceCards?.find((cc) => cc.isDefault);
167-
const defaultProduct = defaultChoiceCard?.product;
168-
const [destinationUrl, setDestinationUrl] = useState<string | null>(
169-
defaultChoiceCard?.destinationUrl ?? null,
170-
);
171-
const [
172-
threeTierChoiceCardSelectedProduct,
173-
setThreeTierChoiceCardSelectedProduct,
174-
] = useState<ChoiceCard['product'] | undefined>(defaultProduct);
175-
176-
const setSelectedProduct: Dispatch<
177-
SetStateAction<ChoiceCard['product'] | undefined>
178-
> = (product) => {
179-
setThreeTierChoiceCardSelectedProduct(product);
180-
const choiceCard = choiceCards?.find(
181-
(choiceCardItem) =>
182-
typeof product === 'object' &&
183-
'supportTier' in product &&
184-
choiceCardItem.product.supportTier === product.supportTier,
185-
);
186-
setDestinationUrl(choiceCard?.destinationUrl ?? null);
187-
};
166+
167+
const [selectedChoiceCard, setSelectedChoiceCard] = useState<
168+
ChoiceCard | undefined
169+
>(defaultChoiceCard);
188170

189171
// We can't render anything without a design
190172
if (!design) {
@@ -399,7 +381,7 @@ const DesignableBanner: ReactComponent<BannerRenderProps> = ({
399381
</div>
400382
)}
401383

402-
{!threeTierChoiceCardSelectedProduct && (
384+
{!selectedChoiceCard && (
403385
<div css={styles.outerImageCtaContainer}>
404386
<div css={styles.innerImageCtaContainer}>
405387
<DesignableBannerCtas
@@ -425,14 +407,12 @@ const DesignableBanner: ReactComponent<BannerRenderProps> = ({
425407
</div>
426408

427409
{choiceCards &&
428-
threeTierChoiceCardSelectedProduct &&
410+
selectedChoiceCard &&
429411
mainOrMobileContent.primaryCta && (
430412
<div css={styles.threeTierChoiceCardsContainer}>
431413
<ThreeTierChoiceCards
432-
selectedProduct={
433-
threeTierChoiceCardSelectedProduct
434-
}
435-
setSelectedProduct={setSelectedProduct}
414+
selectedChoiceCard={selectedChoiceCard}
415+
setSelectedChoiceCard={setSelectedChoiceCard}
436416
choices={choiceCards}
437417
id={'banner'}
438418
/>
@@ -441,8 +421,7 @@ const DesignableBanner: ReactComponent<BannerRenderProps> = ({
441421
<LinkButton
442422
href={buildUrlForThreeTierChoiceCards(
443423
mainOrMobileContent.primaryCta.ctaUrl,
444-
threeTierChoiceCardSelectedProduct,
445-
destinationUrl,
424+
selectedChoiceCard,
446425
)}
447426
onClick={onCtaClick}
448427
priority="tertiary"

dotcom-rendering/src/components/marketing/shared/ThreeTierChoiceCards.tsx

Lines changed: 77 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -148,17 +148,15 @@ const ChoiceCardPill = ({
148148
};
149149

150150
type ThreeTierChoiceCardsProps = {
151-
selectedProduct: ChoiceCard['product'];
152-
setSelectedProduct: Dispatch<
153-
SetStateAction<ChoiceCard['product'] | undefined>
154-
>;
151+
selectedChoiceCard: ChoiceCard;
152+
setSelectedChoiceCard: Dispatch<SetStateAction<ChoiceCard | undefined>>;
155153
choices: ChoiceCard[];
156154
id: string; // uniquely identify this choice cards component to avoid conflicting with others
157155
};
158156

159157
export const ThreeTierChoiceCards = ({
160-
selectedProduct,
161-
setSelectedProduct,
158+
selectedChoiceCard,
159+
setSelectedChoiceCard,
162160
choices,
163161
id,
164162
}: ThreeTierChoiceCardsProps) => {
@@ -169,88 +167,85 @@ export const ThreeTierChoiceCards = ({
169167
`}
170168
>
171169
<Stack space={3}>
172-
{choices.map(
173-
({ product, label, benefitsLabel, benefits, pill }) => {
174-
const { supportTier } = product;
175-
176-
const isSelected = (): boolean => {
170+
{choices.map((card) => {
171+
const { product, label, benefitsLabel, benefits, pill } =
172+
card;
173+
const { supportTier } = product;
174+
175+
const isSelected = (): boolean => {
176+
if (
177+
product.supportTier ===
178+
selectedChoiceCard.product.supportTier
179+
) {
177180
if (
178-
product.supportTier ===
179-
selectedProduct.supportTier
181+
product.supportTier !== 'OneOff' &&
182+
selectedChoiceCard.product.supportTier !==
183+
'OneOff'
180184
) {
181-
if (
182-
product.supportTier !== 'OneOff' &&
183-
selectedProduct.supportTier !== 'OneOff'
184-
) {
185-
return (
186-
product.ratePlan ===
187-
selectedProduct.ratePlan
188-
);
189-
} else {
190-
return true;
191-
}
185+
return (
186+
product.ratePlan ===
187+
selectedChoiceCard.product.ratePlan
188+
);
192189
} else {
193-
return false;
190+
return true;
194191
}
195-
};
196-
const selected = isSelected();
197-
198-
// Each radioId must be unique to the component and choice, e.g. "choicecard-epic-Contribution-Monthly"
199-
const radioId = `choicecard-${id}-${supportTier}${
200-
supportTier !== 'OneOff'
201-
? `-${product.ratePlan}`
202-
: ''
203-
}`;
204-
205-
return (
206-
<div
207-
key={supportTier}
208-
css={css`
209-
position: relative;
210-
background-color: inherit;
211-
`}
192+
} else {
193+
return false;
194+
}
195+
};
196+
const selected = isSelected();
197+
198+
// Each radioId must be unique to the component and choice, e.g. "choicecard-epic-Contribution-Monthly"
199+
const radioId = `choicecard-${id}-${supportTier}${
200+
supportTier !== 'OneOff' ? `-${product.ratePlan}` : ''
201+
}`;
202+
203+
return (
204+
<div
205+
key={supportTier}
206+
css={css`
207+
position: relative;
208+
background-color: inherit;
209+
`}
210+
>
211+
{pill && <ChoiceCardPill pill={pill} />}
212+
<label
213+
css={supportTierChoiceCardStyles(selected)}
214+
htmlFor={radioId}
212215
>
213-
{pill && <ChoiceCardPill pill={pill} />}
214-
<label
215-
css={supportTierChoiceCardStyles(selected)}
216-
htmlFor={radioId}
217-
>
218-
<Radio
219-
label={
220-
<span
221-
dangerouslySetInnerHTML={{
222-
__html: sanitise(label),
223-
}}
216+
<Radio
217+
label={
218+
<span
219+
dangerouslySetInnerHTML={{
220+
__html: sanitise(label),
221+
}}
222+
/>
223+
}
224+
id={radioId}
225+
value={radioId}
226+
cssOverrides={labelOverrideStyles(selected)}
227+
supporting={
228+
selected ? (
229+
<SupportingBenefits
230+
benefitsLabel={
231+
benefitsLabel as
232+
| string
233+
| undefined
234+
}
235+
benefits={benefits}
224236
/>
225-
}
226-
id={radioId}
227-
value={radioId}
228-
cssOverrides={labelOverrideStyles(
229-
selected,
230-
)}
231-
supporting={
232-
selected ? (
233-
<SupportingBenefits
234-
benefitsLabel={
235-
benefitsLabel as
236-
| string
237-
| undefined
238-
}
239-
benefits={benefits}
240-
/>
241-
) : undefined
242-
}
243-
checked={selected}
244-
onChange={() => {
245-
setSelectedProduct(product);
246-
}}
247-
theme={customRadioTheme}
248-
/>
249-
</label>
250-
</div>
251-
);
252-
},
253-
)}
237+
) : undefined
238+
}
239+
checked={selected}
240+
onChange={() => {
241+
setSelectedChoiceCard(card);
242+
}}
243+
theme={customRadioTheme}
244+
/>
245+
</label>
246+
</div>
247+
);
248+
})}
254249
</Stack>
255250
</RadioGroup>
256251
);

0 commit comments

Comments
 (0)