Files
community-rule/app/(app)/create/components/MethodCardPolicyDialog.tsx
T

145 lines
4.0 KiB
TypeScript

"use client";
/**
* Figma: Overlay / Modal / Card (24973:1852) with Has Steps on. A deck card
* opens as a routing view of its parts; each row opens that field's Step
* Modal with Generate draft on an empty field.
*/
import { memo, useCallback, useEffect, useState, type ReactNode } from "react";
import Create from "../../../components/modals/Create";
import { useMessages } from "../../../contexts/MessagesContext";
import type { ModalHeaderMenuItem } from "../../../components/modals/ModalHeader/ModalHeader.types";
import { ValueDialogStepCard } from "./ValueDialogStepCard";
export type MethodCardPolicyStep = {
id: string;
title: string;
emptyDescription: string;
done: boolean;
summary: string;
renderEditor: () => ReactNode;
};
export type MethodCardPolicyDialogProps = {
isOpen: boolean;
cardLabel: string;
description?: string;
editing: boolean;
steps: MethodCardPolicyStep[];
onClose: () => void;
onConfirm: () => void;
onDeselect?: () => void;
kebabTriggerAriaLabel?: string;
kebabMenuAriaLabel?: string;
kebabMenuItems?: ModalHeaderMenuItem[];
ariaLabel?: string;
/** Customized field-blocks body. Replaces the routing steps. */
children?: ReactNode;
};
function MethodCardPolicyDialogComponent({
isOpen,
cardLabel,
description = "",
editing,
steps,
onClose,
onConfirm,
onDeselect,
kebabTriggerAriaLabel,
kebabMenuAriaLabel,
kebabMenuItems,
ariaLabel,
children,
}: MethodCardPolicyDialogProps) {
const m = useMessages();
const t = m.create.customRule.cardDialog;
const [activeStepId, setActiveStepId] = useState<string | null>(null);
useEffect(() => {
if (!isOpen) {
setActiveStepId(null);
}
}, [isOpen]);
const activeStep =
activeStepId == null
? null
: (steps.find((step) => step.id === activeStepId) ?? null);
const useCustomBody = Boolean(children);
const showSteps = !useCustomBody && activeStep == null;
const handleRequestClose = useCallback(() => {
if (activeStepId != null) {
setActiveStepId(null);
return;
}
onClose();
}, [activeStepId, onClose]);
const handleNext = useCallback(() => {
if (activeStepId != null) {
setActiveStepId(null);
return;
}
onConfirm();
}, [activeStepId, onConfirm]);
const title = activeStep ? activeStep.title : cardLabel;
const primaryLabel = activeStepId != null || editing ? t.save : t.addToRule;
return (
<Create
isOpen={isOpen}
onClose={handleRequestClose}
title={title}
description={activeStep ? undefined : description || undefined}
showBackButton={false}
showCancelButton
showNextButton
showRemoveButton={editing && activeStepId == null}
onCancel={handleRequestClose}
onNext={handleNext}
onRemove={onDeselect}
cancelButtonText={t.cancel}
nextButtonText={primaryLabel}
removeButtonText={t.deselect}
stepper={false}
backdropVariant="blurredYellow"
kebabTriggerAriaLabel={kebabTriggerAriaLabel}
kebabMenuAriaLabel={kebabMenuAriaLabel}
kebabMenuItems={
activeStepId == null && kebabMenuItems && kebabMenuItems.length > 0
? kebabMenuItems
: undefined
}
ariaLabel={ariaLabel || cardLabel}
>
{useCustomBody ? (
children
) : showSteps ? (
<div className="flex w-full flex-col gap-[8px]">
{steps.map((step, index) => (
<ValueDialogStepCard
key={step.id}
stepNumber={index + 1}
stepBadgeLabel={t.stepBadge}
title={step.title}
description={step.done ? step.summary : step.emptyDescription}
done={step.done}
onClick={() => setActiveStepId(step.id)}
/>
))}
</div>
) : (
activeStep?.renderEditor()
)}
</Create>
);
}
MethodCardPolicyDialogComponent.displayName = "MethodCardPolicyDialog";
export const MethodCardPolicyDialog = memo(MethodCardPolicyDialogComponent);