From 0825a1e1d61e8f896d1e86bd61616abacb6dbbef Mon Sep 17 00:00:00 2001 From: Nour Malaeb Date: Wed, 21 Jan 2026 10:13:59 -0500 Subject: [PATCH 01/39] Update page to use trpc --- .../decisions/edit/[slug]/page.tsx | 26 +++++++++++-------- .../ProcessBuilder/ProcessBuilderProvider.tsx | 7 +---- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/apps/app/src/app/[locale]/(no-header)/decisions/edit/[slug]/page.tsx b/apps/app/src/app/[locale]/(no-header)/decisions/edit/[slug]/page.tsx index 1c2377055..a7d321e6c 100644 --- a/apps/app/src/app/[locale]/(no-header)/decisions/edit/[slug]/page.tsx +++ b/apps/app/src/app/[locale]/(no-header)/decisions/edit/[slug]/page.tsx @@ -1,25 +1,29 @@ -import { createClient } from '@op/api/serverClient'; +'use client'; + +import { trpc } from '@op/api/client'; import { SidebarLayout } from '@op/ui/Sidebar'; -import { notFound } from 'next/navigation'; +import { notFound, useParams } from 'next/navigation'; import { ProcessBuilderHeader } from '@/components/decisions/ProcessBuilder/ProcessBuilderHeader'; import { ProcessBuilderProvider } from '@/components/decisions/ProcessBuilder/ProcessBuilderProvider'; import { ProcessBuilderSidebar } from '@/components/decisions/ProcessBuilder/ProcessBuilderSidebar'; -const EditDecisionPage = async ({ - params, -}: { - params: Promise<{ slug: string }>; -}) => { - const { slug } = await params; - const client = await createClient(); +const EditDecisionPage = ({}: {}) => { + const { slug } = useParams<{ slug: string }>(); + + console.log(slug); - const decisionProfile = await client.decision.getDecisionBySlug({ slug }); + // Get the decision profile to find the instance ID + const [decisionProfile] = trpc.decision.getDecisionBySlug.useSuspenseQuery({ + slug, + }); - if (!decisionProfile || !decisionProfile.processInstance) { + if (!decisionProfile?.processInstance) { notFound(); } + const instanceId = decisionProfile.processInstance.id; + return ( { - const [selectedProcess] = useQueryState('process'); return ( - + {children} ); From 3876161545a6eb846996c3dcb7ffa1d6e52d0e42 Mon Sep 17 00:00:00 2001 From: Nour Malaeb Date: Wed, 21 Jan 2026 11:25:44 -0500 Subject: [PATCH 02/39] Add navigation types --- .../ProcessBuilder/navigation-config.ts | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 apps/app/src/components/decisions/ProcessBuilder/navigation-config.ts diff --git a/apps/app/src/components/decisions/ProcessBuilder/navigation-config.ts b/apps/app/src/components/decisions/ProcessBuilder/navigation-config.ts new file mode 100644 index 000000000..2ba576611 --- /dev/null +++ b/apps/app/src/components/decisions/ProcessBuilder/navigation-config.ts @@ -0,0 +1,44 @@ +// Process Builder Navigation Configuration +// Steps and sections are defined here with `as const` - types are derived from this config + +export const STEPS = [ + { id: 'overview', labelKey: 'Overview' }, + { id: 'phases', labelKey: 'Phases' }, + { id: 'categories', labelKey: 'Proposal Categories' }, + { id: 'voting', labelKey: 'Voting' }, +] as const; + +export const SECTIONS_BY_STEP = { + overview: [ + { id: 'basics', labelKey: 'Basics' }, + { id: 'timeline', labelKey: 'Timeline' }, + { id: 'permissions', labelKey: 'Permissions' }, + ], + phases: [ + { id: 'submission', labelKey: 'Submission' }, + { id: 'review', labelKey: 'Review' }, + { id: 'deliberation', labelKey: 'Deliberation' }, + ], + categories: [ + { id: 'types', labelKey: 'Types' }, + { id: 'limits', labelKey: 'Limits' }, + ], + voting: [ + { id: 'method', labelKey: 'Voting Method' }, + { id: 'quorum', labelKey: 'Quorum' }, + { id: 'results', labelKey: 'Results' }, + ], +} as const satisfies Record; + +// Derived types from config +export type StepId = (typeof STEPS)[number]['id']; +export type SectionId = (typeof SECTIONS_BY_STEP)[StepId][number]['id']; + +// Visibility configuration (from API) +export interface VisibilityConfig { + steps?: Partial>; + sections?: Partial>; +} + +// Default visibility (all visible) +export const DEFAULT_VISIBILITY_CONFIG: VisibilityConfig = {}; From 43cec28501b7208f4df43e78f4681041319c04a6 Mon Sep 17 00:00:00 2001 From: Nour Malaeb Date: Wed, 21 Jan 2026 11:26:42 -0500 Subject: [PATCH 03/39] StepId used before it was defined --- .../decisions/ProcessBuilder/navigation-config.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/app/src/components/decisions/ProcessBuilder/navigation-config.ts b/apps/app/src/components/decisions/ProcessBuilder/navigation-config.ts index 2ba576611..5dcf1d896 100644 --- a/apps/app/src/components/decisions/ProcessBuilder/navigation-config.ts +++ b/apps/app/src/components/decisions/ProcessBuilder/navigation-config.ts @@ -8,6 +8,9 @@ export const STEPS = [ { id: 'voting', labelKey: 'Voting' }, ] as const; +// Derive StepId first so we can use it in SECTIONS_BY_STEP +export type StepId = (typeof STEPS)[number]['id']; + export const SECTIONS_BY_STEP = { overview: [ { id: 'basics', labelKey: 'Basics' }, @@ -30,8 +33,7 @@ export const SECTIONS_BY_STEP = { ], } as const satisfies Record; -// Derived types from config -export type StepId = (typeof STEPS)[number]['id']; +// Derive SectionId from all sections across all steps export type SectionId = (typeof SECTIONS_BY_STEP)[StepId][number]['id']; // Visibility configuration (from API) From 10e510a29355797185724ed8534bfcfd4c46bd84 Mon Sep 17 00:00:00 2001 From: Nour Malaeb Date: Wed, 21 Jan 2026 11:29:47 -0500 Subject: [PATCH 04/39] Process editor navigation hook --- .../ProcessBuilder/useProcessNavigation.ts | 106 ++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 apps/app/src/components/decisions/ProcessBuilder/useProcessNavigation.ts diff --git a/apps/app/src/components/decisions/ProcessBuilder/useProcessNavigation.ts b/apps/app/src/components/decisions/ProcessBuilder/useProcessNavigation.ts new file mode 100644 index 000000000..bf107eddf --- /dev/null +++ b/apps/app/src/components/decisions/ProcessBuilder/useProcessNavigation.ts @@ -0,0 +1,106 @@ +'use client'; + +import { useQueryState } from 'nuqs'; +import { useCallback, useMemo } from 'react'; + +import { + DEFAULT_VISIBILITY_CONFIG, + SECTIONS_BY_STEP, + STEPS, + type SectionId, + type StepId, + type VisibilityConfig, +} from './navigation-config'; + +export function useProcessNavigation( + visibilityConfig: VisibilityConfig = DEFAULT_VISIBILITY_CONFIG, +) { + const [stepParam, setStepParam] = useQueryState('step'); + const [sectionParam, setSectionParam] = useQueryState('section'); + + // Filter to visible steps only + const visibleSteps = useMemo( + () => + STEPS.filter((s) => { + const visibility = visibilityConfig.steps?.[s.id]; + // Default to visible if not specified + return visibility !== false; + }), + [visibilityConfig.steps], + ); + + // Current step (fallback to first visible step) + const currentStep = useMemo(() => { + const found = visibleSteps.find((s) => s.id === stepParam); + return found ?? visibleSteps[0]; + }, [stepParam, visibleSteps]); + + // Get visible sections for current step + const visibleSections = useMemo(() => { + if (!currentStep) { + return []; + } + + const allSections = SECTIONS_BY_STEP[currentStep.id]; + const allowedSectionIds = visibilityConfig.sections?.[currentStep.id]; + + // If no section config, show all sections for this step + if (!allowedSectionIds) { + return [...allSections]; + } + + // Filter to only allowed sections + return allSections.filter((s) => + allowedSectionIds.includes(s.id as SectionId), + ); + }, [currentStep, visibilityConfig.sections]); + + // Current section (fallback to first visible section) + const currentSection = useMemo(() => { + const found = visibleSections.find((s) => s.id === sectionParam); + return found ?? visibleSections[0]; + }, [sectionParam, visibleSections]); + + // Handle step change - resets section to first of new step + const setStep = useCallback( + (newStepId: StepId | string) => { + const newStep = visibleSteps.find((s) => s.id === newStepId); + if (!newStep) { + return; + } + + // Get first section of the new step + const newStepSections = SECTIONS_BY_STEP[newStep.id]; + const allowedSectionIds = visibilityConfig.sections?.[newStep.id]; + const firstVisibleSection = allowedSectionIds + ? newStepSections.find((s) => + allowedSectionIds.includes(s.id as SectionId), + ) + : newStepSections[0]; + + setStepParam(newStepId); + setSectionParam(firstVisibleSection?.id ?? null); + }, + [visibleSteps, visibilityConfig.sections, setStepParam, setSectionParam], + ); + + // Handle section change + const setSection = useCallback( + (newSectionId: SectionId | string) => { + setSectionParam(newSectionId); + }, + [setSectionParam], + ); + + return { + // Current state + currentStep, + currentSection, + // Visible items + visibleSteps, + visibleSections, + // Actions + setStep, + setSection, + }; +} From 71673b2b4081f7b9bb60e8423ca967c2bb4e0dde Mon Sep 17 00:00:00 2001 From: Nour Malaeb Date: Wed, 21 Jan 2026 11:30:46 -0500 Subject: [PATCH 05/39] Use visibilityConfig in ProcessBuilderProvider --- .../ProcessBuilder/ProcessBuilderProvider.tsx | 26 ++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/apps/app/src/components/decisions/ProcessBuilder/ProcessBuilderProvider.tsx b/apps/app/src/components/decisions/ProcessBuilder/ProcessBuilderProvider.tsx index 7412c8e5a..0afe7d708 100644 --- a/apps/app/src/components/decisions/ProcessBuilder/ProcessBuilderProvider.tsx +++ b/apps/app/src/components/decisions/ProcessBuilder/ProcessBuilderProvider.tsx @@ -1,15 +1,35 @@ 'use client'; import { SidebarProvider } from '@op/ui/Sidebar'; +import { createContext, useContext } from 'react'; + +import { + DEFAULT_VISIBILITY_CONFIG, + type VisibilityConfig, +} from './navigation-config'; + +interface ProcessBuilderContextValue { + visibilityConfig: VisibilityConfig; +} + +const ProcessBuilderContext = createContext({ + visibilityConfig: DEFAULT_VISIBILITY_CONFIG, +}); + +export const useProcessBuilderContext = () => useContext(ProcessBuilderContext); export const ProcessBuilderProvider = ({ children, + visibilityConfig = DEFAULT_VISIBILITY_CONFIG, }: { children: React.ReactNode; + visibilityConfig?: VisibilityConfig; }) => { return ( - - {children} - + + + {children} + + ); }; From 3bd7633df6cb920538411c39481e5d681d812202 Mon Sep 17 00:00:00 2001 From: Nour Malaeb Date: Wed, 21 Jan 2026 12:34:20 -0500 Subject: [PATCH 06/39] Update page to use nav config --- .../decisions/edit/[slug]/page.tsx | 20 +++++++------------ 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/apps/app/src/app/[locale]/(no-header)/decisions/edit/[slug]/page.tsx b/apps/app/src/app/[locale]/(no-header)/decisions/edit/[slug]/page.tsx index a7d321e6c..8c8e198c7 100644 --- a/apps/app/src/app/[locale]/(no-header)/decisions/edit/[slug]/page.tsx +++ b/apps/app/src/app/[locale]/(no-header)/decisions/edit/[slug]/page.tsx @@ -7,12 +7,11 @@ import { notFound, useParams } from 'next/navigation'; import { ProcessBuilderHeader } from '@/components/decisions/ProcessBuilder/ProcessBuilderHeader'; import { ProcessBuilderProvider } from '@/components/decisions/ProcessBuilder/ProcessBuilderProvider'; import { ProcessBuilderSidebar } from '@/components/decisions/ProcessBuilder/ProcessBuilderSidebar'; +import { type NavigationConfig } from '@/components/decisions/ProcessBuilder/navigation-config'; -const EditDecisionPage = ({}: {}) => { +const EditDecisionPage = () => { const { slug } = useParams<{ slug: string }>(); - console.log(slug); - // Get the decision profile to find the instance ID const [decisionProfile] = trpc.decision.getDecisionBySlug.useSuspenseQuery({ slug, @@ -22,18 +21,13 @@ const EditDecisionPage = ({}: {}) => { notFound(); } - const instanceId = decisionProfile.processInstance.id; + // TODO: Get navigation config from process instance or process type + // For now, show all steps and sections (empty config = all visible) + const navigationConfig: NavigationConfig = {}; return ( - - + +
From 2bccb59ae1c37eee13d5d206460c95364016250e Mon Sep 17 00:00:00 2001 From: Nour Malaeb Date: Wed, 21 Jan 2026 12:34:30 -0500 Subject: [PATCH 07/39] Nav config and hook --- .../ProcessBuilder/ProcessBuilderHeader.tsx | 72 +++++++++++------- .../ProcessBuilder/ProcessBuilderProvider.tsx | 14 ++-- .../ProcessBuilder/ProcessBuilderSidebar.tsx | 75 +++++++++---------- .../ProcessBuilder/navigation-config.ts | 8 +- .../ProcessBuilder/useProcessNavigation.ts | 18 ++--- 5 files changed, 101 insertions(+), 86 deletions(-) diff --git a/apps/app/src/components/decisions/ProcessBuilder/ProcessBuilderHeader.tsx b/apps/app/src/components/decisions/ProcessBuilder/ProcessBuilderHeader.tsx index fd1c77caf..da75f6e12 100644 --- a/apps/app/src/components/decisions/ProcessBuilder/ProcessBuilderHeader.tsx +++ b/apps/app/src/components/decisions/ProcessBuilder/ProcessBuilderHeader.tsx @@ -1,57 +1,77 @@ 'use client'; import { Button } from '@op/ui/Button'; -import { useQueryState } from 'nuqs'; +import { Tab, TabList, Tabs } from '@op/ui/Tabs'; +import { Key } from 'react-aria-components'; import { LuChevronRight, LuCircleAlert, LuHouse, LuPlus } from 'react-icons/lu'; -import { Link } from '@/lib/i18n'; +import { Link, useTranslations } from '@/lib/i18n'; import { UserAvatarMenu } from '@/components/SiteHeader'; -export const ProcessBuilderHeader = ({ - steps, -}: { - steps?: { id: string; label: string }[]; -}) => { - const [currentStep, setCurrentStep] = useQueryState('step'); +import { useProcessBuilderContext } from './ProcessBuilderProvider'; +import { useProcessNavigation } from './useProcessNavigation'; + +export const ProcessBuilderHeader = () => { + const t = useTranslations(); + const { navigationConfig } = useProcessBuilderContext(); + const { visibleSteps, currentStep, setStep } = + useProcessNavigation(navigationConfig); + + const handleSelectionChange = (key: Key) => { + setStep(String(key)); + }; + return (
- Home + {t('Home')} - New process + {t('New process')}
-
- {steps && steps.length > 0 && ( + {visibleSteps.length > 0 && (
)} diff --git a/apps/app/src/components/decisions/ProcessBuilder/ProcessBuilderProvider.tsx b/apps/app/src/components/decisions/ProcessBuilder/ProcessBuilderProvider.tsx index 0afe7d708..54f63cc20 100644 --- a/apps/app/src/components/decisions/ProcessBuilder/ProcessBuilderProvider.tsx +++ b/apps/app/src/components/decisions/ProcessBuilder/ProcessBuilderProvider.tsx @@ -4,29 +4,29 @@ import { SidebarProvider } from '@op/ui/Sidebar'; import { createContext, useContext } from 'react'; import { - DEFAULT_VISIBILITY_CONFIG, - type VisibilityConfig, + DEFAULT_NAVIGATION_CONFIG, + type NavigationConfig, } from './navigation-config'; interface ProcessBuilderContextValue { - visibilityConfig: VisibilityConfig; + navigationConfig: NavigationConfig; } const ProcessBuilderContext = createContext({ - visibilityConfig: DEFAULT_VISIBILITY_CONFIG, + navigationConfig: DEFAULT_NAVIGATION_CONFIG, }); export const useProcessBuilderContext = () => useContext(ProcessBuilderContext); export const ProcessBuilderProvider = ({ children, - visibilityConfig = DEFAULT_VISIBILITY_CONFIG, + navigationConfig = DEFAULT_NAVIGATION_CONFIG, }: { children: React.ReactNode; - visibilityConfig?: VisibilityConfig; + navigationConfig?: NavigationConfig; }) => { return ( - + {children} diff --git a/apps/app/src/components/decisions/ProcessBuilder/ProcessBuilderSidebar.tsx b/apps/app/src/components/decisions/ProcessBuilder/ProcessBuilderSidebar.tsx index b3060d84f..6a8da73b5 100644 --- a/apps/app/src/components/decisions/ProcessBuilder/ProcessBuilderSidebar.tsx +++ b/apps/app/src/components/decisions/ProcessBuilder/ProcessBuilderSidebar.tsx @@ -1,55 +1,50 @@ 'use client'; -import { MenuItem } from '@op/ui/Menu'; import { Sidebar } from '@op/ui/Sidebar'; -import { cn } from '@op/ui/utils'; -import { useQueryState } from 'nuqs'; -import { Menu } from 'react-aria-components'; +import { Tab, TabList, Tabs } from '@op/ui/Tabs'; +import { Key } from 'react-aria-components'; import { useTranslations } from '@/lib/i18n'; +import { useProcessBuilderContext } from './ProcessBuilderProvider'; +import { useProcessNavigation } from './useProcessNavigation'; + export const ProcessBuilderSidebar = () => { - const [section, setSection] = useQueryState('section'); const t = useTranslations(); + const { navigationConfig } = useProcessBuilderContext(); + const { visibleSections, currentSection, setSection } = + useProcessNavigation(navigationConfig); - const navSections = [ - { slug: 'overview', label: t('Overview') }, - { slug: 'phases', label: t('Phases') }, - { slug: 'categories', label: t('Proposal Categories') }, - { slug: 'voting', label: t('Voting') }, - ]; + const handleSelectionChange = (key: Key) => { + setSection(String(key)); + }; return ( - - {navSections.map(({ slug, label }) => ( - setSection(slug)} - label={label} - /> - ))} - + {visibleSections.length > 0 && ( + + + {visibleSections.map((section) => ( + + {t(section.labelKey)} + + ))} + + + )} ); }; - -const SidebarLink = ({ - label, - isCurrent, - onPress, -}: { - label: string; - isCurrent: boolean; - onPress: () => void; -}) => { - return ( - - {label} - - ); -}; diff --git a/apps/app/src/components/decisions/ProcessBuilder/navigation-config.ts b/apps/app/src/components/decisions/ProcessBuilder/navigation-config.ts index 5dcf1d896..4bd98b847 100644 --- a/apps/app/src/components/decisions/ProcessBuilder/navigation-config.ts +++ b/apps/app/src/components/decisions/ProcessBuilder/navigation-config.ts @@ -36,11 +36,11 @@ export const SECTIONS_BY_STEP = { // Derive SectionId from all sections across all steps export type SectionId = (typeof SECTIONS_BY_STEP)[StepId][number]['id']; -// Visibility configuration (from API) -export interface VisibilityConfig { +// Navigation configuration (from API) +export interface NavigationConfig { steps?: Partial>; sections?: Partial>; } -// Default visibility (all visible) -export const DEFAULT_VISIBILITY_CONFIG: VisibilityConfig = {}; +// Default navigation config (all visible) +export const DEFAULT_NAVIGATION_CONFIG: NavigationConfig = {}; diff --git a/apps/app/src/components/decisions/ProcessBuilder/useProcessNavigation.ts b/apps/app/src/components/decisions/ProcessBuilder/useProcessNavigation.ts index bf107eddf..664b5c432 100644 --- a/apps/app/src/components/decisions/ProcessBuilder/useProcessNavigation.ts +++ b/apps/app/src/components/decisions/ProcessBuilder/useProcessNavigation.ts @@ -4,16 +4,16 @@ import { useQueryState } from 'nuqs'; import { useCallback, useMemo } from 'react'; import { - DEFAULT_VISIBILITY_CONFIG, + DEFAULT_NAVIGATION_CONFIG, SECTIONS_BY_STEP, STEPS, + type NavigationConfig, type SectionId, type StepId, - type VisibilityConfig, } from './navigation-config'; export function useProcessNavigation( - visibilityConfig: VisibilityConfig = DEFAULT_VISIBILITY_CONFIG, + navigationConfig: NavigationConfig = DEFAULT_NAVIGATION_CONFIG, ) { const [stepParam, setStepParam] = useQueryState('step'); const [sectionParam, setSectionParam] = useQueryState('section'); @@ -22,11 +22,11 @@ export function useProcessNavigation( const visibleSteps = useMemo( () => STEPS.filter((s) => { - const visibility = visibilityConfig.steps?.[s.id]; + const visibility = navigationConfig.steps?.[s.id]; // Default to visible if not specified return visibility !== false; }), - [visibilityConfig.steps], + [navigationConfig.steps], ); // Current step (fallback to first visible step) @@ -42,7 +42,7 @@ export function useProcessNavigation( } const allSections = SECTIONS_BY_STEP[currentStep.id]; - const allowedSectionIds = visibilityConfig.sections?.[currentStep.id]; + const allowedSectionIds = navigationConfig.sections?.[currentStep.id]; // If no section config, show all sections for this step if (!allowedSectionIds) { @@ -53,7 +53,7 @@ export function useProcessNavigation( return allSections.filter((s) => allowedSectionIds.includes(s.id as SectionId), ); - }, [currentStep, visibilityConfig.sections]); + }, [currentStep, navigationConfig.sections]); // Current section (fallback to first visible section) const currentSection = useMemo(() => { @@ -71,7 +71,7 @@ export function useProcessNavigation( // Get first section of the new step const newStepSections = SECTIONS_BY_STEP[newStep.id]; - const allowedSectionIds = visibilityConfig.sections?.[newStep.id]; + const allowedSectionIds = navigationConfig.sections?.[newStep.id]; const firstVisibleSection = allowedSectionIds ? newStepSections.find((s) => allowedSectionIds.includes(s.id as SectionId), @@ -81,7 +81,7 @@ export function useProcessNavigation( setStepParam(newStepId); setSectionParam(firstVisibleSection?.id ?? null); }, - [visibleSteps, visibilityConfig.sections, setStepParam, setSectionParam], + [visibleSteps, navigationConfig.sections, setStepParam, setSectionParam], ); // Handle section change From dded85bdd8215b7785cc6567eb87b2b888a50ee5 Mon Sep 17 00:00:00 2001 From: Nour Malaeb Date: Wed, 21 Jan 2026 12:51:24 -0500 Subject: [PATCH 08/39] Add placeholdre content sections --- .../decisions/edit/[slug]/page.tsx | 12 +++-- .../ProcessBuilder/ProcessBuilderContent.tsx | 31 ++++++++++++ .../ProcessBuilder/content-registry.tsx | 50 +++++++++++++++++++ .../ProcessBuilder/navigation-config.ts | 5 +- .../sections/categories/LimitsSection.tsx | 15 ++++++ .../sections/categories/TypesSection.tsx | 15 ++++++ .../sections/overview/BasicsSection.tsx | 15 ++++++ .../sections/overview/PermissionsSection.tsx | 15 ++++++ .../sections/overview/TimelineSection.tsx | 15 ++++++ .../sections/phases/DeliberationSection.tsx | 15 ++++++ .../sections/phases/ReviewSection.tsx | 15 ++++++ .../sections/phases/SubmissionSection.tsx | 15 ++++++ .../sections/voting/MethodSection.tsx | 15 ++++++ .../sections/voting/QuorumSection.tsx | 15 ++++++ .../sections/voting/ResultsSection.tsx | 15 ++++++ .../ProcessBuilder/useProcessNavigation.ts | 2 +- 16 files changed, 258 insertions(+), 7 deletions(-) create mode 100644 apps/app/src/components/decisions/ProcessBuilder/ProcessBuilderContent.tsx create mode 100644 apps/app/src/components/decisions/ProcessBuilder/content-registry.tsx create mode 100644 apps/app/src/components/decisions/ProcessBuilder/sections/categories/LimitsSection.tsx create mode 100644 apps/app/src/components/decisions/ProcessBuilder/sections/categories/TypesSection.tsx create mode 100644 apps/app/src/components/decisions/ProcessBuilder/sections/overview/BasicsSection.tsx create mode 100644 apps/app/src/components/decisions/ProcessBuilder/sections/overview/PermissionsSection.tsx create mode 100644 apps/app/src/components/decisions/ProcessBuilder/sections/overview/TimelineSection.tsx create mode 100644 apps/app/src/components/decisions/ProcessBuilder/sections/phases/DeliberationSection.tsx create mode 100644 apps/app/src/components/decisions/ProcessBuilder/sections/phases/ReviewSection.tsx create mode 100644 apps/app/src/components/decisions/ProcessBuilder/sections/phases/SubmissionSection.tsx create mode 100644 apps/app/src/components/decisions/ProcessBuilder/sections/voting/MethodSection.tsx create mode 100644 apps/app/src/components/decisions/ProcessBuilder/sections/voting/QuorumSection.tsx create mode 100644 apps/app/src/components/decisions/ProcessBuilder/sections/voting/ResultsSection.tsx diff --git a/apps/app/src/app/[locale]/(no-header)/decisions/edit/[slug]/page.tsx b/apps/app/src/app/[locale]/(no-header)/decisions/edit/[slug]/page.tsx index 8c8e198c7..6c467699a 100644 --- a/apps/app/src/app/[locale]/(no-header)/decisions/edit/[slug]/page.tsx +++ b/apps/app/src/app/[locale]/(no-header)/decisions/edit/[slug]/page.tsx @@ -4,6 +4,7 @@ import { trpc } from '@op/api/client'; import { SidebarLayout } from '@op/ui/Sidebar'; import { notFound, useParams } from 'next/navigation'; +import { ProcessBuilderContent } from '@/components/decisions/ProcessBuilder/ProcessBuilderContent'; import { ProcessBuilderHeader } from '@/components/decisions/ProcessBuilder/ProcessBuilderHeader'; import { ProcessBuilderProvider } from '@/components/decisions/ProcessBuilder/ProcessBuilderProvider'; import { ProcessBuilderSidebar } from '@/components/decisions/ProcessBuilder/ProcessBuilderSidebar'; @@ -30,11 +31,12 @@ const EditDecisionPage = () => { -
- {/* Main content area - will show section content based on query param */} -

Editing: {decisionProfile.name}

- {/* TODO: Add section-specific content components */} -
+
+ +
); diff --git a/apps/app/src/components/decisions/ProcessBuilder/ProcessBuilderContent.tsx b/apps/app/src/components/decisions/ProcessBuilder/ProcessBuilderContent.tsx new file mode 100644 index 000000000..4db713951 --- /dev/null +++ b/apps/app/src/components/decisions/ProcessBuilder/ProcessBuilderContent.tsx @@ -0,0 +1,31 @@ +'use client'; + +import { Suspense } from 'react'; + +import { useProcessBuilderContext } from './ProcessBuilderProvider'; +import { type SectionProps, getContentComponent } from './content-registry'; +import { useProcessNavigation } from './useProcessNavigation'; + +export function ProcessBuilderContent({ + decisionId, + decisionName, +}: SectionProps) { + const { navigationConfig } = useProcessBuilderContext(); + const { currentStep, currentSection } = + useProcessNavigation(navigationConfig); + + const ContentComponent = getContentComponent( + currentStep?.id, + currentSection?.id, + ); + + if (!ContentComponent) { + return
Section not found
; + } + + return ( + Loading...
}> + + + ); +} diff --git a/apps/app/src/components/decisions/ProcessBuilder/content-registry.tsx b/apps/app/src/components/decisions/ProcessBuilder/content-registry.tsx new file mode 100644 index 000000000..089b54756 --- /dev/null +++ b/apps/app/src/components/decisions/ProcessBuilder/content-registry.tsx @@ -0,0 +1,50 @@ +'use client'; + +import { type ComponentType, lazy } from 'react'; + +import type { StepId } from './navigation-config'; + +// Props that all section components receive +export interface SectionProps { + decisionId: string; + decisionName: string; +} + +type SectionComponent = ComponentType; + +// Registry structure - allows partial coverage +type ContentRegistry = { + [S in StepId]?: Partial>; +}; + +const CONTENT_REGISTRY: ContentRegistry = { + overview: { + basics: lazy(() => import('./sections/overview/BasicsSection')), + timeline: lazy(() => import('./sections/overview/TimelineSection')), + permissions: lazy(() => import('./sections/overview/PermissionsSection')), + }, + phases: { + submission: lazy(() => import('./sections/phases/SubmissionSection')), + review: lazy(() => import('./sections/phases/ReviewSection')), + deliberation: lazy(() => import('./sections/phases/DeliberationSection')), + }, + categories: { + types: lazy(() => import('./sections/categories/TypesSection')), + limits: lazy(() => import('./sections/categories/LimitsSection')), + }, + voting: { + method: lazy(() => import('./sections/voting/MethodSection')), + quorum: lazy(() => import('./sections/voting/QuorumSection')), + results: lazy(() => import('./sections/voting/ResultsSection')), + }, +}; + +export function getContentComponent( + stepId: StepId | undefined, + sectionId: string | undefined, +): SectionComponent | null { + if (!stepId || !sectionId) { + return null; + } + return CONTENT_REGISTRY[stepId]?.[sectionId] ?? null; +} diff --git a/apps/app/src/components/decisions/ProcessBuilder/navigation-config.ts b/apps/app/src/components/decisions/ProcessBuilder/navigation-config.ts index 4bd98b847..ba487fda7 100644 --- a/apps/app/src/components/decisions/ProcessBuilder/navigation-config.ts +++ b/apps/app/src/components/decisions/ProcessBuilder/navigation-config.ts @@ -31,7 +31,10 @@ export const SECTIONS_BY_STEP = { { id: 'quorum', labelKey: 'Quorum' }, { id: 'results', labelKey: 'Results' }, ], -} as const satisfies Record; +} as const satisfies Record< + StepId, + readonly { id: string; labelKey: string }[] +>; // Derive SectionId from all sections across all steps export type SectionId = (typeof SECTIONS_BY_STEP)[StepId][number]['id']; diff --git a/apps/app/src/components/decisions/ProcessBuilder/sections/categories/LimitsSection.tsx b/apps/app/src/components/decisions/ProcessBuilder/sections/categories/LimitsSection.tsx new file mode 100644 index 000000000..36b165ee6 --- /dev/null +++ b/apps/app/src/components/decisions/ProcessBuilder/sections/categories/LimitsSection.tsx @@ -0,0 +1,15 @@ +import type { SectionProps } from '../../content-registry'; + +export default function LimitsSection({ + decisionId, + decisionName, +}: SectionProps) { + return ( +
+

Limits

+

Decision: {decisionName}

+

ID: {decisionId}

+ {/* TODO: Implement category limits configuration */} +
+ ); +} diff --git a/apps/app/src/components/decisions/ProcessBuilder/sections/categories/TypesSection.tsx b/apps/app/src/components/decisions/ProcessBuilder/sections/categories/TypesSection.tsx new file mode 100644 index 000000000..9748e0ef8 --- /dev/null +++ b/apps/app/src/components/decisions/ProcessBuilder/sections/categories/TypesSection.tsx @@ -0,0 +1,15 @@ +import type { SectionProps } from '../../content-registry'; + +export default function TypesSection({ + decisionId, + decisionName, +}: SectionProps) { + return ( +
+

Types

+

Decision: {decisionName}

+

ID: {decisionId}

+ {/* TODO: Implement proposal types configuration */} +
+ ); +} diff --git a/apps/app/src/components/decisions/ProcessBuilder/sections/overview/BasicsSection.tsx b/apps/app/src/components/decisions/ProcessBuilder/sections/overview/BasicsSection.tsx new file mode 100644 index 000000000..3e6002053 --- /dev/null +++ b/apps/app/src/components/decisions/ProcessBuilder/sections/overview/BasicsSection.tsx @@ -0,0 +1,15 @@ +import type { SectionProps } from '../../content-registry'; + +export default function BasicsSection({ + decisionId, + decisionName, +}: SectionProps) { + return ( +
+

Basics

+

Decision: {decisionName}

+

ID: {decisionId}

+ {/* TODO: Implement basics form */} +
+ ); +} diff --git a/apps/app/src/components/decisions/ProcessBuilder/sections/overview/PermissionsSection.tsx b/apps/app/src/components/decisions/ProcessBuilder/sections/overview/PermissionsSection.tsx new file mode 100644 index 000000000..523fa0c29 --- /dev/null +++ b/apps/app/src/components/decisions/ProcessBuilder/sections/overview/PermissionsSection.tsx @@ -0,0 +1,15 @@ +import type { SectionProps } from '../../content-registry'; + +export default function PermissionsSection({ + decisionId, + decisionName, +}: SectionProps) { + return ( +
+

Permissions

+

Decision: {decisionName}

+

ID: {decisionId}

+ {/* TODO: Implement permissions configuration */} +
+ ); +} diff --git a/apps/app/src/components/decisions/ProcessBuilder/sections/overview/TimelineSection.tsx b/apps/app/src/components/decisions/ProcessBuilder/sections/overview/TimelineSection.tsx new file mode 100644 index 000000000..94af8b27d --- /dev/null +++ b/apps/app/src/components/decisions/ProcessBuilder/sections/overview/TimelineSection.tsx @@ -0,0 +1,15 @@ +import type { SectionProps } from '../../content-registry'; + +export default function TimelineSection({ + decisionId, + decisionName, +}: SectionProps) { + return ( +
+

Timeline

+

Decision: {decisionName}

+

ID: {decisionId}

+ {/* TODO: Implement timeline configuration */} +
+ ); +} diff --git a/apps/app/src/components/decisions/ProcessBuilder/sections/phases/DeliberationSection.tsx b/apps/app/src/components/decisions/ProcessBuilder/sections/phases/DeliberationSection.tsx new file mode 100644 index 000000000..3340c0a08 --- /dev/null +++ b/apps/app/src/components/decisions/ProcessBuilder/sections/phases/DeliberationSection.tsx @@ -0,0 +1,15 @@ +import type { SectionProps } from '../../content-registry'; + +export default function DeliberationSection({ + decisionId, + decisionName, +}: SectionProps) { + return ( +
+

Deliberation

+

Decision: {decisionName}

+

ID: {decisionId}

+ {/* TODO: Implement deliberation phase configuration */} +
+ ); +} diff --git a/apps/app/src/components/decisions/ProcessBuilder/sections/phases/ReviewSection.tsx b/apps/app/src/components/decisions/ProcessBuilder/sections/phases/ReviewSection.tsx new file mode 100644 index 000000000..93495df67 --- /dev/null +++ b/apps/app/src/components/decisions/ProcessBuilder/sections/phases/ReviewSection.tsx @@ -0,0 +1,15 @@ +import type { SectionProps } from '../../content-registry'; + +export default function ReviewSection({ + decisionId, + decisionName, +}: SectionProps) { + return ( +
+

Review

+

Decision: {decisionName}

+

ID: {decisionId}

+ {/* TODO: Implement review phase configuration */} +
+ ); +} diff --git a/apps/app/src/components/decisions/ProcessBuilder/sections/phases/SubmissionSection.tsx b/apps/app/src/components/decisions/ProcessBuilder/sections/phases/SubmissionSection.tsx new file mode 100644 index 000000000..c0d2680a9 --- /dev/null +++ b/apps/app/src/components/decisions/ProcessBuilder/sections/phases/SubmissionSection.tsx @@ -0,0 +1,15 @@ +import type { SectionProps } from '../../content-registry'; + +export default function SubmissionSection({ + decisionId, + decisionName, +}: SectionProps) { + return ( +
+

Submission

+

Decision: {decisionName}

+

ID: {decisionId}

+ {/* TODO: Implement submission phase configuration */} +
+ ); +} diff --git a/apps/app/src/components/decisions/ProcessBuilder/sections/voting/MethodSection.tsx b/apps/app/src/components/decisions/ProcessBuilder/sections/voting/MethodSection.tsx new file mode 100644 index 000000000..6fcec20b7 --- /dev/null +++ b/apps/app/src/components/decisions/ProcessBuilder/sections/voting/MethodSection.tsx @@ -0,0 +1,15 @@ +import type { SectionProps } from '../../content-registry'; + +export default function MethodSection({ + decisionId, + decisionName, +}: SectionProps) { + return ( +
+

Voting Method

+

Decision: {decisionName}

+

ID: {decisionId}

+ {/* TODO: Implement voting method configuration */} +
+ ); +} diff --git a/apps/app/src/components/decisions/ProcessBuilder/sections/voting/QuorumSection.tsx b/apps/app/src/components/decisions/ProcessBuilder/sections/voting/QuorumSection.tsx new file mode 100644 index 000000000..964649fc1 --- /dev/null +++ b/apps/app/src/components/decisions/ProcessBuilder/sections/voting/QuorumSection.tsx @@ -0,0 +1,15 @@ +import type { SectionProps } from '../../content-registry'; + +export default function QuorumSection({ + decisionId, + decisionName, +}: SectionProps) { + return ( +
+

Quorum

+

Decision: {decisionName}

+

ID: {decisionId}

+ {/* TODO: Implement quorum configuration */} +
+ ); +} diff --git a/apps/app/src/components/decisions/ProcessBuilder/sections/voting/ResultsSection.tsx b/apps/app/src/components/decisions/ProcessBuilder/sections/voting/ResultsSection.tsx new file mode 100644 index 000000000..25c368c61 --- /dev/null +++ b/apps/app/src/components/decisions/ProcessBuilder/sections/voting/ResultsSection.tsx @@ -0,0 +1,15 @@ +import type { SectionProps } from '../../content-registry'; + +export default function ResultsSection({ + decisionId, + decisionName, +}: SectionProps) { + return ( +
+

Results

+

Decision: {decisionName}

+

ID: {decisionId}

+ {/* TODO: Implement results configuration */} +
+ ); +} diff --git a/apps/app/src/components/decisions/ProcessBuilder/useProcessNavigation.ts b/apps/app/src/components/decisions/ProcessBuilder/useProcessNavigation.ts index 664b5c432..6ccff524c 100644 --- a/apps/app/src/components/decisions/ProcessBuilder/useProcessNavigation.ts +++ b/apps/app/src/components/decisions/ProcessBuilder/useProcessNavigation.ts @@ -5,9 +5,9 @@ import { useCallback, useMemo } from 'react'; import { DEFAULT_NAVIGATION_CONFIG, + type NavigationConfig, SECTIONS_BY_STEP, STEPS, - type NavigationConfig, type SectionId, type StepId, } from './navigation-config'; From 38e58781cec03bc21595eeb5001863991f45151f Mon Sep 17 00:00:00 2001 From: Nour Malaeb Date: Wed, 21 Jan 2026 13:12:17 -0500 Subject: [PATCH 09/39] Loading skeleton for section content --- .../ProcessBuilder/ProcessBuilderContent.tsx | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/apps/app/src/components/decisions/ProcessBuilder/ProcessBuilderContent.tsx b/apps/app/src/components/decisions/ProcessBuilder/ProcessBuilderContent.tsx index 4db713951..4ca9d375d 100644 --- a/apps/app/src/components/decisions/ProcessBuilder/ProcessBuilderContent.tsx +++ b/apps/app/src/components/decisions/ProcessBuilder/ProcessBuilderContent.tsx @@ -1,5 +1,6 @@ 'use client'; +import { Skeleton } from '@op/ui/Skeleton'; import { Suspense } from 'react'; import { useProcessBuilderContext } from './ProcessBuilderProvider'; @@ -24,8 +25,19 @@ export function ProcessBuilderContent({ } return ( - Loading...
}> + }> ); } + +const ContentSkeleton = () => { + return ( +
+ + + + +
+ ); +}; From 049fa9df8b079f1cc83339053d54962c4f9306e6 Mon Sep 17 00:00:00 2001 From: Nour Malaeb Date: Wed, 21 Jan 2026 13:49:40 -0500 Subject: [PATCH 10/39] Remove lazy loading for now --- .../ProcessBuilder/ProcessBuilderContent.tsx | 19 +-------- .../ProcessBuilder/ProcessBuilderSidebar.tsx | 5 ++- .../ProcessBuilder/content-registry.tsx | 40 +++++++++++++------ 3 files changed, 34 insertions(+), 30 deletions(-) diff --git a/apps/app/src/components/decisions/ProcessBuilder/ProcessBuilderContent.tsx b/apps/app/src/components/decisions/ProcessBuilder/ProcessBuilderContent.tsx index 4ca9d375d..e5c4442bd 100644 --- a/apps/app/src/components/decisions/ProcessBuilder/ProcessBuilderContent.tsx +++ b/apps/app/src/components/decisions/ProcessBuilder/ProcessBuilderContent.tsx @@ -1,8 +1,5 @@ 'use client'; -import { Skeleton } from '@op/ui/Skeleton'; -import { Suspense } from 'react'; - import { useProcessBuilderContext } from './ProcessBuilderProvider'; import { type SectionProps, getContentComponent } from './content-registry'; import { useProcessNavigation } from './useProcessNavigation'; @@ -19,25 +16,13 @@ export function ProcessBuilderContent({ currentStep?.id, currentSection?.id, ); + const sectionKey = `${currentStep?.id}-${currentSection?.id}`; if (!ContentComponent) { return
Section not found
; } return ( - }> - - + ); } - -const ContentSkeleton = () => { - return ( -
- - - - -
- ); -}; diff --git a/apps/app/src/components/decisions/ProcessBuilder/ProcessBuilderSidebar.tsx b/apps/app/src/components/decisions/ProcessBuilder/ProcessBuilderSidebar.tsx index 6a8da73b5..365d84a6a 100644 --- a/apps/app/src/components/decisions/ProcessBuilder/ProcessBuilderSidebar.tsx +++ b/apps/app/src/components/decisions/ProcessBuilder/ProcessBuilderSidebar.tsx @@ -12,9 +12,11 @@ import { useProcessNavigation } from './useProcessNavigation'; export const ProcessBuilderSidebar = () => { const t = useTranslations(); const { navigationConfig } = useProcessBuilderContext(); - const { visibleSections, currentSection, setSection } = + const { visibleSections, currentSection, currentStep, setSection } = useProcessNavigation(navigationConfig); + console.log('[Sidebar] currentStep:', currentStep?.id, 'currentSection:', currentSection?.id, 'visibleSections:', visibleSections.length); + const handleSelectionChange = (key: Key) => { setSection(String(key)); }; @@ -23,6 +25,7 @@ export const ProcessBuilderSidebar = () => { {visibleSections.length > 0 && ( import('./sections/overview/BasicsSection')), - timeline: lazy(() => import('./sections/overview/TimelineSection')), - permissions: lazy(() => import('./sections/overview/PermissionsSection')), + basics: BasicsSection, + timeline: TimelineSection, + permissions: PermissionsSection, }, phases: { - submission: lazy(() => import('./sections/phases/SubmissionSection')), - review: lazy(() => import('./sections/phases/ReviewSection')), - deliberation: lazy(() => import('./sections/phases/DeliberationSection')), + submission: SubmissionSection, + review: ReviewSection, + deliberation: DeliberationSection, }, categories: { - types: lazy(() => import('./sections/categories/TypesSection')), - limits: lazy(() => import('./sections/categories/LimitsSection')), + types: TypesSection, + limits: LimitsSection, }, voting: { - method: lazy(() => import('./sections/voting/MethodSection')), - quorum: lazy(() => import('./sections/voting/QuorumSection')), - results: lazy(() => import('./sections/voting/ResultsSection')), + method: MethodSection, + quorum: QuorumSection, + results: ResultsSection, }, }; +// No-op for now (no lazy loading to preload) +export function preloadAllSections() {} + export function getContentComponent( stepId: StepId | undefined, sectionId: string | undefined, From 1cd12b77faa0fc4130c3c6e44bf6f9d597c1c2cd Mon Sep 17 00:00:00 2001 From: Nour Malaeb Date: Wed, 21 Jan 2026 13:50:52 -0500 Subject: [PATCH 11/39] Cleanup --- .../decisions/ProcessBuilder/ProcessBuilderContent.tsx | 1 - .../decisions/ProcessBuilder/ProcessBuilderSidebar.tsx | 2 -- .../components/decisions/ProcessBuilder/content-registry.tsx | 5 ++--- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/apps/app/src/components/decisions/ProcessBuilder/ProcessBuilderContent.tsx b/apps/app/src/components/decisions/ProcessBuilder/ProcessBuilderContent.tsx index e5c4442bd..1b55a0845 100644 --- a/apps/app/src/components/decisions/ProcessBuilder/ProcessBuilderContent.tsx +++ b/apps/app/src/components/decisions/ProcessBuilder/ProcessBuilderContent.tsx @@ -16,7 +16,6 @@ export function ProcessBuilderContent({ currentStep?.id, currentSection?.id, ); - const sectionKey = `${currentStep?.id}-${currentSection?.id}`; if (!ContentComponent) { return
Section not found
; diff --git a/apps/app/src/components/decisions/ProcessBuilder/ProcessBuilderSidebar.tsx b/apps/app/src/components/decisions/ProcessBuilder/ProcessBuilderSidebar.tsx index 365d84a6a..7d7fdcda0 100644 --- a/apps/app/src/components/decisions/ProcessBuilder/ProcessBuilderSidebar.tsx +++ b/apps/app/src/components/decisions/ProcessBuilder/ProcessBuilderSidebar.tsx @@ -15,8 +15,6 @@ export const ProcessBuilderSidebar = () => { const { visibleSections, currentSection, currentStep, setSection } = useProcessNavigation(navigationConfig); - console.log('[Sidebar] currentStep:', currentStep?.id, 'currentSection:', currentSection?.id, 'visibleSections:', visibleSections.length); - const handleSelectionChange = (key: Key) => { setSection(String(key)); }; diff --git a/apps/app/src/components/decisions/ProcessBuilder/content-registry.tsx b/apps/app/src/components/decisions/ProcessBuilder/content-registry.tsx index 10a0d4c1e..f81f477cd 100644 --- a/apps/app/src/components/decisions/ProcessBuilder/content-registry.tsx +++ b/apps/app/src/components/decisions/ProcessBuilder/content-registry.tsx @@ -3,7 +3,8 @@ import { type ComponentType } from 'react'; import type { StepId } from './navigation-config'; - +import LimitsSection from './sections/categories/LimitsSection'; +import TypesSection from './sections/categories/TypesSection'; // Direct imports (no lazy loading) - test if this fixes skeleton flash import BasicsSection from './sections/overview/BasicsSection'; import PermissionsSection from './sections/overview/PermissionsSection'; @@ -11,8 +12,6 @@ import TimelineSection from './sections/overview/TimelineSection'; import DeliberationSection from './sections/phases/DeliberationSection'; import ReviewSection from './sections/phases/ReviewSection'; import SubmissionSection from './sections/phases/SubmissionSection'; -import LimitsSection from './sections/categories/LimitsSection'; -import TypesSection from './sections/categories/TypesSection'; import MethodSection from './sections/voting/MethodSection'; import QuorumSection from './sections/voting/QuorumSection'; import ResultsSection from './sections/voting/ResultsSection'; From cb4464d7a667462d4eaee3c4e27755e300c51051 Mon Sep 17 00:00:00 2001 From: Nour Malaeb Date: Wed, 21 Jan 2026 14:00:53 -0500 Subject: [PATCH 12/39] Replace placeholder content --- .../decisions/edit/[slug]/page.tsx | 2 +- .../ProcessBuilder/ProcessBuilderHeader.tsx | 8 ++++-- .../ProcessBuilder/content-registry.tsx | 3 -- .../ProcessBuilder/navigation-config.ts | 28 +++++++++---------- 4 files changed, 21 insertions(+), 20 deletions(-) diff --git a/apps/app/src/app/[locale]/(no-header)/decisions/edit/[slug]/page.tsx b/apps/app/src/app/[locale]/(no-header)/decisions/edit/[slug]/page.tsx index 6c467699a..ca8024dd4 100644 --- a/apps/app/src/app/[locale]/(no-header)/decisions/edit/[slug]/page.tsx +++ b/apps/app/src/app/[locale]/(no-header)/decisions/edit/[slug]/page.tsx @@ -28,7 +28,7 @@ const EditDecisionPage = () => { return ( - +
diff --git a/apps/app/src/components/decisions/ProcessBuilder/ProcessBuilderHeader.tsx b/apps/app/src/components/decisions/ProcessBuilder/ProcessBuilderHeader.tsx index da75f6e12..43b03d101 100644 --- a/apps/app/src/components/decisions/ProcessBuilder/ProcessBuilderHeader.tsx +++ b/apps/app/src/components/decisions/ProcessBuilder/ProcessBuilderHeader.tsx @@ -12,7 +12,11 @@ import { UserAvatarMenu } from '@/components/SiteHeader'; import { useProcessBuilderContext } from './ProcessBuilderProvider'; import { useProcessNavigation } from './useProcessNavigation'; -export const ProcessBuilderHeader = () => { +export const ProcessBuilderHeader = ({ + processName, +}: { + processName?: string; +}) => { const t = useTranslations(); const { navigationConfig } = useProcessBuilderContext(); const { visibleSteps, currentStep, setStep } = @@ -30,7 +34,7 @@ export const ProcessBuilderHeader = () => { {t('Home')} - {t('New process')} + {processName || t('New process')}