Skip to content

Commit a64ba86

Browse files
committed
Move Wizard to ConfigureSSO folder
1 parent ae49754 commit a64ba86

13 files changed

Lines changed: 109 additions & 112 deletions

packages/ui/src/components/ConfigureSSO/ConfigureSSO.tsx

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ import { ApplicationLogo } from '@/elements/ApplicationLogo';
88
import { withCardStateProvider } from '@/elements/contexts';
99
import { NavBar, NavbarContextProvider } from '@/elements/Navbar';
1010
import { ProfileCard } from '@/elements/ProfileCard';
11-
import { Wizard } from '@/elements/Wizard';
1211
import { BoxIcon } from '@/icons';
1312
import { Route, Switch } from '@/router';
1413

15-
import { ConfigureSSOFlowProvider, useConfigureSSOFlow } from './ConfigureSSOContext';
14+
import { ConfigureSSOFlowProvider } from './ConfigureSSOContext';
1615
import { CONFIGURE_SSO_STEPS } from './constants';
16+
import { ConfigureSSOWizard } from './wizard';
1717

1818
const ConfigureSSOInternal = () => {
1919
return (
@@ -117,30 +117,18 @@ const AuthenticatedContent = withCoreUserGuard(() => {
117117
enterpriseConnection={enterpriseConnection}
118118
isLoading={isLoadingEnterpriseConnections}
119119
>
120-
<ConfigureSSOWizardPanel />
120+
<ConfigureSSOWizard.Root steps={CONFIGURE_SSO_STEPS}>
121+
<ConfigureSSOWizard.Header />
122+
<ConfigureSSOWizard.Content />
123+
<ConfigureSSOWizard.Footer />
124+
</ConfigureSSOWizard.Root>
121125
</ConfigureSSOFlowProvider>
122126
</Col>
123127
</NavbarContextProvider>
124128
</ProfileCard.Root>
125129
);
126130
});
127131

128-
const ConfigureSSOWizardPanel = () => {
129-
const data = useConfigureSSOFlow();
130-
131-
return (
132-
<Wizard.Root
133-
steps={CONFIGURE_SSO_STEPS}
134-
data={data}
135-
isLoading={data.isLoading}
136-
>
137-
<Wizard.Header />
138-
<Wizard.Content />
139-
<Wizard.Footer />
140-
</Wizard.Root>
141-
);
142-
};
143-
144132
const OrganizationSidebarSubtitle = () => {
145133
const { organization } = useOrganization();
146134

packages/ui/src/components/ConfigureSSO/ConfigureSSOContext.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ import React, { type PropsWithChildren } from 'react';
44

55
/**
66
* Shared form state for the ConfigureSSO wizard, persisted across step
7-
* route mounts and exposed to `WizardStep.shouldSkip` via `Wizard.Root`'s
8-
* `data` prop
7+
* route mounts. Sourced by the wizard via `useConfigureSSOFlow()` and
8+
* passed to each step's `shouldSkip` predicate
99
*/
1010
export interface ConfigureSSOData {
1111
/**

packages/ui/src/components/ConfigureSSO/constants.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
import type { WizardStep } from '@/elements/Wizard';
2-
3-
import type { ConfigureSSOData } from './ConfigureSSOContext';
41
import {
52
ConfigureCreateApp,
63
ConfigureMapAttributes,
@@ -9,8 +6,9 @@ import {
96
TestConfigurationStep,
107
VerifyDomain,
118
} from './steps';
9+
import type { ConfigureSSOWizardStep } from './wizard';
1210

13-
export const CONFIGURE_SSO_STEPS: ReadonlyArray<WizardStep<ConfigureSSOData>> = [
11+
export const CONFIGURE_SSO_STEPS: ReadonlyArray<ConfigureSSOWizardStep> = [
1412
{
1513
id: 'verify-email-domain',
1614
path: 'verify-email-domain',

packages/ui/src/components/ConfigureSSO/steps/ConfigureCreateAppStep.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import { Flow, Text } from '@/customizables';
2-
import { useRegisterContinueAction, useWizard } from '@/elements/Wizard';
32

3+
import { useConfigureSSOWizard, useRegisterContinueAction } from '../wizard';
44
import { StepLayout } from './StepLayout';
55

66
export const ConfigureCreateApp = (): JSX.Element => {
7-
const { goNext } = useWizard();
7+
const { goNext } = useConfigureSSOWizard();
88

99
useRegisterContinueAction({
1010
handler: () => goNext(),

packages/ui/src/components/ConfigureSSO/steps/ConfigureMapAttributesStep.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import { Flow, Text } from '@/customizables';
2-
import { useRegisterContinueAction, useWizard } from '@/elements/Wizard';
32

3+
import { useConfigureSSOWizard, useRegisterContinueAction } from '../wizard';
44
import { StepLayout } from './StepLayout';
55

66
export const ConfigureMapAttributes = (): JSX.Element => {
7-
const { goNext } = useWizard();
7+
const { goNext } = useConfigureSSOWizard();
88

99
useRegisterContinueAction({
1010
handler: () => goNext(),

packages/ui/src/components/ConfigureSSO/steps/ProvideEmailStep.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import { Flow, Text } from '@/customizables';
2-
import { useRegisterContinueAction, useWizard } from '@/elements/Wizard';
32

3+
import { useConfigureSSOWizard, useRegisterContinueAction } from '../wizard';
44
import { StepLayout } from './StepLayout';
55

66
export const ProvideEmail = (): JSX.Element => {
7-
const { goNext } = useWizard();
7+
const { goNext } = useConfigureSSOWizard();
88

99
useRegisterContinueAction({
1010
handler: () => {

packages/ui/src/components/ConfigureSSO/steps/StepLayout.tsx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import React from 'react';
22

33
import { Col, Flex, Heading, Text } from '@/customizables';
4-
import { Wizard } from '@/elements/Wizard';
4+
5+
import { ConfigureSSOWizard } from '../wizard';
56

67
interface StepLayoutProps {
78
title?: React.ReactNode;
@@ -13,8 +14,8 @@ interface StepLayoutProps {
1314
* Renders the title row (with the Wizard's Step X/Y badge) on top, a divider, and the step body
1415
* underneath. Each individual step file owns the body content
1516
*
16-
* The Step X/Y badge is rendered via `Wizard.StepIndicator`, which
17-
* self-hides on steps that have no inner sub-steps
17+
* The Step X/Y badge is rendered via `ConfigureSSOWizard.StepIndicator`,
18+
* which self-hides on steps that have no inner sub-steps
1819
*/
1920
export const StepLayout = ({ title, subtitle, children }: StepLayoutProps): JSX.Element => {
2021
return (
@@ -52,7 +53,7 @@ export const StepLayout = ({ title, subtitle, children }: StepLayoutProps): JSX.
5253
) : null}
5354
</Col>
5455
) : null}
55-
<Wizard.StepIndicator />
56+
<ConfigureSSOWizard.StepIndicator />
5657
</Flex>
5758
<Col
5859
sx={theme => ({

packages/ui/src/components/ConfigureSSO/steps/VerifyDomainStep.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import { Flow, Text } from '@/customizables';
2-
import { useRegisterContinueAction, useWizard } from '@/elements/Wizard';
32

3+
import { useConfigureSSOWizard, useRegisterContinueAction } from '../wizard';
44
import { StepLayout } from './StepLayout';
55

66
export const VerifyDomain = (): JSX.Element => {
7-
const { goNext } = useWizard();
7+
const { goNext } = useConfigureSSOWizard();
88

99
useRegisterContinueAction({
1010
handler: () => goNext(),

packages/ui/src/elements/Wizard/Wizard.tsx renamed to packages/ui/src/components/ConfigureSSO/wizard/ConfigureSSOWizard.tsx

Lines changed: 29 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -4,38 +4,35 @@ import { Badge, Box, Button, descriptors, Flex, Icon, Spinner, Text, useLocaliza
44
import { CaretLeft, CaretRight } from '@/icons';
55
import { Route, Switch, useRouter } from '@/router';
66

7-
import type { WizardInnerStep, WizardStep } from './types';
8-
import { useWizard, WizardProvider } from './WizardContext';
7+
import { useConfigureSSOFlow } from '../ConfigureSSOContext';
8+
import { ConfigureSSOWizardProvider, useConfigureSSOWizard } from './ConfigureSSOWizardContext';
9+
import type { ConfigureSSOWizardInnerStep, ConfigureSSOWizardStep } from './types';
910

10-
interface WizardRootProps<TData = unknown> {
11-
steps: ReadonlyArray<WizardStep<TData>>;
12-
/**
13-
* Optional data passed to each step's `shouldSkip` predicate. When the
14-
* referenced shape changes, the active step list is recomputed
15-
*/
16-
data?: TData;
17-
/**
18-
* `true` while the parent flow is still loading async dependencies.
19-
* The header renders a skeleton breadcrumb, the content renders a
20-
* centered spinner, and the footer's buttons are disabled
21-
*/
22-
isLoading?: boolean;
11+
interface ConfigureSSOWizardRootProps {
12+
steps: ReadonlyArray<ConfigureSSOWizardStep>;
2313
children: React.ReactNode;
2414
}
2515

26-
const Root = <TData,>(props: WizardRootProps<TData>): JSX.Element => {
27-
const { steps, data, isLoading = false, children } = props;
16+
/**
17+
* Top-level wizard scaffold for the ConfigureSSO flow. Sources its
18+
* `data` and `isLoading` from `useConfigureSSOFlow()` directly, so it
19+
* must be rendered inside `<ConfigureSSOFlowProvider>`
20+
*/
21+
const Root = (props: ConfigureSSOWizardRootProps): JSX.Element => {
22+
const { steps, children } = props;
2823
const router = useRouter();
24+
const data = useConfigureSSOFlow();
25+
const { isLoading } = data;
2926

30-
const activeSteps = React.useMemo(() => steps.filter(s => !s.shouldSkip?.(data as TData)), [steps, data]);
27+
const activeSteps = React.useMemo(() => steps.filter(s => !s.shouldSkip?.(data)), [steps, data]);
3128

3229
const getActiveInnerSteps = React.useCallback(
33-
(step: WizardStep<TData> | undefined): WizardInnerStep<TData>[] =>
34-
step?.innerSteps?.filter(s => !s.shouldSkip?.(data as TData)) ?? [],
30+
(step: ConfigureSSOWizardStep | undefined): ConfigureSSOWizardInnerStep[] =>
31+
step?.innerSteps?.filter(s => !s.shouldSkip?.(data)) ?? [],
3532
[data],
3633
);
3734

38-
const currentStep = React.useMemo<WizardStep<TData> | undefined>(() => {
35+
const currentStep = React.useMemo<ConfigureSSOWizardStep | undefined>(() => {
3936
if (activeSteps.length === 0) {
4037
return undefined;
4138
}
@@ -57,7 +54,7 @@ const Root = <TData,>(props: WizardRootProps<TData>): JSX.Element => {
5754
// is the catch-all, the first inner step of any main
5855
// step is its parent's index route (no segment)
5956
const buildPath = React.useCallback(
60-
(mainStep: WizardStep<TData>, innerStep?: WizardInnerStep<TData>): string => {
57+
(mainStep: ConfigureSSOWizardStep, innerStep?: ConfigureSSOWizardInnerStep): string => {
6158
const inners = getActiveInnerSteps(mainStep);
6259
const target = innerStep ?? inners[0];
6360
const isFirstMain = activeSteps[0]?.id === mainStep.id;
@@ -68,7 +65,7 @@ const Root = <TData,>(props: WizardRootProps<TData>): JSX.Element => {
6865
[activeSteps, getActiveInnerSteps],
6966
);
7067

71-
const currentInnerStep = React.useMemo<WizardInnerStep<TData> | undefined>(() => {
68+
const currentInnerStep = React.useMemo<ConfigureSSOWizardInnerStep | undefined>(() => {
7269
if (!currentStep || innerSteps.length === 0) {
7370
return undefined;
7471
}
@@ -82,7 +79,7 @@ const Root = <TData,>(props: WizardRootProps<TData>): JSX.Element => {
8279
}, [currentStep, innerSteps, router, buildPath]);
8380

8481
const navigateTo = React.useCallback(
85-
(mainStep: WizardStep<TData> | undefined, innerStep?: WizardInnerStep<TData>) =>
82+
(mainStep: ConfigureSSOWizardStep | undefined, innerStep?: ConfigureSSOWizardInnerStep) =>
8683
mainStep ? router.navigate(buildPath(mainStep, innerStep)) : undefined,
8784
[router, buildPath],
8885
);
@@ -128,7 +125,7 @@ const Root = <TData,>(props: WizardRootProps<TData>): JSX.Element => {
128125
);
129126

130127
return (
131-
<WizardProvider
128+
<ConfigureSSOWizardProvider
132129
activeSteps={activeSteps}
133130
currentStep={currentStep}
134131
innerSteps={innerSteps}
@@ -139,15 +136,15 @@ const Root = <TData,>(props: WizardRootProps<TData>): JSX.Element => {
139136
goToStep={goToStep}
140137
>
141138
{children}
142-
</WizardProvider>
139+
</ConfigureSSOWizardProvider>
143140
);
144141
};
145142

146143
/**
147144
* Renders a container step's inner sub-routes, or falls back to the
148145
* step's own `Component` for leaf steps
149146
*/
150-
const StepRoutes = <TData,>({ step }: { step: WizardStep<TData> }): JSX.Element | null => {
147+
const StepRoutes = ({ step }: { step: ConfigureSSOWizardStep }): JSX.Element | null => {
151148
const Component = step.Component;
152149
if (!step.innerSteps?.length) {
153150
return Component ? <Component /> : null;
@@ -176,7 +173,7 @@ const StepRoutes = <TData,>({ step }: { step: WizardStep<TData> }): JSX.Element
176173
* doesn't match another main step (e.g. its own inner-step paths)
177174
*/
178175
const Content = (): JSX.Element | null => {
179-
const { activeSteps, isLoading } = useWizard();
176+
const { activeSteps, isLoading } = useConfigureSSOWizard();
180177

181178
if (isLoading) {
182179
return (
@@ -222,7 +219,7 @@ const Content = (): JSX.Element | null => {
222219
* are clickable for backwards navigation, future steps are disabled
223220
*/
224221
const Header = (): JSX.Element => {
225-
const { activeSteps, currentIndex, isLoading, goToStep } = useWizard();
222+
const { activeSteps, currentIndex, isLoading, goToStep } = useConfigureSSOWizard();
226223
const { t } = useLocalizations();
227224

228225
return (
@@ -335,7 +332,7 @@ const SkeletonBreadcrumbStep = (): JSX.Element => (
335332
* need to reserve room for it
336333
*/
337334
const StepIndicator = (): JSX.Element | null => {
338-
const { totalInnerSteps, currentInnerIndex } = useWizard();
335+
const { totalInnerSteps, currentInnerIndex } = useConfigureSSOWizard();
339336

340337
if (totalInnerSteps <= 0 || currentInnerIndex < 0) {
341338
return null;
@@ -391,7 +388,7 @@ interface FooterProps {
391388
*/
392389
const Footer = (props: FooterProps): JSX.Element => {
393390
const { previousLabel = 'Previous', continueLabel = 'Continue', hidePrevious = false, isDisabled = false } = props;
394-
const { isFirstStep, isLastStep, isLoading, goPrev, goNext, continueAction } = useWizard();
391+
const { isFirstStep, isLastStep, isLoading, goPrev, goNext, continueAction } = useConfigureSSOWizard();
395392
const isForceDisabled = isDisabled || isLoading;
396393
const { t } = useLocalizations();
397394

@@ -457,7 +454,7 @@ const Footer = (props: FooterProps): JSX.Element => {
457454
);
458455
};
459456

460-
export const Wizard = {
457+
export const ConfigureSSOWizard = {
461458
Root,
462459
Header,
463460
Content,

packages/ui/src/elements/Wizard/WizardContext.tsx renamed to packages/ui/src/components/ConfigureSSO/wizard/ConfigureSSOWizardContext.tsx

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,38 @@
11
import React from 'react';
22

3-
import type { ContinueAction, WizardContextValue, WizardInnerStep, WizardStep } from './types';
3+
import type {
4+
ConfigureSSOWizardContextValue,
5+
ConfigureSSOWizardInnerStep,
6+
ConfigureSSOWizardStep,
7+
ContinueAction,
8+
} from './types';
49

5-
const WizardContext = React.createContext<WizardContextValue<any> | null>(null);
6-
WizardContext.displayName = 'WizardContext';
10+
const ConfigureSSOWizardContext = React.createContext<ConfigureSSOWizardContextValue | null>(null);
11+
ConfigureSSOWizardContext.displayName = 'ConfigureSSOWizardContext';
712

8-
export function useWizard<TData = unknown>(): WizardContextValue<TData> {
9-
const ctx = React.useContext(WizardContext);
13+
export function useConfigureSSOWizard(): ConfigureSSOWizardContextValue {
14+
const ctx = React.useContext(ConfigureSSOWizardContext);
1015

1116
if (!ctx) {
12-
throw new Error('useWizard called outside of <Wizard.Root>');
17+
throw new Error('useConfigureSSOWizard called outside of <ConfigureSSOWizard.Root>');
1318
}
1419

15-
return ctx as WizardContextValue<TData>;
20+
return ctx;
1621
}
1722

18-
interface WizardProviderProps<TData> {
19-
activeSteps: WizardStep<TData>[];
20-
currentStep: WizardStep<TData> | undefined;
21-
innerSteps: WizardInnerStep<TData>[];
22-
currentInnerStep: WizardInnerStep<TData> | undefined;
23+
interface ConfigureSSOWizardProviderProps {
24+
activeSteps: ConfigureSSOWizardStep[];
25+
currentStep: ConfigureSSOWizardStep | undefined;
26+
innerSteps: ConfigureSSOWizardInnerStep[];
27+
currentInnerStep: ConfigureSSOWizardInnerStep | undefined;
2328
isLoading: boolean;
24-
goNext: WizardContextValue<TData>['goNext'];
25-
goPrev: WizardContextValue<TData>['goPrev'];
26-
goToStep: WizardContextValue<TData>['goToStep'];
29+
goNext: ConfigureSSOWizardContextValue['goNext'];
30+
goPrev: ConfigureSSOWizardContextValue['goPrev'];
31+
goToStep: ConfigureSSOWizardContextValue['goToStep'];
2732
children: React.ReactNode;
2833
}
2934

30-
export function WizardProvider<TData>(props: WizardProviderProps<TData>): JSX.Element {
35+
export function ConfigureSSOWizardProvider(props: ConfigureSSOWizardProviderProps): JSX.Element {
3136
const { activeSteps, currentStep, innerSteps, currentInnerStep, isLoading, goNext, goPrev, goToStep, children } =
3237
props;
3338

@@ -38,7 +43,7 @@ export function WizardProvider<TData>(props: WizardProviderProps<TData>): JSX.El
3843
setContinueAction(undefined);
3944
}, [currentStep?.id, currentInnerStep?.id]);
4045

41-
const value = React.useMemo<WizardContextValue<TData>>(() => {
46+
const value = React.useMemo<ConfigureSSOWizardContextValue>(() => {
4247
const currentIndex = currentStep ? activeSteps.findIndex(s => s.id === currentStep.id) : -1;
4348
const currentInnerIndex = currentInnerStep ? innerSteps.findIndex(s => s.id === currentInnerStep.id) : -1;
4449
const totalInnerSteps = innerSteps.length;
@@ -68,14 +73,14 @@ export function WizardProvider<TData>(props: WizardProviderProps<TData>): JSX.El
6873
};
6974
}, [activeSteps, currentStep, innerSteps, currentInnerStep, isLoading, goNext, goPrev, goToStep, continueAction]);
7075

71-
return <WizardContext.Provider value={value}>{children}</WizardContext.Provider>;
76+
return <ConfigureSSOWizardContext.Provider value={value}>{children}</ConfigureSSOWizardContext.Provider>;
7277
}
7378

7479
/**
7580
* Helper for step components that need to register a Continue action
7681
*/
7782
export function useRegisterContinueAction(action: ContinueAction | undefined): void {
78-
const { setContinueAction } = useWizard();
83+
const { setContinueAction } = useConfigureSSOWizard();
7984

8085
const handlerRef = React.useRef<ContinueAction['handler'] | undefined>(action?.handler);
8186
handlerRef.current = action?.handler;

0 commit comments

Comments
 (0)