Files
HiveGrid-Wireframes/hivegrid-cloud/apps/web/app/components/ui/wizards/WizardSteps.tsx
T

138 lines
5.3 KiB
TypeScript

import clsx from "clsx";
import ButtonSecondary from "../buttons/ButtonSecondary";
import LoadingButton from "../buttons/LoadingButton";
import { useTranslation } from "react-i18next";
import { ChevronLeftIcon, ChevronRightIcon } from "~/components/ui/icons/vendor";
export type WizardStepDto = {
name: string;
description?: string;
};
interface Props {
steps: WizardStepDto[];
selectedStep: number;
onSetStep: (step: number, direction: "next" | "back" | undefined) => void;
children: React.ReactNode;
breakpoint?: "sm" | "md" | "lg" | "xl" | "2xl";
className?: string;
}
export default function WizardSteps({ steps, selectedStep, onSetStep, children, className, breakpoint = "md" }: Props) {
const { t } = useTranslation();
const canGoBack = selectedStep > 0;
const canGoNext = selectedStep < steps.length - 1;
const backTitle = canGoBack ? steps[selectedStep - 1].name : t("shared.back");
const nextTitle = canGoNext ? steps[selectedStep + 1].name : t("shared.next");
function onBack() {
if (canGoBack) {
onSetStep(selectedStep - 1, "back");
}
}
function onNext() {
if (canGoNext) {
onSetStep(selectedStep + 1, "next");
}
}
return (
<div className="relative">
<div
className={clsx(
"p-1",
breakpoint === "sm" && "sm:hidden",
breakpoint === "md" && "md:hidden",
breakpoint === "lg" && "lg:hidden",
breakpoint === "xl" && "xl:hidden",
breakpoint === "2xl" && "2xl:hidden"
)}
>
<label htmlFor="tabs" className="sr-only">
{t("shared.select")}
</label>
<select
id="tabs"
name="tabs"
className="border-border-default bg-surface-neutral-primary text-text-neutral-primary focus:border-border-default focus:shadow-focus block w-full rounded-md"
onChange={(e) => onSetStep(Number(e.target.value), undefined)}
value={selectedStep}
>
{steps.map((item, idx) => {
return (
<option key={item.name} value={Number(idx)}>
{item.name}
</option>
);
})}
</select>
</div>
<div
className={clsx(
className,
breakpoint === "sm" && "sm:flex sm:space-x-4",
breakpoint === "md" && "md:flex md:space-x-4",
breakpoint === "lg" && "lg:flex lg:space-x-4",
breakpoint === "xl" && "xl:flex xl:space-x-4",
breakpoint === "2xl" && "2xl:flex 2xl:space-x-4"
)}
>
<div className="hidden overflow-auto p-3 md:block md:w-1/4">
<nav aria-label={t("shared.progress")}>
<ol className="overflow-hidden">
{steps.map((step, stepIdx) => (
<li key={step.name} className={clsx(stepIdx !== steps.length - 1 ? "pb-10" : "", "relative")}>
{stepIdx !== steps.length - 1 ? <div className="absolute left-3 top-4 -ml-px mt-0.5 h-full w-0.5 bg-gray-300" aria-hidden="true" /> : null}
<button type="button" onClick={() => onSetStep(stepIdx, undefined)} className="group relative flex items-start text-left">
<span className="flex h-9 items-center" aria-hidden="true">
<span
className={clsx(
"border-border-default bg-surface-neutral-primary relative flex h-6 w-6 items-center justify-center rounded-full border-2",
stepIdx === selectedStep ? "border-theme-600 group-hover:border-theme-600" : "group-hover:border-theme-600"
)}
>
{stepIdx === selectedStep ? (
<span className="bg-theme-600 h-2.5 w-2.5 rounded-full" />
) : (
<span className="group-hover:bg-theme-600 h-2.5 w-2.5 rounded-full bg-gray-400" />
)}
</span>
</span>
<span className="ml-4 flex min-w-0 flex-col">
<span className="text-text-neutral-tertiary text-sm font-medium">{step.name}</span>
<span className="text-text-neutral-tertiary line-clamp-2 text-sm">{step.description}</span>
</span>
</button>
</li>
))}
</ol>
</nav>
</div>
<div className="h-full w-full overflow-auto pb-20 md:w-3/4">{children}</div>
</div>
<div className="bg-surface-neutral-secondary/90 sticky bottom-0 -mx-8 px-4 py-3 shadow-inner md:py-2">
<div className="flex w-full justify-between space-x-2">
<div>
{canGoBack && (
<ButtonSecondary onClick={onBack}>
<div className="flex items-center space-x-2">
<ChevronLeftIcon className="h-4 w-4" />
</div>
<div>{backTitle}</div>
</ButtonSecondary>
)}
</div>
<div>
{canGoNext && (
<LoadingButton onClick={onNext}>
<div className="flex items-center space-x-2">
<div>{nextTitle}</div>
<ChevronRightIcon className="h-4 w-4" />
</div>
</LoadingButton>
)}
</div>
</div>
</div>
</div>
);
}