Skip to content

Commit 372e21b

Browse files
committed
Refactor PricingAddons component to improve layout and add singular unit labels for better clarity
Signed-off-by: Lee Calcote <lee.calcote@layer5.io>
1 parent d3d90d3 commit 372e21b

3 files changed

Lines changed: 102 additions & 41 deletions

File tree

src/components/Pricing/PlanCard/planCard.style.js

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,11 +233,29 @@ const PlanCardWrapper = styled.section`
233233
color: ${(props) => props.theme.text.light};
234234
border: 1px solid;
235235
border-color: ${(props) => props.theme.secondaryColor};
236-
236+
min-width: 40%;
237+
justify-content: flex-start;
238+
display: flex;
237239
}
238240
.addon-chip .MuiChip-icon {
239241
color: ${(props) => props.theme.secondaryColor};
242+
line-height: 1rem;
243+
}
244+
245+
.MuiTypography-root {
246+
font-family: "Qanelas Soft", "Open Sans", sans-serif;
240247
}
248+
.MuiSlider-root {
249+
"& .MuiSlider-mark": {
250+
fontSize: "12px",
251+
color: ${(props) => props.theme.text.light};
252+
},
253+
"& .MuiSlider-markLabel": {
254+
fontSize: "12px",
255+
color: ${(props) => props.theme.secondaryColor};
256+
},
257+
}
258+
});
241259
`;
242260

243261
export default PlanCardWrapper;

src/components/Pricing/PricingAddons/index.js

