Fix ask organizer modal
This commit is contained in:
@@ -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]}
|
||||
onClick={onOverlayClick}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<div
|
||||
ref={overlayRef}
|
||||
className={`${backdropOverlayClasses[backdropVariant]} flex flex-col items-center justify-center gap-6 overflow-y-auto px-4 py-8`}
|
||||
onClick={onOverlayClick}
|
||||
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") {
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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" />,
|
||||
|
||||
Reference in New Issue
Block a user