@windstream/react-shared-components 0.2.53 → 0.2.54

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,86 +1,86 @@
1
- import "@testing-library/jest-dom";
2
-
3
- import React from "react";
4
- import { AwardMarquee } from "./index";
5
- import { AwardMarqueeItem } from "./types";
6
-
7
- import { render, screen } from "@testing-library/react";
8
-
9
- const buildItems = (count: number): AwardMarqueeItem[] =>
10
- Array.from({ length: count }, (_, index) => ({
11
- iconUrl: `https://example.com/icon-${index}.png`,
12
- iconAlt: `Award ${index}`,
13
- title: `Award ${index}`,
14
- description: `Description ${index}`,
15
- }));
16
-
17
- describe("AwardMarquee", () => {
18
- it("renders award items synchronously (SSR, no hydration gate)", () => {
19
- render(<AwardMarquee items={buildItems(2)} />);
20
- expect(screen.getByText("Award 0")).toBeInTheDocument();
21
- expect(screen.getByText("Award 1")).toBeInTheDocument();
22
- });
23
-
24
- it("renders the icon with its alt text", () => {
25
- render(<AwardMarquee items={buildItems(1)} />);
26
- const icon = screen.getByAltText("Award 0") as HTMLImageElement;
27
- expect(icon).toBeInTheDocument();
28
- expect(icon.src).toContain("icon-0.png");
29
- });
30
-
31
- it("renders a static (non-animated) list when scroll is disabled", () => {
32
- const { container } = render(
33
- <AwardMarquee items={buildItems(5)} scroll={false} />
34
- );
35
- expect(container.querySelector(".animate-award-marquee")).toBeNull();
36
- });
37
-
38
- it("animates at every breakpoint when scroll is enabled with more than 3 items", () => {
39
- const { container } = render(
40
- <AwardMarquee items={buildItems(5)} scroll={true} />
41
- );
42
- expect(container.querySelector(".animate-award-marquee")).not.toBeNull();
43
- // No breakpoint split -> no mobile-only wrapper.
44
- expect(container.querySelector(".sm\\:hidden")).toBeNull();
45
- });
46
-
47
- it("renders both mobile (animated) and desktop (static) variants when scroll is enabled with 3 or fewer items", () => {
48
- const { container } = render(
49
- <AwardMarquee items={buildItems(2)} scroll={true} />
50
- );
51
- // Mobile variant animates and is hidden from >= sm.
52
- expect(container.querySelector(".sm\\:hidden")).not.toBeNull();
53
- expect(container.querySelector(".animate-award-marquee")).not.toBeNull();
54
- // Desktop variant is a static list shown only at >= sm.
55
- expect(container.querySelector(".hidden.sm\\:block")).not.toBeNull();
56
- // 2 items duplicated for the animated loop (4) + 2 in the static list.
57
- expect(screen.getAllByText("Award 0")).toHaveLength(3);
58
- });
59
-
60
- it("applies the anchorId to the wrapper in every render branch", () => {
61
- const staticView = render(
62
- <AwardMarquee
63
- items={buildItems(2)}
64
- scroll={false}
65
- anchorId="static-anchor"
66
- />
67
- );
68
- expect(staticView.container.querySelector("#static-anchor")).not.toBeNull();
69
-
70
- const animatedView = render(
71
- <AwardMarquee
72
- items={buildItems(5)}
73
- scroll={true}
74
- anchorId="animated-anchor"
75
- />
76
- );
77
- expect(
78
- animatedView.container.querySelector("#animated-anchor")
79
- ).not.toBeNull();
80
-
81
- const splitView = render(
82
- <AwardMarquee items={buildItems(2)} scroll={true} anchorId="split-anchor" />
83
- );
84
- expect(splitView.container.querySelector("#split-anchor")).not.toBeNull();
85
- });
86
- });
1
+ import "@testing-library/jest-dom";
2
+
3
+ import React from "react";
4
+ import { AwardMarquee } from "./index";
5
+ import { AwardMarqueeItem } from "./types";
6
+
7
+ import { render, screen } from "@testing-library/react";
8
+
9
+ const buildItems = (count: number): AwardMarqueeItem[] =>
10
+ Array.from({ length: count }, (_, index) => ({
11
+ iconUrl: `https://example.com/icon-${index}.png`,
12
+ iconAlt: `Award ${index}`,
13
+ title: `Award ${index}`,
14
+ description: `Description ${index}`,
15
+ }));
16
+
17
+ describe("AwardMarquee", () => {
18
+ it("renders award items synchronously (SSR, no hydration gate)", () => {
19
+ render(<AwardMarquee items={buildItems(2)} />);
20
+ expect(screen.getByText("Award 0")).toBeInTheDocument();
21
+ expect(screen.getByText("Award 1")).toBeInTheDocument();
22
+ });
23
+
24
+ it("renders the icon with its alt text", () => {
25
+ render(<AwardMarquee items={buildItems(1)} />);
26
+ const icon = screen.getByAltText("Award 0") as HTMLImageElement;
27
+ expect(icon).toBeInTheDocument();
28
+ expect(icon.src).toContain("icon-0.png");
29
+ });
30
+
31
+ it("renders a static (non-animated) list when scroll is disabled", () => {
32
+ const { container } = render(
33
+ <AwardMarquee items={buildItems(5)} scroll={false} />
34
+ );
35
+ expect(container.querySelector(".animate-award-marquee")).toBeNull();
36
+ });
37
+
38
+ it("animates at every breakpoint when scroll is enabled with more than 3 items", () => {
39
+ const { container } = render(
40
+ <AwardMarquee items={buildItems(5)} scroll={true} />
41
+ );
42
+ expect(container.querySelector(".animate-award-marquee")).not.toBeNull();
43
+ // No breakpoint split -> no mobile-only wrapper.
44
+ expect(container.querySelector(".sm\\:hidden")).toBeNull();
45
+ });
46
+
47
+ it("renders both mobile (animated) and desktop (static) variants when scroll is enabled with 3 or fewer items", () => {
48
+ const { container } = render(
49
+ <AwardMarquee items={buildItems(2)} scroll={true} />
50
+ );
51
+ // Mobile variant animates and is hidden from >= sm.
52
+ expect(container.querySelector(".sm\\:hidden")).not.toBeNull();
53
+ expect(container.querySelector(".animate-award-marquee")).not.toBeNull();
54
+ // Desktop variant is a static list shown only at >= sm.
55
+ expect(container.querySelector(".hidden.sm\\:block")).not.toBeNull();
56
+ // 2 items duplicated for the animated loop (4) + 2 in the static list.
57
+ expect(screen.getAllByText("Award 0")).toHaveLength(3);
58
+ });
59
+
60
+ it("applies the anchorId to the wrapper in every render branch", () => {
61
+ const staticView = render(
62
+ <AwardMarquee
63
+ items={buildItems(2)}
64
+ scroll={false}
65
+ anchorId="static-anchor"
66
+ />
67
+ );
68
+ expect(staticView.container.querySelector("#static-anchor")).not.toBeNull();
69
+
70
+ const animatedView = render(
71
+ <AwardMarquee
72
+ items={buildItems(5)}
73
+ scroll={true}
74
+ anchorId="animated-anchor"
75
+ />
76
+ );
77
+ expect(
78
+ animatedView.container.querySelector("#animated-anchor")
79
+ ).not.toBeNull();
80
+
81
+ const splitView = render(
82
+ <AwardMarquee items={buildItems(2)} scroll={true} anchorId="split-anchor" />
83
+ );
84
+ expect(splitView.container.querySelector("#split-anchor")).not.toBeNull();
85
+ });
86
+ });
@@ -1,110 +1,110 @@
1
- import React from "react";
2
- import {
3
- AwardMarqueeBackground,
4
- AwardMarqueeItem,
5
- AwardMarqueeProps,
6
- AwardMarqueeSpeed,
7
- } from "./types";
8
-
9
- import { cx } from "@shared/utils";
10
-
11
- const DURATION_IN_SECONDS: Record<AwardMarqueeSpeed, number> = {
12
- slow: 30,
13
- medium: 20,
14
- fast: 10,
15
- };
16
-
17
- const BACKGROUND_CLASS: Record<AwardMarqueeBackground, string> = {
18
- cream: "bg-[#FFFEEF]",
19
- gray90: "bg-[#FBFBFC]",
20
- white: "bg-white",
21
- };
22
-
23
- const renderAwardItem = (
24
- { iconUrl, iconAlt, title, description }: AwardMarqueeItem,
25
- key: React.Key
26
- ) => (
27
- <div
28
- key={key}
29
- className="ml-4 flex w-auto flex-shrink-0 items-center whitespace-nowrap"
30
- >
31
- <img src={iconUrl} alt={iconAlt ?? ""} width={200} />
32
- <div className="w-[250px] text-center">
33
- <p className="flex justify-center text-center text-body3 font-bold">
34
- {title}
35
- </p>
36
- <p className="flex flex-wrap whitespace-normal text-center text-footnote">
37
- {description}
38
- </p>
39
- </div>
40
- </div>
41
- );
42
-
43
- export const AwardMarquee: React.FC<AwardMarqueeProps> = ({
44
- anchorId = "Award-Marquee",
45
- items = [],
46
- speed = "medium",
47
- scroll = false,
48
- backgroundColor = "white",
49
- className,
50
- }) => {
51
- const scrollAvailable = items.length > 3;
52
- const shouldDuplicate = items.length < 8;
53
- const duration = DURATION_IN_SECONDS[speed];
54
-
55
- const animatedMarquee = () => {
56
- const marqueeItems = shouldDuplicate ? [...items, ...items] : items;
57
-
58
- return (
59
- <div
60
- className={cx(
61
- "flex items-center overflow-x-hidden",
62
- BACKGROUND_CLASS[backgroundColor]
63
- )}
64
- >
65
- <div
66
- className="flex animate-award-marquee gap-4 px-2"
67
- style={
68
- {
69
- "--award-marquee-duration": `${duration}s`,
70
- } as React.CSSProperties
71
- }
72
- >
73
- {marqueeItems.map((item, index) => renderAwardItem(item, index))}
74
- </div>
75
- </div>
76
- );
77
- };
78
-
79
- const staticMarquee = (
80
- <div className="flex flex-nowrap items-center justify-around overflow-clip">
81
- {items.map((item, index) => renderAwardItem(item, index))}
82
- </div>
83
- );
84
-
85
- // No scroll: always static at every breakpoint.
86
- if (!scroll)
87
- return (
88
- <div id={anchorId} className={className}>
89
- {staticMarquee}
90
- </div>
91
- );
92
-
93
- // Scroll with >3 items: animate at every breakpoint.
94
- if (scrollAvailable)
95
- return (
96
- <div id={anchorId} className={className}>
97
- {animatedMarquee()}
98
- </div>
99
- );
100
-
101
- // Scroll with <=3 items: animate on mobile, static on >= sm (CSS-driven).
102
- return (
103
- <div id={anchorId} className={className}>
104
- <div className="sm:hidden">{animatedMarquee()}</div>
105
- <div className="hidden sm:block">{staticMarquee}</div>
106
- </div>
107
- );
108
- };
109
-
110
- export default AwardMarquee;
1
+ import React from "react";
2
+ import {
3
+ AwardMarqueeBackground,
4
+ AwardMarqueeItem,
5
+ AwardMarqueeProps,
6
+ AwardMarqueeSpeed,
7
+ } from "./types";
8
+
9
+ import { cx } from "@shared/utils";
10
+
11
+ const DURATION_IN_SECONDS: Record<AwardMarqueeSpeed, number> = {
12
+ slow: 30,
13
+ medium: 20,
14
+ fast: 10,
15
+ };
16
+
17
+ const BACKGROUND_CLASS: Record<AwardMarqueeBackground, string> = {
18
+ cream: "bg-[#FFFEEF]",
19
+ gray90: "bg-[#FBFBFC]",
20
+ white: "bg-white",
21
+ };
22
+
23
+ const renderAwardItem = (
24
+ { iconUrl, iconAlt, title, description }: AwardMarqueeItem,
25
+ key: React.Key
26
+ ) => (
27
+ <div
28
+ key={key}
29
+ className="ml-4 flex w-auto flex-shrink-0 items-center whitespace-nowrap"
30
+ >
31
+ <img src={iconUrl} alt={iconAlt ?? ""} width={200} />
32
+ <div className="w-[250px] text-center">
33
+ <p className="flex justify-center text-center text-body3 font-bold">
34
+ {title}
35
+ </p>
36
+ <p className="flex flex-wrap whitespace-normal text-center text-footnote">
37
+ {description}
38
+ </p>
39
+ </div>
40
+ </div>
41
+ );
42
+
43
+ export const AwardMarquee: React.FC<AwardMarqueeProps> = ({
44
+ anchorId = "Award-Marquee",
45
+ items = [],
46
+ speed = "medium",
47
+ scroll = false,
48
+ backgroundColor = "white",
49
+ className,
50
+ }) => {
51
+ const scrollAvailable = items.length > 3;
52
+ const shouldDuplicate = items.length < 8;
53
+ const duration = DURATION_IN_SECONDS[speed];
54
+
55
+ const animatedMarquee = () => {
56
+ const marqueeItems = shouldDuplicate ? [...items, ...items] : items;
57
+
58
+ return (
59
+ <div
60
+ className={cx(
61
+ "flex items-center overflow-x-hidden",
62
+ BACKGROUND_CLASS[backgroundColor]
63
+ )}
64
+ >
65
+ <div
66
+ className="flex animate-award-marquee gap-4 px-2"
67
+ style={
68
+ {
69
+ "--award-marquee-duration": `${duration}s`,
70
+ } as React.CSSProperties
71
+ }
72
+ >
73
+ {marqueeItems.map((item, index) => renderAwardItem(item, index))}
74
+ </div>
75
+ </div>
76
+ );
77
+ };
78
+
79
+ const staticMarquee = (
80
+ <div className="flex flex-nowrap items-center justify-around overflow-clip">
81
+ {items.map((item, index) => renderAwardItem(item, index))}
82
+ </div>
83
+ );
84
+
85
+ // No scroll: always static at every breakpoint.
86
+ if (!scroll)
87
+ return (
88
+ <div id={anchorId} className={className}>
89
+ {staticMarquee}
90
+ </div>
91
+ );
92
+
93
+ // Scroll with >3 items: animate at every breakpoint.
94
+ if (scrollAvailable)
95
+ return (
96
+ <div id={anchorId} className={className}>
97
+ {animatedMarquee()}
98
+ </div>
99
+ );
100
+
101
+ // Scroll with <=3 items: animate on mobile, static on >= sm (CSS-driven).
102
+ return (
103
+ <div id={anchorId} className={className}>
104
+ <div className="sm:hidden">{animatedMarquee()}</div>
105
+ <div className="hidden sm:block">{staticMarquee}</div>
106
+ </div>
107
+ );
108
+ };
109
+
110
+ export default AwardMarquee;
@@ -1,19 +1,19 @@
1
- export type AwardMarqueeSpeed = "fast" | "medium" | "slow";
2
-
3
- export type AwardMarqueeBackground = "cream" | "gray90" | "white";
4
-
5
- export type AwardMarqueeItem = {
6
- iconUrl: string;
7
- iconAlt?: string;
8
- title?: string;
9
- description?: string;
10
- };
11
-
12
- export type AwardMarqueeProps = {
13
- anchorId?: string;
14
- items: AwardMarqueeItem[];
15
- speed?: AwardMarqueeSpeed;
16
- scroll?: boolean;
17
- backgroundColor?: AwardMarqueeBackground;
18
- className?: string;
19
- };
1
+ export type AwardMarqueeSpeed = "fast" | "medium" | "slow";
2
+
3
+ export type AwardMarqueeBackground = "cream" | "gray90" | "white";
4
+
5
+ export type AwardMarqueeItem = {
6
+ iconUrl: string;
7
+ iconAlt?: string;
8
+ title?: string;
9
+ description?: string;
10
+ };
11
+
12
+ export type AwardMarqueeProps = {
13
+ anchorId?: string;
14
+ items: AwardMarqueeItem[];
15
+ speed?: AwardMarqueeSpeed;
16
+ scroll?: boolean;
17
+ backgroundColor?: AwardMarqueeBackground;
18
+ className?: string;
19
+ };
@@ -0,0 +1,97 @@
1
+ import { act, fireEvent, render, screen, waitFor } from "@testing-library/react";
2
+ import * as Yup from "yup";
3
+ import { FiberForm } from ".";
4
+ import type { FiberFormValues } from "./types";
5
+
6
+ jest.mock("@vimeo/player", () => jest.fn(), { virtual: true });
7
+
8
+ const initialValues: FiberFormValues = {
9
+ firstName: "",
10
+ lastName: "",
11
+ address: "",
12
+ phone: "",
13
+ email: "",
14
+ unit: "",
15
+ zip: "",
16
+ isManualAddress: false,
17
+ isMarketingCom: false,
18
+ addressToSend: {},
19
+ notes: "",
20
+ referralCode: "",
21
+ hasUnits: false,
22
+ };
23
+
24
+ const AddressAutocomplete = () => null;
25
+
26
+ const deferred = () => {
27
+ let resolve!: () => void;
28
+ let reject!: (error: Error) => void;
29
+ const promise = new Promise<void>((resolvePromise, rejectPromise) => {
30
+ resolve = resolvePromise;
31
+ reject = rejectPromise;
32
+ });
33
+ return { promise, resolve, reject };
34
+ };
35
+
36
+ const renderForm = (onSubmit: (values: FiberFormValues) => Promise<void>) =>
37
+ render(
38
+ <FiberForm
39
+ AddressAutocomplete={AddressAutocomplete}
40
+ initialValues={initialValues}
41
+ inputList={{}}
42
+ formSchema={Yup.object({})}
43
+ onSubmit={onSubmit}
44
+ buttonText="Submit"
45
+ hideLegalCopy={true}
46
+ />
47
+ );
48
+
49
+ describe("FiberForm submit loading state", () => {
50
+ it("shows a spinner and disables submit until submission resolves", async () => {
51
+ const submission = deferred();
52
+ const onSubmit = jest.fn(() => submission.promise);
53
+ renderForm(onSubmit);
54
+ const button = screen.getByRole("button", { name: /submit/i });
55
+
56
+ expect(button).toHaveClass("w-[198px]", "max-w-full");
57
+
58
+ fireEvent.click(button);
59
+
60
+ await waitFor(() => expect(button).toBeDisabled());
61
+ expect(button).toHaveAttribute("aria-busy", "true");
62
+ expect(button).toHaveClass("opacity-75");
63
+ expect(screen.getByRole("status")).toBeInTheDocument();
64
+
65
+ fireEvent.click(button);
66
+ expect(onSubmit).toHaveBeenCalledTimes(1);
67
+
68
+ await act(async () => submission.resolve());
69
+
70
+ await waitFor(() => expect(button).toBeEnabled());
71
+ expect(button).toHaveAttribute("aria-busy", "false");
72
+ expect(button).not.toHaveClass("opacity-75");
73
+ expect(screen.queryByRole("status")).not.toBeInTheDocument();
74
+ });
75
+
76
+ it("returns submit to normal after a handled rejection", async () => {
77
+ const submission = deferred();
78
+ renderForm(async () => {
79
+ try {
80
+ await submission.promise;
81
+ } catch {
82
+ return;
83
+ }
84
+ });
85
+ const button = screen.getByRole("button", { name: /submit/i });
86
+
87
+ fireEvent.click(button);
88
+
89
+ await waitFor(() => expect(button).toBeDisabled());
90
+ expect(screen.getByRole("status")).toBeInTheDocument();
91
+
92
+ await act(async () => submission.reject(new Error("Request failed")));
93
+
94
+ await waitFor(() => expect(button).toBeEnabled());
95
+ expect(screen.queryByRole("status")).not.toBeInTheDocument();
96
+ });
97
+ });
@@ -5,6 +5,7 @@ import { Button } from "../../../components/button";
5
5
  import { Input } from "../../../components/input";