Lines changed: 77 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -269,15 +269,18 @@ export const PricingAddons = ({ isYearly = false, setIsYearly }) => {
269269

270270
{selectedAddon?.id === "academy" && (
271271
<>
272-
<Box className="pricing-features" sx={{ marginTop: "-1rem" }}>
273-
<Box className="feature" sx={{ display: "flex", alignContent: "center", justifyContent: "space-evenly", flexWrap: "nowrap", gap: 1 }}>
272+
<Box className="pricing-features">
273+
<Typography variant="h6" sx={{ marginBottom: 2, marginTop: -2 }}>
274+
Add-On Features
275+
</Typography>
276+
<Box className="feature" sx={{ display: "flex", alignContent: "center", justifyContent: "flex-start", flexWrap: "nowrap", gap: 1 }}>
274277
<FormControlLabel
275278
key="academy-theory"
276279
control={<Switch disabled
277280
checked={selectedSubAddOns["academy-theory"] || false}
278281
onChange={(e) => handleSubAddOnToggle("academy-theory", e.target.checked)}
279282
color="primary" />}
280-
sx={{ display: "block", alignContent: "flex-start", padding: 0, margin: 0 }}
283+
sx={{ display: "flex", justifySelf: "flex-end", marginRight: -1, marginTop: "-0.5rem", marginLeft: 1, padding: 0, alignItems: "flex-start" }}
281284
/>
282285
<FeatureDetails
283286
sx={{ display: "flex", flexDirection: "row", flexWrap: "wrap" }}
@@ -288,69 +291,89 @@ export const PricingAddons = ({ isYearly = false, setIsYearly }) => {
288291
{selectedAddon?.subAddOns?.find(sub => sub.id === "academy-theory")?.features?.map((feature, index) => (
289292
<Chip
290293
key={`theory-${index}`}
291-
icon={<CheckCircle sx={{ fontSize: 12 }} />}
294+
icon={<CheckCircle />}
292295
label={feature}
293-
size="small"
294-
sx={{
295-
backgroundColor: "transparent",
296-
color: "text.primary",
297-
width: "fit-content",
298-
"& .MuiChip-icon": { color: "primary.main" },
299-
}} />
296+
size="large"
297+
className="addon-chip"
298+
/>
300299
))}
301300
</Box>
302301
</FeatureDetails>
303302
</Box>
304-
<Box className="feature" sx={{ display: "flex", flexWrap: "nowrap", alignItems: "flex-start", gap: 1 }}>
303+
<Box className="feature" sx={{ display: "flex", flexWrap: "nowrap", justifyContent: "flex-end", alignItems: "flex-start", gap: 1, }}>
305304
<FormControlLabel
306305
key="academy-practical"
307-
control={<Switch sx={{ margin: 0, display: "flex", gap: 1, alignSelf: "flex-start" }}
308-
checked={selectedSubAddOns["academy-practical"] || false}
309-
onChange={(e) => handleSubAddOnToggle("academy-practical", e.target.checked)}
310-
color="primary" />}
311-
sx={{ display: "block", alignContent: "flex-start" }}
306+
control={<Switch sx={{ margin: 0, display: "flex", gap: 1, alignSelf: "flex-end" }}
307+
checked={selectedSubAddOns["academy-practical"] || false}
308+
onChange={(e) => handleSubAddOnToggle("academy-practical", e.target.checked)}
309+
color="primary" />}
310+
sx={{ display: "flex", justifySelf: "flex-end", marginRight: -1, marginTop: "-0.5rem", marginLeft: 1, padding: 0, alignItems: "flex-start" }}
312311
/>
313312
<FeatureDetails
314313
category="Practical Learning"
315314
description="An inclusive, collaborative, hands-on learning environment powered by Kanvas with labs for students."
316315
>
317-
<Box sx={{ display: "flex", flexWrap: "wrap", gap: 1, my: 1, mt: 1 }}>
316+
<Box sx={{ display: "flex", flexWrap: "wrap", gap: 1, my: .5, mt: 1 }}>
318317
{selectedAddon?.subAddOns?.find(sub => sub.id === "academy-practical")?.features?.map((feature, index) => (
319318
<Chip
320319
key={`practical-${index}`}
321-
icon={<CheckCircle sx={{ fontSize: 12 }} />}
320+
icon={<CheckCircle />}
322321
label={feature}
323-
size="small"
324-
sx={{
325-
backgroundColor: "transparent",
326-
color: "text.primary",
327-
"& .MuiChip-icon": { color: "primary.main" },
328-
}} />
322+
size="large"
323+
className="addon-chip"
324+
/>
329325
))}
330326
</Box>
331327
</FeatureDetails>
332328
</Box>
333329
</Box>
334330

335331
<Box sx={{ display: "flex", justifyContent: "center", flexWrap: "wrap", gap: 1, mt: 2 }}>
336-
<Typography variant="h6" sx={{ justifySelf: "center", textAlign: "center", width: "100%", fontFamily: "\"Qanelas Soft\", \"Open Sans\", sans-serif" }}>Learners</Typography>
332+
<Typography variant="h6" sx={{ justifySelf: "center", textAlign: "center", width: "100%", fontFamily: "\"Qanelas Soft\", \"Open Sans\", sans-serif" }}>
333+
{(() => {
334+
// Determine which sub-addon to show learner count for
335+
let targetSubAddon = null;
336+
if (selectedSubAddOns["academy-practical"]) {
337+
targetSubAddon = selectedAddon?.subAddOns?.find(sub => sub.id === "academy-practical");
338+
} else {
339+
targetSubAddon = selectedAddon?.subAddOns?.find(sub => sub.id === "academy-theory");
340+
}
341+
return targetSubAddon?.pricing?.[quantityIndex]?.learners || 0;
342+
})()} Learners
343+
</Typography>
337344
<Slider
338345
value={quantityIndex}
339346
onChange={(event, newValue) => setQuantityIndex(newValue)}
340347
min={0}
341348
valueLabelDisplay="auto"
342349
valueLabelFormat={(value) => {
343-
const theorySubAddon = selectedAddon?.subAddOns?.find(sub => sub.id === "academy-theory");
344-
if (theorySubAddon?.pricing && theorySubAddon.pricing[value]) {
345-
const option = theorySubAddon.pricing[value];
350+
// Determine which sub-addon to show pricing for
351+
let targetSubAddon = null;
352+
if (selectedSubAddOns["academy-practical"]) {
353+
targetSubAddon = selectedAddon?.subAddOns?.find(sub => sub.id === "academy-practical");
354+
} else {
355+
targetSubAddon = selectedAddon?.subAddOns?.find(sub => sub.id === "academy-theory");
356+
}
357+
358+
if (targetSubAddon?.pricing && targetSubAddon.pricing[value]) {
359+
const option = targetSubAddon.pricing[value];
346360
const pricePerUser = isYearly ? option.yearlyPerUser : option.monthlyPerUser;
347361
const totalPrice = pricePerUser * option.learners;
348362
const period = isYearly ? "/year" : "/month";
349363
return `${option.learners} learners - ${formatPrice(totalPrice)}${period}`;
350364
}
351365
return "";
352366
}}
353-
max={selectedAddon?.subAddOns?.find(sub => sub.id === "academy-theory")?.pricing?.length - 1 || 0}
367+
max={(() => {
368+
// Determine which sub-addon to use for max value
369+
let targetSubAddon = null;
370+
if (selectedSubAddOns["academy-practical"]) {
371+
targetSubAddon = selectedAddon?.subAddOns?.find(sub => sub.id === "academy-practical");
372+
} else {
373+
targetSubAddon = selectedAddon?.subAddOns?.find(sub => sub.id === "academy-theory");
374+
}
375+
return (targetSubAddon?.pricing?.length - 1) || 0;
376+
})()}
354377
step={null}
355378
sx={{
356379
mb: 2,
@@ -375,18 +398,32 @@ export const PricingAddons = ({ isYearly = false, setIsYearly }) => {
375398
fontFamily: "\"Qanelas Soft\", \"Open Sans\", sans-serif",
376399
},
377400
}}
378-
marks={selectedAddon?.subAddOns?.find(sub => sub.id === "academy-theory")?.pricing?.map((option, index) => ({
379-
value: index,
380-
label: (
381-
<Box sx={{ textAlign: "center", fontSize: "1.25rem" }}>
382-
<Box>{option.learners === "2500+" ? "2,500+" : option.learners}</Box>
383-
</Box>
384-
),
385-
})) || []}
401+
marks={(() => {
402+
// Determine which sub-addon to show pricing for based on selection
403+
let targetSubAddon = null;
404+
if (selectedSubAddOns["academy-practical"]) {
405+
targetSubAddon = selectedAddon?.subAddOns?.find(sub => sub.id === "academy-practical");
406+
} else {
407+
targetSubAddon = selectedAddon?.subAddOns?.find(sub => sub.id === "academy-theory");
408+
}
409+
410+
return targetSubAddon?.pricing?.map((option, index) => ({
411+
value: index,
412+
label: (
413+
<Box sx={{ textAlign: "center", fontSize: "1.25rem" }}>
414+
415+
<Box>{option.learners === "2500+" ? "2,500+" : option.learners}</Box>
416+
<Box sx={{ color: "primary.main", mb: 1.5, fontSize: ".9rem" }}>
417+
{option.currency}{isYearly ? option.yearlyPerUser : option.monthlyPerUser}/{targetSubAddon.unitLabelSingular}/{isYearly ? "year" : "month"}
418+
</Box>
419+
</Box>
420+
),
421+
})) || [];
422+
})()}
386423
/>
387-
<Box sx={{ display: "flex", my: 2, justifyContent: "space-between" }}>
424+
<Box sx={{ display: "flex", my: 5, justifyContent: "space-between" }}>
388425
<Typography variant="body2" sx={{ fontStyle: "italic", color: "text.secondary", fontFamily: "\"Qanelas Soft\", \"Open Sans\", sans-serif" }}>
389-
Looking for a plan larger than 2,500 learners? Great! <Link to="/company/contact">Let us know</Link>.
426+
Looking for a plan larger than 2,500 learners? Great! <a href="/company/contact">Let us know</a>.
390427
</Typography>
391428
</Box>
392429
</Box>

src/components/Pricing/PricingAddons/pricingData.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ export const getAddOns = (theme) => [
2525
secondaryFill={theme?.palette?.background?.inverse || "#eee"}
2626
/>,
2727
unitLabel: "learners",
28+
unitLabelSingular: "learner",
2829
maxUnits: 5000,
2930
// features: ["Learning Paths", "Challenges", "Certifications", "Instructor Console"],
3031
subAddOns: [
@@ -33,6 +34,7 @@ export const getAddOns = (theme) => [
3334
name: "Theoretical Learning",
3435
description: "A comprehensive learning management system for creators and instructors on how to build, manage, and extend educational content like learning paths, challenges, and certifications.",
3536
unitLabel: "learners",
37+
unitLabelSingular: "learner",
3638
maxUnits: 5000,
3739
pricing: [
3840
{ learners: 250, monthlyPerUser: 1.29, yearlyPerUser: 1.05, currency: "$" },
@@ -57,6 +59,8 @@ export const getAddOns = (theme) => [
5759
name: "Practical Learning",
5860
description: "An inclusive, collaborative, hands-on learning environment with labs for students.",
5961
maxUnits: 5000,
62+
unitLabel: "learners",
63+
unitLabelSingular: "learner",
6064
pricing: [
6165
{ learners: 250, monthlyPerUser: 1.29, yearlyPerUser: 1.05, currency: "$" },
6266
{ learners: 500, monthlyPerUser: 0.80, yearlyPerUser: 0.67, currency: "$" },
@@ -84,6 +88,7 @@ export const getAddOns = (theme) => [
8488
yearlyPrice: 653, // ~15% discount for yearly
8589
icon: <Cloud sx={{ color: theme?.palette?.background?.inverse || "#FFFFFF" }} />,
8690
unitLabel: "servers",
91+
unitLabelSingular: "server",
8792
maxUnits: 50,
8893
pricing: [
8994
{ units: 1, monthlyPerUnit: 64, yearlyPerUnit: 54.40, currency: "$" },
@@ -100,6 +105,7 @@ export const getAddOns = (theme) => [
100105
yearlyPrice: 15.30, // ~15% discount for yearly
101106
icon: <Group sx={{ color: theme?.palette?.background?.inverse || "#00B39F" }} />,
102107
unitLabel: "collaborators",
108+
unitLabelSingular: "collaborator",
103109
maxUnits: 200,
104110
pricing: [
105111
{ units: 1, monthlyPerUnit: 2, yearlyPerUnit: 1.70, currency: "$" },

0 commit comments

Comments
 (0)