Show invited people the Rule, let them copy its cards for their community, and replace an expired invitation link.

This commit is contained in:
adilallo committed 2026-11-06 09:16:06 -07:00
1 parent 727a92a9ac
commit 3c984e00c5
37 files changed
+1962 -19

No files matched your search

@@ -26,6 +26,11 @@ import {
CREATE_FLOW_COMPLETED_CELEBRATE_QUERY,
CREATE_FLOW_COMPLETED_CELEBRATE_VALUE,
} from "../../utils/flowSteps";
import {
CREATE_FLOW_COPIED_QUERY,
CREATE_FLOW_COPIED_VALUE,
} from "../../../../../lib/create/invitePaths";
import { communityPossessive } from "../../../../../lib/create/ruleInviteCardMeta";
function emptyCompletedDocumentState(): {
headerTitle: string;
@@ -80,6 +85,11 @@ export function CompletedScreen() {
const celebrateInUrl =
searchParams.get(CREATE_FLOW_COMPLETED_CELEBRATE_QUERY) ===
CREATE_FLOW_COMPLETED_CELEBRATE_VALUE;
const copiedInUrl =
searchParams.get(CREATE_FLOW_COPIED_QUERY) === CREATE_FLOW_COPIED_VALUE;
const storedForCopy = ruleIdParam ? null : readLastPublishedRule();
const copiedFromTitle = storedForCopy?.copiedFromTitle;
const copiedNameHit = storedForCopy?.copiedNameHit ?? null;
const mdUp = useCreateFlowMdUp();
const m = useMessages();
const completed = m.create.reviewAndComplete.completed;
@@ -88,6 +98,7 @@ export function CompletedScreen() {
const [toastDismissed, setToastDismissed] = useState(false);
/** Latch: toast copy should survive `router.replace` after we strip `?celebrate=1`. */
const [showCelebrateToast] = useState(celebrateInUrl);
const [showCopiedReady] = useState(copiedInUrl);
const [askOrganizerOpen, setAskOrganizerOpen] = useState(false);
const [headerTitle, setHeaderTitle] = useState(initial.headerTitle);
const [headerDescription, setHeaderDescription] = useState<
@@ -141,11 +152,17 @@ export function CompletedScreen() {
}, [ruleIdParam, router]);
useEffect(() => {
if (!celebrateInUrl) return;
if (!celebrateInUrl && !copiedInUrl) return;
router.replace("/create/completed");
}, [celebrateInUrl, router]);
}, [celebrateInUrl, copiedInUrl, router]);
const toast = showCelebrateToast && !toastDismissed ? (
const surfaceCopied = showCopiedReady || Boolean(copiedFromTitle);
const surfaceClass = surfaceCopied
? "bg-[var(--color-lavender-lavender150,#d1bdf3)]"
: "bg-[var(--color-teal-teal50,#c9fef9)]";
const toast =
!toastDismissed && (showCopiedReady || showCelebrateToast) ? (
<div
className="fixed bottom-0 left-0 right-0 z-10 w-full"
role="status"
@@ -154,8 +171,19 @@ export function CompletedScreen() {
<Alert
type="toast"
status="default"
title={completed.toastTitle}
description={completed.toastDescription}
title={
showCopiedReady
? completed.copyReadyToastTitle
: completed.toastTitle
}
description={
showCopiedReady
? completed.copyReadyToastDescription.replace(
"{possessive}",
communityPossessive(copiedFromTitle ?? ""),
)
: completed.toastDescription
}
hasLeadingIcon
hasBodyText
onClose={() => setToastDismissed(true)}
@@ -166,7 +194,7 @@ export function CompletedScreen() {
return (
<>
<div className="flex min-h-0 w-full flex-1 flex-col overflow-hidden bg-[var(--color-teal-teal50,#c9fef9)] md:h-full">
<div className={`flex min-h-0 w-full flex-1 flex-col overflow-hidden ${surfaceClass} md:h-full`}>
<div
className={`mx-auto grid min-h-0 w-full grid-cols-1 gap-4 ${CREATE_FLOW_PAGE_GUTTER_CLASS} max-md:h-full max-md:grid-rows-[auto_minmax(0,1fr)] max-md:overflow-hidden max-md:pt-[var(--space-800)] max-md:pb-8 md:h-full md:grid-cols-2 md:grid-rows-1 md:items-stretch md:justify-items-center md:gap-[var(--space-1200)] md:overflow-hidden md:py-0 ${CREATE_FLOW_TWO_COLUMN_MAX_WIDTH_CLASS}`}
>
@@ -180,7 +208,7 @@ export function CompletedScreen() {
size="L"
palette="inverse"
/>
{headerTitle ? (
{headerTitle && !surfaceCopied ? (
<p className="mt-[var(--space-400)] max-w-[640px] text-small-paragraph text-[var(--color-content-invert-secondary)]">
{completed.askOrganizerLead}{" "}
<InlineTextButton
@@ -196,10 +224,33 @@ export function CompletedScreen() {
className={`relative flex min-h-0 flex-col overflow-x-hidden overflow-y-auto md:max-h-full md:self-stretch ${CREATE_FLOW_SCROLL_REGION_CLASS} ${CREATE_FLOW_MD_UP_GRID_CELL_CLASS}`}
>
<div
className="pointer-events-none sticky top-0 z-10 hidden h-5 shrink-0 bg-gradient-to-b from-[var(--color-teal-teal50,#c9fef9)]/55 from-0% via-[var(--color-teal-teal50,#c9fef9)]/20 via-50% to-transparent md:block"
className={`pointer-events-none sticky top-0 z-10 hidden h-5 shrink-0 bg-gradient-to-b from-0% via-50% to-transparent md:block ${
surfaceCopied
? "from-[var(--color-lavender-lavender150,#d1bdf3)]/55 via-[var(--color-lavender-lavender150,#d1bdf3)]/20"
: "from-[var(--color-teal-teal50,#c9fef9)]/55 via-[var(--color-teal-teal50,#c9fef9)]/20"
}`}
aria-hidden
/>
<div className="w-full min-w-0 py-0 md:pb-8">
{copiedNameHit && copiedFromTitle ? (
<div className="mb-[var(--space-400)]">
<Alert
type="banner"
status="warning"
title={completed.copyNameHitTitle.replace(
"{name}",
copiedFromTitle,
)}
description={completed.copyNameHitDescription
.replace("{entry}", copiedNameHit.entryTitle)
.replace("{category}", copiedNameHit.categoryName)}
hasLeadingIcon
hasBodyText
hasTrailingIcon={false}
className="w-full"
/>
</div>
) : null}
<CommunityRule
sections={documentSections}
useCardStyle={!mdUp}