6
6
  import { MaterialIcon } from "../../../components/material-icon";
7
7
  import { Select, type SelectOption } from "../../../components/select";
8
+ import { Spinner } from "../../../components/spinner";
8
9
  import { Text } from "../../../components/text";
9
10
  import { Tooltip } from "../../../components/tooltip";
10
11
  import { cx } from "../../../utils";
@@ -160,7 +161,7 @@ export const FiberForm: React.FC<FiberFormProps> = ({
160
161
  setFieldValue,
161
162
  values,
162
163
  }) => (
163
- <Form className={cx("w-full", className)}>
164
+ <Form className={cx("fiber-form w-full", className)}>
164
165
  <div className="flex flex-col gap-5 sm:flex-row">
165
166
  {inputList.firstName && (
166
167
  <div className="flex-1">
@@ -259,7 +260,7 @@ export const FiberForm: React.FC<FiberFormProps> = ({
259
260
  >
260
261
  <button
261
262
  type="button"
262
- className="flex w-full items-center gap-2 px-4 py-3 text-left hover:bg-bg-surface-hover"
263
+ className="body2 flex w-full items-center gap-2 px-4 py-3 text-left hover:bg-bg-surface-hover"
263
264
  onClick={() =>
264
265
  selectCandidate(candidate, setFieldValue)
265
266
  }
@@ -487,7 +488,7 @@ export const FiberForm: React.FC<FiberFormProps> = ({
487
488
  </label>
488
489
  <Tooltip
489
490
  tooltipMsg="By opting in to receive text messages, you will receive automated text message related to service notifications including installations, service changes and updates, billing information, marketing offers from Kinetic including cart reminders. Consent is not a condition of purchase. Reply STOP at any time to unsubscribe. Message frequency varies. Msg & data rates may apply. To contact our Customer Support via email, chat, or phone, visit our Support page below."
490
- className="ff-NR mt-0"
491
+ className="fiber-form-tooltip ff-NR mt-0"
491
492
  >
492
493
  <MaterialIcon
493
494
  name="info"
@@ -531,16 +532,22 @@ export const FiberForm: React.FC<FiberFormProps> = ({
531
532
  ))}
532
533
  </ul>
533
534
  )}
534
- <div className="mt-8 flex items-center justify-center px-[60px] lg:mt-[64px]">
535
+ <div className="mt-8 flex items-center justify-center lg:mt-[64px]">
535
536
  <Button
536
537
  type="submit"
537
538
  disabled={isSubmitting}
538
539
  className={cx(
539
- "min-h-14 rounded-xl bg-bg-fill-brand px-8 py-4 font-bold text-white disabled:opacity-50",
540
+ "flex h-16 w-[198px] max-w-full cursor-pointer items-center justify-center overflow-hidden rounded-button border border-brand bg-bg-fill-brand px-[60px] py-4 text-center font-black leading-7 text-text-brand-on-bg-fill no-underline transition-colors duration-300 ease-in-out enabled:hover:border-[var(--color-bg-fill-brand-hover)] enabled:hover:bg-bg-fill-brand-hover focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-border-brand disabled:cursor-not-allowed",
541
+ isSubmitting && "opacity-75",
540
542
  buttonClassName
541
543
  )}
542
544
  >
543
- {isSubmitting ? "Submitting..." : buttonText}
545
+ <span className="relative flex w-full items-center justify-center">
546
+ {isSubmitting && (
547
+ <Spinner size="small" className="!h-5 !w-5" />
548
+ )}
549
+ <span>{buttonText}</span>
550
+ </span>
544
551
  </Button>
545
552
  </div>
546
553
  </Form>
@@ -27,6 +27,7 @@ export const PrimaryHero: React.FC<PrimaryHeroProps> = props => {
27
27
  secondaryCta,
28
28
  secondaryCtaPrefix,
29
29
  onModalButtonClick,
30
+ onImageClick,
30
31
  hideOnMobileCta1,
31
32
  hideOnMobileCta2,
32
33
  textColor = "light",
@@ -67,7 +68,8 @@ export const PrimaryHero: React.FC<PrimaryHeroProps> = props => {
67
68
  <NextImage
68
69
  src={badgeImageUrl}
69
70
  alt="Badge"
70
- className={className}
71
+ className={cx(className, onImageClick && "cursor-pointer")}
72
+ onClick={onImageClick}
71
73
  width={208}
72
74
  height={208}
73
75
  quality={90}
@@ -250,9 +252,13 @@ export const PrimaryHero: React.FC<PrimaryHeroProps> = props => {
250
252
  )}
251
253
  {secondaryCtaPrefix || secondaryCta ? (
252
254
  <div className="hidden lg:flex">
253
- {secondaryCtaPrefix && secondaryCta?.preDefinedFunctionExecution !== "check availability" && (
254
- <Text as="span" className="body2 mr-1">{secondaryCtaPrefix}</Text>
255
- )}
255
+ {secondaryCtaPrefix &&
256
+ secondaryCta?.preDefinedFunctionExecution !==
257
+ "check availability" && (
258
+ <Text as="span" className="body2 mr-1">
259
+ {secondaryCtaPrefix}
260
+ </Text>
261
+ )}
256
262
  {secondaryCta && (
257
263
  <Button
258
264
  {...secondaryCta}
@@ -315,7 +321,11 @@ export const PrimaryHero: React.FC<PrimaryHeroProps> = props => {
315
321
  <NextImage
316
322
  src={heroImageUrl}
317
323
  alt={"Hero"}
318
- className="h-[205px] w-full rounded-[40px] object-cover object-center sm:h-[420px]"
324
+ className={cx(
325
+ "h-[205px] w-full rounded-[40px] object-cover object-center sm:h-[420px]",
326
+ onImageClick && "cursor-pointer"
327
+ )}
328
+ onClick={onImageClick}
319
329
  width={1024}
320
330
  height={600}
321
331
  sizes="100vw"
@@ -331,9 +341,12 @@ export const PrimaryHero: React.FC<PrimaryHeroProps> = props => {
331
341
  <div
332
342
  className={`flex flex-wrap items-center ${textColorClass} lg:hidden`}
333
343
  >
334
- {secondaryCtaPrefix && !secondaryCta?.preDefinedFunctionExecution && (
335
- <Text as="span" className="body2 mr-1">{secondaryCtaPrefix}</Text>
336
- )}
344
+ {secondaryCtaPrefix &&
345
+ !secondaryCta?.preDefinedFunctionExecution && (
346
+ <Text as="span" className="body2 mr-1">
347
+ {secondaryCtaPrefix}
348
+ </Text>
349
+ )}
337
350
  {secondaryCta && (
338
351
  <Button
339
352
  {...secondaryCta}
@@ -369,7 +382,11 @@ export const PrimaryHero: React.FC<PrimaryHeroProps> = props => {
369
382
  <NextImage
370
383
  src={heroImageUrl}
371
384
  alt={"Hero"}
372
- className="aspect-square rounded-[40px] object-cover object-center"
385
+ className={cx(
386
+ "aspect-square rounded-[40px] object-cover object-center",
387
+ onImageClick && "cursor-pointer"
388
+ )}
389
+ onClick={onImageClick}
373
390
  width={584}
374
391
  height={584}
375
392
  quality={90}