* intro work * update wixard form to have content callback to remove preset navigation * more fixes to deployment * fix calling static service * fix save license key text * ensure default steps work as expected * fix conditional for rendering step * skip step * add on next step for free license * refactor wizard form to use nuqs * fix styles * merge base param with step config * fix next stepo text * use deployment Signature token * decrypt signature token * fix: resolve type errors and test failures from wizard form refactor - Fix signatureToken field name to signatureTokenEncrypted in deployment repository - Add missing getSignatureToken method to verifyApiKey test mock - Fix WizardForm import from default to named export in test file - Add missing nextStep prop to Steps component in WizardForm Resolves TypeScript type check errors and unit test failures without changing functionality. Co-Authored-By: sean@cal.com <Sean@brydon.io> * fix: add missing getDeploymentSignatureToken mock in LicenseKeyService test Co-Authored-By: sean@cal.com <Sean@brydon.io> * fix: add nuqs library mock for WizardForm test Co-Authored-By: sean@cal.com <Sean@brydon.io> * fix: add missing nav prop to AdminAppsList component with eslint disable Co-Authored-By: sean@cal.com <Sean@brydon.io> * Apply suggestions from code review Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com> * Update apps/web/modules/auth/setup-view.tsx Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com> * fix license schema changes * revret schema generation * fix eslint errors * remove required nav type + add use client * fix types * Update packages/ui/components/form/wizard/useWizardState.ts Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com> * fix controller issue * add checks for deployment key being null - add more tests * fix tests * add deployment key tests * fix: resolve crypto mock to handle empty encryption keys gracefully - Updated symmetricDecrypt mock to return null instead of throwing 'Invalid key' error when encryption key is empty - All getDeploymentKey tests now pass including the previously failing 'should return null when decryption fails due to missing encryption key' test - Fixes mocking issues in PR 22102 self-hosted onboarding wizard form refactor Co-Authored-By: sean@cal.com <Sean@brydon.io> * fix label * add i18n to error * use enum for steps * add as const * fix test env issues --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
121 lines
3.6 KiB
TypeScript
121 lines
3.6 KiB
TypeScript
"use client";
|
|
|
|
import type { Dispatch, SetStateAction } from "react";
|
|
import { useEffect, useState } from "react";
|
|
|
|
import classNames from "@calcom/ui/classNames";
|
|
|
|
import { Button } from "../../button";
|
|
import { Steps } from "../../form/step";
|
|
import { useWizardState } from "./useWizardState";
|
|
|
|
export type WizardStep = {
|
|
title: string;
|
|
containerClassname?: string;
|
|
contentClassname?: string;
|
|
description: string;
|
|
content?:
|
|
| ((
|
|
setIsPending: Dispatch<SetStateAction<boolean>>,
|
|
nav: { onNext: () => void; onPrev: () => void; step: number; maxSteps: number }
|
|
) => JSX.Element)
|
|
| JSX.Element;
|
|
isEnabled?: boolean;
|
|
isPending?: boolean;
|
|
customActions?: boolean;
|
|
};
|
|
|
|
export interface WizardFormProps {
|
|
steps: WizardStep[];
|
|
containerClassname?: string;
|
|
prevLabel?: string;
|
|
nextLabel?: string;
|
|
finishLabel?: string;
|
|
stepLabel?: React.ComponentProps<typeof Steps>["stepLabel"];
|
|
defaultStep?: number;
|
|
disableNavigation?: boolean;
|
|
}
|
|
|
|
export function WizardForm({
|
|
steps,
|
|
containerClassname,
|
|
prevLabel = "Back",
|
|
nextLabel = "Next",
|
|
finishLabel = "Finish",
|
|
stepLabel,
|
|
defaultStep = 1,
|
|
disableNavigation = false,
|
|
}: WizardFormProps) {
|
|
const { currentStep, maxSteps, nextStep, prevStep, isFirstStep, isLastStep } = useWizardState(
|
|
defaultStep,
|
|
steps.length
|
|
);
|
|
const [currentStepisPending, setCurrentStepisPending] = useState(false);
|
|
const currentStepData = steps[currentStep - 1];
|
|
|
|
useEffect(() => {
|
|
setCurrentStepisPending(false);
|
|
}, [currentStep]);
|
|
|
|
return (
|
|
<div className="mx-auto mt-4 print:w-full" data-testid="wizard-form">
|
|
<div className={classNames("overflow-hidden md:mb-2 md:w-[700px]", containerClassname)}>
|
|
<div className="px-6 py-5">
|
|
<h1 className="font-cal text-emphasis text-2xl" data-testid="step-title">
|
|
{currentStepData.title}
|
|
</h1>
|
|
<p className="text-subtle text-sm" data-testid="step-description">
|
|
{currentStepData.description}
|
|
</p>
|
|
{!disableNavigation && (
|
|
<Steps
|
|
maxSteps={maxSteps}
|
|
currentStep={currentStep}
|
|
nextStep={nextStep}
|
|
stepLabel={stepLabel}
|
|
data-testid="wizard-step-component"
|
|
disableNavigation={disableNavigation}
|
|
/>
|
|
)}
|
|
</div>
|
|
</div>
|
|
<div className={classNames("mb-8 overflow-hidden md:w-[700px]", containerClassname)}>
|
|
<div
|
|
className={classNames(
|
|
"bg-default border-subtle max-w-3xl rounded-2xl border px-4 py-3 sm:p-4 ",
|
|
currentStepData.contentClassname
|
|
)}>
|
|
{typeof currentStepData.content === "function"
|
|
? currentStepData.content(setCurrentStepisPending, {
|
|
onNext: nextStep,
|
|
onPrev: prevStep,
|
|
step: currentStep,
|
|
maxSteps,
|
|
})
|
|
: currentStepData.content}
|
|
</div>
|
|
{!disableNavigation && !currentStepData.customActions && (
|
|
<div className="flex justify-end px-4 py-4 print:hidden sm:px-6">
|
|
{!isFirstStep && (
|
|
<Button color="secondary" onClick={prevStep}>
|
|
{prevLabel}
|
|
</Button>
|
|
)}
|
|
|
|
<Button
|
|
tabIndex={0}
|
|
loading={currentStepisPending}
|
|
type="submit"
|
|
color="primary"
|
|
form={`wizard-step-${currentStep}`}
|
|
disabled={currentStepData.isEnabled === false}
|
|
className="relative ml-2">
|
|
{isLastStep ? finishLabel : nextLabel}
|
|
</Button>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|