Show seven cards on the four method decks and open each as a routing overlay of its parts, so groups write from empty fields with Generate draft, search the full deck, and see unselected scope chips with enough contrast.
This commit is contained in:
1 parent
dea7dd7fbd
commit
46656f52d3
28 files changed
+1349
-318
No files matched your search
@@ -0,0 +1,144 @@
|
||||
"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);
|
||||
Reference in new issue
Block a user