Fix ask organizer modal

This commit is contained in:
adilallo
2026-05-24 16:44:36 -06:00
parent 30a7dd1c2f
commit d8e0b87bb3
10 changed files with 57 additions and 12 deletions
+2 -2
View File
@@ -3,7 +3,7 @@ blank_issues_enabled: false
contact_links:
- name: Open the staging site
url: https://staging.communityrule.info
about: Preview version of Community Rule test here before reporting
about: Preview version of Community Rule, test here before reporting
- name: How to sign in (read first)
url: https://staging.communityrule.info/login
about: Use your email — we send a link to click, not a code to type
about: Use your email to recieve a link to click
@@ -14,6 +14,7 @@ import { useTranslation } from "../../../contexts/MessagesContext";
const AskOrganizerInquiryModalContainer = memo<AskOrganizerInquiryModalProps>(
({ isOpen, onClose }) => {
const t = useTranslation("modals.askOrganizerInquiry");
const tLogin = useTranslation("pages.login");
const copy = useMemo(
() => ({
title: t("title"),
@@ -28,8 +29,9 @@ const AskOrganizerInquiryModalContainer = memo<AskOrganizerInquiryModalProps>(
successDescription: t("successDescription"),
ariaDialog: t("ariaDialog"),
honeypotLabel: t("honeypotLabel"),
backToHome: tLogin("backToHome"),
}),
[t],
[t, tLogin],
);
const [email, setEmail] = useState("");
const [message, setMessage] = useState("");
@@ -16,6 +16,7 @@ export interface AskOrganizerInquiryModalCopy {
successDescription: string;
ariaDialog: string;
honeypotLabel: string;
backToHome: string;
}
export interface AskOrganizerInquiryModalViewProps
@@ -1,5 +1,6 @@
"use client";
import Link from "next/link";
import Create from "../Create";
import TextInput from "../../controls/TextInput";
import TextArea from "../../controls/TextArea";
@@ -72,6 +73,15 @@ export function AskOrganizerInquiryModalView({
ariaLabel={copy.ariaDialog}
footerContent={footer}
footerClassName="!h-auto min-h-[112px] shrink-0 flex flex-col justify-end pb-8 pt-3 px-4"
belowCard={
<Link
href="/"
className="font-inter font-normal text-[14px] leading-[20px] text-[var(--color-content-invert-tertiary,#2d2d2d)] text-center hover:opacity-90"
onClick={() => onClose()}
>
{copy.backToHome}
</Link>
}
>
{success ? (
<div className="flex flex-col gap-3 py-2">
@@ -36,6 +36,7 @@ const CreateContainer = memo<CreateProps>(
kebabTriggerAriaLabel,
kebabMenuAriaLabel,
kebabMenuItems,
belowCard,
}) => {
const createRef = useRef<HTMLDivElement>(null);
const overlayRef = useRef<HTMLDivElement>(null);
@@ -72,6 +73,7 @@ const CreateContainer = memo<CreateProps>(
kebabTriggerAriaLabel={kebabTriggerAriaLabel}
kebabMenuAriaLabel={kebabMenuAriaLabel}
kebabMenuItems={kebabMenuItems}
belowCard={belowCard}
/>
);
},
@@ -43,6 +43,8 @@ export interface CreateProps {
kebabTriggerAriaLabel?: string;
kebabMenuAriaLabel?: string;
kebabMenuItems?: ModalHeaderMenuItem[];
/** Rendered below the dialog card on the backdrop (e.g. “Back to home”). */
belowCard?: React.ReactNode;
}
export interface CreateViewProps {
@@ -73,4 +75,5 @@ export interface CreateViewProps {
kebabTriggerAriaLabel?: string;
kebabMenuAriaLabel?: string;
kebabMenuItems?: ModalHeaderMenuItem[];
belowCard?: React.ReactNode;
}
@@ -34,6 +34,7 @@ export function CreateView({
kebabTriggerAriaLabel,
kebabMenuAriaLabel,
kebabMenuItems,
belowCard,
}: CreateViewProps) {
return (
<CreateModalFrameView
@@ -45,6 +46,7 @@ export function CreateView({
ariaLabelledBy={ariaLabelledBy}
overlayRef={overlayRef}
dialogRef={createRef}
belowCard={belowCard}
>
<ModalHeader
onClose={onClose}
@@ -22,6 +22,8 @@ export type CreateModalFrameViewProps = {
overlayRef: RefObject<HTMLDivElement | null>;
dialogRef: RefObject<HTMLDivElement | null>;
children: ReactNode;
/** Rendered below the dialog card on the backdrop (e.g. “Back to home”). */
belowCard?: ReactNode;
};
/**
@@ -37,28 +39,34 @@ export function CreateModalFrameView({
overlayRef,
dialogRef,
children,
belowCard,
}: CreateModalFrameViewProps) {
if (!isOpen) return null;
const content = (
<>
<div
ref={overlayRef}
className={backdropOverlayClasses[backdropVariant]}
className={`${backdropOverlayClasses[backdropVariant]} flex flex-col items-center justify-center gap-6 overflow-y-auto px-4 py-8`}
onClick={onOverlayClick}
aria-hidden="true"
/>
role="presentation"
>
<div
ref={dialogRef}
role="dialog"
aria-modal="true"
aria-label={ariaLabel}
aria-labelledby={ariaLabelledBy}
className={`fixed left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 bg-[var(--color-surface-default-primary)] rounded-[var(--radius-500,20px)] shadow-[0px_0px_48px_0px_rgba(0,0,0,0.1)] w-[560px] max-h-[90vh] flex min-h-0 flex-col overflow-hidden z-[9999] ${className}`}
className={`flex min-h-0 max-h-[90vh] w-full max-w-[560px] shrink-0 flex-col overflow-hidden rounded-[var(--radius-500,20px)] bg-[var(--color-surface-default-primary)] shadow-[0px_0px_48px_0px_rgba(0,0,0,0.1)] z-[9999] ${className}`}
onClick={(e) => e.stopPropagation()}
>
{children}
</div>
</>
{belowCard ? (
<div className="shrink-0" onClick={(e) => e.stopPropagation()}>
{belowCard}
</div>
) : null}
</div>
);
if (typeof window !== "undefined") {
+9
View File
@@ -70,6 +70,15 @@ describe("AskOrganizer (behavioral tests)", () => {
).toBeInTheDocument();
});
it("shows back to home link below inquiry modal", async () => {
const user = userEvent.setup();
render(<AskOrganizer title="Test" />);
await user.click(screen.getByTestId("ask-organizer-cta"));
expect(
await screen.findByRole("link", { name: /back to home/i }),
).toHaveAttribute("href", "/");
});
it("renders button with custom text", () => {
render(<AskOrganizer title="Test" buttonText="Contact" />);
expect(
+8
View File
@@ -169,6 +169,14 @@ describe("Create", () => {
expect(screen.getByText("Custom Footer")).toBeInTheDocument();
});
it("uses responsive width at baseline (matches Login modal)", () => {
renderWithProviders(
<Create {...defaultProps}>Create dialog content</Create>,
);
const dialog = screen.getByRole("dialog");
expect(dialog).toHaveClass("w-full", "max-w-[560px]");
});
it("has proper ARIA attributes", () => {
renderWithProviders(
<Create {...defaultProps} ariaLabel="Test create dialog" />,