Ask organizer modal implemented

This commit is contained in:
adilallo
2026-05-11 18:03:52 -06:00
parent b5930331c0
commit 625a8c3161
29 changed files with 724 additions and 56 deletions
@@ -1,8 +1,9 @@
"use client";
import { memo } from "react";
import { memo, useCallback, useState } from "react";
import { useTranslation } from "../../../contexts/MessagesContext";
import { useAnalytics } from "../../../hooks";
import AskOrganizerInquiryModal from "../../modals/AskOrganizerInquiry";
import AskOrganizerView from "./AskOrganizer.view";
import type {
AskOrganizerProps,
@@ -45,8 +46,9 @@ const AskOrganizerContainer = memo<AskOrganizerProps>(
const variant = variantProp;
const t = useTranslation();
const defaultButtonText = buttonText ?? t("askOrganizer.buttonText");
const defaultButtonHref = buttonHref ?? t("askOrganizer.buttonHref");
const analyticsHref = buttonHref ?? "modal";
const { trackEvent, trackCustomEvent } = useAnalytics();
const [inquiryOpen, setInquiryOpen] = useState(false);
const resolvedVariant: AskOrganizerVariant = variant ?? "centered";
const styles = VARIANT_STYLES[resolvedVariant] ?? VARIANT_STYLES.centered;
@@ -66,6 +68,31 @@ const AskOrganizerContainer = memo<AskOrganizerProps>(
const handleContactClick = (
event: React.MouseEvent<HTMLButtonElement | HTMLAnchorElement>,
) => {
if (buttonHref) {
// Legacy link CTA: do not intercept navigation.
trackEvent({
event: "contact_button_click",
category: "engagement",
label: "ask_organizer",
component: "AskOrganizer",
variant: resolvedVariant,
});
trackCustomEvent(
"contact_button_click",
{
component: "AskOrganizer",
variant: resolvedVariant,
buttonText: defaultButtonText,
buttonHref: analyticsHref,
},
onContactClick as
| ((_data: Record<string, unknown>) => void)
| undefined,
);
return event;
}
event.preventDefault();
trackEvent({
event: "contact_button_click",
category: "engagement",
@@ -80,33 +107,39 @@ const AskOrganizerContainer = memo<AskOrganizerProps>(
component: "AskOrganizer",
variant: resolvedVariant,
buttonText: defaultButtonText,
buttonHref: defaultButtonHref,
buttonHref: analyticsHref,
},
onContactClick as
| ((_data: Record<string, unknown>) => void)
| undefined,
);
// Preserve existing button behavior (no preventDefault here)
// while still tracking analytics.
setInquiryOpen(true);
return event;
};
const closeInquiry = useCallback(() => {
setInquiryOpen(false);
}, []);
return (
<AskOrganizerView
title={title}
subtitle={subtitle}
description={description}
buttonText={defaultButtonText}
buttonHref={defaultButtonHref}
className={className}
sectionPadding={sectionPadding}
contentGap={`${contentGap} ${styles.container}`}
buttonContainerClass={styles.buttonContainer}
variant={resolvedVariant}
labelledBy={labelledBy}
onContactClick={handleContactClick}
/>
<>
<AskOrganizerView
title={title}
subtitle={subtitle}
description={description}
buttonText={defaultButtonText}
buttonHref={buttonHref}
className={className}
sectionPadding={sectionPadding}
contentGap={`${contentGap} ${styles.container}`}
buttonContainerClass={styles.buttonContainer}
variant={resolvedVariant}
labelledBy={labelledBy}
onContactClick={handleContactClick}
/>
<AskOrganizerInquiryModal isOpen={inquiryOpen} onClose={closeInquiry} />
</>
);
},
);
@@ -11,6 +11,9 @@ export interface AskOrganizerProps {
subtitle?: string;
description?: string;
buttonText?: string;
/**
* @deprecated Modal-only flow (CR-107). Omit; kept optional for Storybook overrides.
*/
buttonHref?: string;
className?: string;
/**
@@ -22,7 +25,7 @@ export interface AskOrganizerProps {
component: string;
variant: string;
buttonText: string;
buttonHref: string;
buttonHref?: string;
timestamp: string;
}) => void;
}
@@ -32,7 +35,7 @@ export interface AskOrganizerViewProps {
subtitle?: string;
description?: string;
buttonText: string;
buttonHref: string;
buttonHref?: string;
className: string;
sectionPadding: string;
contentGap: string;
@@ -43,13 +43,14 @@ function AskOrganizerView({
{/* Button */}
<div className={buttonContainerClass}>
<Button
href={buttonHref}
{...(buttonHref ? { href: buttonHref } : {})}
size="large"
buttonType="filled"
palette={variant === "inverse" ? "inverse" : "default"}
className="xl:!px-[var(--spacing-scale-020)] xl:!py-[var(--spacing-scale-012)] xl:!text-[24px] xl:!leading-[28px]"
onClick={onContactClick}
ariaLabel={ariaLabel}
data-testid="ask-organizer-cta"
>
{buttonText}
</Button>