From 70ceb73104d0c4b91b987bb6c8abf40d0f346338 Mon Sep 17 00:00:00 2001
From: adilallo <39313955+adilallo@users.noreply.github.com>
Date: Fri, 6 Nov 2026 08:56:13 -0700
Subject: [PATCH] Invite people after review, then finish the Rule, with login
before inviting and Invite your members on Profile.
---
app/(app)/create/CreateFlowLayoutClient.tsx | 94 +++-
.../MembershipInvitePreviewCard.tsx | 43 ++
.../create/hooks/useCreateFlowFinalize.ts | 279 ++++++-----
.../screens/completed/CompletedScreen.tsx | 24 +-
.../select/ConfirmStakeholdersScreen.tsx | 446 ++++++++++++------
.../PublishedStakeholdersManagePanel.tsx | 41 +-
.../create/utils/createFlowScreenRegistry.ts | 2 +-
app/(app)/create/utils/flowSteps.ts | 15 +-
app/(app)/profile/ProfilePageClient.tsx | 40 ++
.../profile/_components/ProfilePage.view.tsx | 18 +-
.../modals/Login/Login.container.tsx | 22 +
app/components/modals/Login/Login.types.ts | 2 +
app/components/modals/Login/Login.view.tsx | 16 +-
app/components/modals/Login/LoginForm.tsx | 86 ++--
app/contexts/AuthModalContext.tsx | 19 +-
lib/create/membershipInvitePreview.ts | 43 ++
lib/create/parseInviteEmails.ts | 82 ++++
.../create/reviewAndComplete/completed.json | 6 +-
.../confirmStakeholders.json | 47 +-
messages/en/pages/login.json | 3 +
messages/en/pages/profile.json | 10 +-
.../pages/ConfirmStakeholdersPage.stories.js | 4 +-
tests/components/CompletedPage.test.tsx | 36 +-
.../ConfirmStakeholdersPage.test.tsx | 126 ++++-
tests/components/LoginForm.test.tsx | 38 ++
tests/contexts/AuthModalContext.test.tsx | 51 ++
tests/pages/profile.test.tsx | 42 ++
tests/unit/flowSteps.test.ts | 7 +-
.../unit/hooks/useCreateFlowFinalize.test.tsx | 65 +++
tests/unit/membershipInvitePreview.test.ts | 28 ++
tests/unit/parseInviteEmails.test.ts | 54 +++
31 files changed, 1388 insertions(+), 401 deletions(-)
create mode 100644 app/(app)/create/components/MembershipInvitePreviewCard.tsx
create mode 100644 lib/create/membershipInvitePreview.ts
create mode 100644 lib/create/parseInviteEmails.ts
create mode 100644 tests/unit/membershipInvitePreview.test.ts
create mode 100644 tests/unit/parseInviteEmails.test.ts
diff --git a/app/(app)/create/CreateFlowLayoutClient.tsx b/app/(app)/create/CreateFlowLayoutClient.tsx
index fa465cd..9e46c6b 100644
--- a/app/(app)/create/CreateFlowLayoutClient.tsx
+++ b/app/(app)/create/CreateFlowLayoutClient.tsx
@@ -199,9 +199,7 @@ function CreateFlowLayoutContent({
const editingPublishedRuleIdTrimmed =
state.editingPublishedRuleId?.trim() ?? "";
const isConfirmStakeholdersManagePublished =
- currentStep === "confirm-stakeholders" &&
- manageStakeholdersIntent &&
- editingPublishedRuleIdTrimmed.length > 0;
+ currentStep === "confirm-stakeholders" && manageStakeholdersIntent;
const { draftSaveBannerMessage, setDraftSaveBannerMessage } =
useCreateFlowDraftSaveBanner();
const { markAttempted, clearAttempted } = useCreateFlowContinueAttempt();
@@ -277,6 +275,7 @@ function CreateFlowLayoutContent({
: createFlowStepPathWithSyncDraft("final-review");
const {
+ publishBannerTitle,
publishBannerMessage,
setPublishBannerMessage,
isPublishing,
@@ -450,7 +449,10 @@ function CreateFlowLayoutContent({
}, [currentStep]);
useEffect(() => {
- if (currentStep !== "edit-rule") return;
+ const editingFromCompleted =
+ currentStep === "final-review" &&
+ (state.editingPublishedRuleId?.trim() ?? "").length > 0;
+ if (currentStep !== "edit-rule" && !editingFromCompleted) return;
const last = readLastPublishedRule();
if (!last) {
router.replace(CREATE_ROUTES.completed);
@@ -515,6 +517,33 @@ function CreateFlowLayoutContent({
state.customMethodCardMetaById,
]);
+ useEffect(() => {
+ if (currentStep !== "confirm-stakeholders") return;
+ if (!manageStakeholdersIntent) return;
+ if (editingPublishedRuleIdTrimmed.length > 0) return;
+ const last = readLastPublishedRule();
+ if (!last) {
+ router.replace(CREATE_ROUTES.completed);
+ return;
+ }
+ const patch = createFlowStateFromPublishedRule(last);
+ const pinPatch = methodSectionsPinsFromPublishedHydratePatch(patch);
+ updateState({
+ ...patch,
+ methodSectionsPinCommitted: {
+ ...state.methodSectionsPinCommitted,
+ ...pinPatch,
+ },
+ });
+ }, [
+ currentStep,
+ manageStakeholdersIntent,
+ editingPublishedRuleIdTrimmed.length,
+ router,
+ updateState,
+ state.methodSectionsPinCommitted,
+ ]);
+
useEffect(() => {
if (currentStep !== "completed") {
setCompletedFlowBanner(null);
@@ -705,6 +734,7 @@ function CreateFlowLayoutContent({
key: "publish",
status: "danger" as const,
title:
+ publishBannerTitle ??
messages.create.reviewAndComplete.publish.publishBannerTitle,
description: publishBannerMessage,
onClose: () => setPublishBannerMessage(null),
@@ -862,7 +892,7 @@ function CreateFlowLayoutContent({
editingPublishedRuleId: last.id,
sections: [],
});
- router.push(createFlowStepPath("edit-rule"));
+ router.push(createFlowStepPath("final-review"));
}
: undefined
}
@@ -1125,12 +1155,14 @@ function CreateFlowLayoutContent({
buttonType="filled"
palette="default"
size="xsmall"
- disabled={isPublishing}
+ disabled={
+ isPublishing || editingPublishedRuleIdTrimmed.length === 0
+ }
className={CREATE_FLOW_FOOTER_BUTTON_CLASS}
onClick={() => {
router.push(
createFlowStepPathAfterStrippingReviewReturn(
- "edit-rule",
+ reviewReturnTarget ?? "completed",
searchParams,
),
);
@@ -1141,6 +1173,39 @@ function CreateFlowLayoutContent({
.footerDone
}
+ ) : currentStep === "confirm-stakeholders" ? (
+
+
+
+
) : nextStep || isFinalReviewLike ? (