|
|
|
@@ -1,6 +1,6 @@
|
|
|
|
|
import { useState } from 'react';
|
|
|
|
|
import { useState, useRef, useEffect } from 'react';
|
|
|
|
|
import {
|
|
|
|
|
ArrowLeft, Plus, Trash2, Minus, Bell, Book, Users, GitBranch
|
|
|
|
|
ArrowLeft, Plus, Trash2, Minus, Book, Users, GitBranch, ChevronDown
|
|
|
|
|
} from 'lucide-react';
|
|
|
|
|
import { useNavigate } from 'react-router-dom';
|
|
|
|
|
import {
|
|
|
|
@@ -84,8 +84,70 @@ const ROOM_TYPE_TIER_OPTIONS = [
|
|
|
|
|
const LOGIC_OPTIONS = [
|
|
|
|
|
{ label: 'AND', value: 'AND' },
|
|
|
|
|
{ label: 'OR', value: 'OR' },
|
|
|
|
|
{ label: 'NOT', value: 'NOT' },
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
// Per-gate color scheme (exact Figma tokens): AND=blue, OR=yellow, NOT=red.
|
|
|
|
|
// Fill = background per gate; border per gate; label/chevron text = #032D20 for all.
|
|
|
|
|
const LOGIC_STYLES: Record<string, { bg: string; text: string; border: string }> = {
|
|
|
|
|
AND: { bg: 'bg-[#F2FAFF]', text: 'text-[#032D20]', border: 'border-[#1A6597]' },
|
|
|
|
|
OR: { bg: 'bg-[#FFFDF2]', text: 'text-[#032D20]', border: 'border-[#977E1A]' },
|
|
|
|
|
NOT: { bg: 'bg-[#FFF2F2]', text: 'text-[#032D20]', border: 'border-[#971A1C]' },
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// ─── Logic Gate Dropdown ─────────────────────────────────────────────────────
|
|
|
|
|
// Colored variant of the logic selector — the shared CustomDropdown hardcodes a
|
|
|
|
|
// white background and text color, so we render a dedicated colored control here.
|
|
|
|
|
|
|
|
|
|
function LogicDropdown({ value, onChange, readOnly = false }: { value: string; onChange?: (v: string) => void; readOnly?: boolean }) {
|
|
|
|
|
const [open, setOpen] = useState(false);
|
|
|
|
|
const ref = useRef<HTMLDivElement>(null);
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
if (readOnly) return;
|
|
|
|
|
const handleClickOutside = (e: MouseEvent) => {
|
|
|
|
|
if (ref.current && !ref.current.contains(e.target as Node)) setOpen(false);
|
|
|
|
|
};
|
|
|
|
|
document.addEventListener('mousedown', handleClickOutside);
|
|
|
|
|
return () => document.removeEventListener('mousedown', handleClickOutside);
|
|
|
|
|
}, [readOnly]);
|
|
|
|
|
|
|
|
|
|
const style = LOGIC_STYLES[value] ?? LOGIC_STYLES.AND;
|
|
|
|
|
const boxClass = `w-full h-[50px] px-4 rounded-[10px] border flex items-center justify-between gap-2 text-[14px] font-semibold transition-colors shadow-[0_1px_2px_0_rgba(0,0,0,0.05)] ${style.bg} ${style.text} ${style.border}`;
|
|
|
|
|
|
|
|
|
|
// Fixed / non-editable gate (used by the Strategic Action Builder) — no menu.
|
|
|
|
|
if (readOnly) {
|
|
|
|
|
return <div className={boxClass}>{value}</div>;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div className="relative" ref={ref}>
|
|
|
|
|
<button
|
|
|
|
|
type="button"
|
|
|
|
|
onClick={() => setOpen(o => !o)}
|
|
|
|
|
className={boxClass}
|
|
|
|
|
>
|
|
|
|
|
{value}
|
|
|
|
|
<ChevronDown size={16} className={`transition-transform duration-200 ${open ? 'rotate-180' : ''}`} />
|
|
|
|
|
</button>
|
|
|
|
|
{open && (
|
|
|
|
|
<div className="absolute z-20 mt-1 w-full bg-white border border-gray-200 rounded-lg shadow-lg overflow-hidden">
|
|
|
|
|
{LOGIC_OPTIONS.map(opt => (
|
|
|
|
|
<button
|
|
|
|
|
key={opt.value}
|
|
|
|
|
type="button"
|
|
|
|
|
onClick={() => { onChange?.(opt.value); setOpen(false); }}
|
|
|
|
|
className="w-full text-left px-4 h-[42px] text-[14px] font-medium flex items-center text-gray-700 hover:bg-gray-50"
|
|
|
|
|
>
|
|
|
|
|
{opt.label}
|
|
|
|
|
</button>
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ─── Component ───────────────────────────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
export default function AddPolicyEngine() {
|
|
|
|
@@ -113,11 +175,20 @@ export default function AddPolicyEngine() {
|
|
|
|
|
|
|
|
|
|
// ─── Handlers ──────────────────────────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
// Returns the lowest priority (1-10) not already used by an existing rule.
|
|
|
|
|
const findFreePriority = () => {
|
|
|
|
|
const taken = rules.map(r => r.priority);
|
|
|
|
|
for (let p = 1; p <= 10; p++) {
|
|
|
|
|
if (!taken.includes(p)) return p;
|
|
|
|
|
}
|
|
|
|
|
return 1; // all 10 slots taken (>10 rules) — warning handles this edge case
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleAddRule = () => {
|
|
|
|
|
setRules([...rules, {
|
|
|
|
|
id: crypto.randomUUID(),
|
|
|
|
|
category: '',
|
|
|
|
|
priority: 1,
|
|
|
|
|
priority: findFreePriority(),
|
|
|
|
|
conditions: [{ id: crypto.randomUUID(), condition: '', operator: '', value: '', logic: 'AND' }],
|
|
|
|
|
actions: [{ id: crypto.randomUUID(), actionType: '', roomTypeTier: '', duration: '', logic: 'AND' }]
|
|
|
|
|
}]);
|
|
|
|
@@ -131,6 +202,28 @@ export default function AddPolicyEngine() {
|
|
|
|
|
setRules(rules.map(r => r.id === ruleId ? { ...r, ...updates } : r));
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Priorities used by every OTHER rule — a rule may never land on one of these.
|
|
|
|
|
const priorityTakenByOthers = (rule: Rule) =>
|
|
|
|
|
rules.filter(r => r.id !== rule.id).map(r => r.priority);
|
|
|
|
|
|
|
|
|
|
// Next free priority below the current value (down to 1), or null if none.
|
|
|
|
|
const getPrevPriority = (rule: Rule): number | null => {
|
|
|
|
|
const taken = priorityTakenByOthers(rule);
|
|
|
|
|
for (let p = rule.priority - 1; p >= 1; p--) {
|
|
|
|
|
if (!taken.includes(p)) return p;
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Next free priority above the current value (up to 10), or null if none.
|
|
|
|
|
const getNextPriority = (rule: Rule): number | null => {
|
|
|
|
|
const taken = priorityTakenByOthers(rule);
|
|
|
|
|
for (let p = rule.priority + 1; p <= 10; p++) {
|
|
|
|
|
if (!taken.includes(p)) return p;
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleAddCondition = (ruleId: string) => {
|
|
|
|
|
setRules(rules.map(r => {
|
|
|
|
|
if (r.id === ruleId) {
|
|
|
|
@@ -209,7 +302,7 @@ export default function AddPolicyEngine() {
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div className="flex flex-col h-full bg-[#FAFAFA] min-h-screen">
|
|
|
|
|
<div className="flex flex-col h-full bg-white min-h-screen">
|
|
|
|
|
|
|
|
|
|
{/* ─── Header ────────────────────────────────────────────────────── */}
|
|
|
|
|
<div className="flex items-center justify-between px-8 py-4 bg-white border-b border-gray-200">
|
|
|
|
@@ -226,9 +319,6 @@ export default function AddPolicyEngine() {
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="flex items-center gap-3">
|
|
|
|
|
<button className="p-2 text-gray-400 hover:text-gray-600 transition-colors">
|
|
|
|
|
<Bell size={20} />
|
|
|
|
|
</button>
|
|
|
|
|
<CustomButton
|
|
|
|
|
variant="primary"
|
|
|
|
|
className="!bg-[#1E7D5C] hover:!bg-[#17664B] !h-10 !px-4 !rounded-[10px]"
|
|
|
|
@@ -244,7 +334,7 @@ export default function AddPolicyEngine() {
|
|
|
|
|
<div className="max-w-[1200px] mx-auto flex flex-col gap-6">
|
|
|
|
|
|
|
|
|
|
{/* Policy Information Card */}
|
|
|
|
|
<div className="bg-white rounded-[16px] p-6 shadow-sm border border-gray-100">
|
|
|
|
|
<div className="bg-[#FAFAFA] rounded-[16px] p-6 border border-gray-100">
|
|
|
|
|
<CardHeader icon={Book} title="Policy Information" />
|
|
|
|
|
|
|
|
|
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-6 mb-6">
|
|
|
|
@@ -305,7 +395,7 @@ export default function AddPolicyEngine() {
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{/* Target Audience Card */}
|
|
|
|
|
<div className="bg-white rounded-[16px] p-6 shadow-sm border border-gray-100">
|
|
|
|
|
<div className="bg-[#FAFAFA] rounded-[16px] p-6 border border-gray-100">
|
|
|
|
|
<CardHeader icon={Users} title="Target Audience" />
|
|
|
|
|
|
|
|
|
|
<div className="flex flex-col gap-6">
|
|
|
|
@@ -347,22 +437,30 @@ export default function AddPolicyEngine() {
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{/* Rule Engine Card */}
|
|
|
|
|
<div className="bg-white rounded-[16px] p-6 shadow-sm border border-gray-100">
|
|
|
|
|
<div className="bg-[#FAFAFA] rounded-[16px] p-6 border border-gray-100">
|
|
|
|
|
<div className="flex items-center justify-between mb-6">
|
|
|
|
|
<CardHeader icon={GitBranch} title="Rule Engine" />
|
|
|
|
|
<CustomButton
|
|
|
|
|
variant="outlined"
|
|
|
|
|
className="!border-[#1E7D5C] !text-[#1E7D5C] hover:!bg-[#E8F3EF] !rounded-[10px]"
|
|
|
|
|
leftIcon={<Plus size={16} />}
|
|
|
|
|
<button
|
|
|
|
|
type="button"
|
|
|
|
|
onClick={handleAddRule}
|
|
|
|
|
className="flex items-center justify-center gap-2.5 min-w-[181px] h-10 px-4 rounded-[12px] whitespace-nowrap transition-opacity hover:opacity-90"
|
|
|
|
|
style={{
|
|
|
|
|
border: '2px solid transparent',
|
|
|
|
|
backgroundImage: 'linear-gradient(#fff, #fff), linear-gradient(180deg, #1B9869 0%, #14704E 100%)',
|
|
|
|
|
backgroundOrigin: 'border-box',
|
|
|
|
|
backgroundClip: 'padding-box, border-box',
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<Plus size={16} color="#14704E" />
|
|
|
|
|
<span className="font-bold text-[14px] leading-none bg-gradient-to-b from-[#1B9869] to-[#14704E] bg-clip-text text-transparent">
|
|
|
|
|
Add Strategic Rule
|
|
|
|
|
</CustomButton>
|
|
|
|
|
</span>
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className="flex flex-col gap-6">
|
|
|
|
|
{rules.map((rule, ruleIndex) => (
|
|
|
|
|
<div key={rule.id} className="border border-gray-100 rounded-[12px] p-6 bg-[#FAFAFA] relative">
|
|
|
|
|
<div key={rule.id} className="border border-gray-100 rounded-[12px] p-6 bg-white relative">
|
|
|
|
|
|
|
|
|
|
{/* Rule Header */}
|
|
|
|
|
<div className="flex items-center justify-between mb-5">
|
|
|
|
@@ -380,7 +478,7 @@ export default function AddPolicyEngine() {
|
|
|
|
|
{/* Rule Settings */}
|
|
|
|
|
<div className="flex items-end gap-6 mb-8">
|
|
|
|
|
<div className="w-1/3 flex flex-col gap-2">
|
|
|
|
|
<label className="text-[13px] font-semibold text-gray-700">Rule Category</label>
|
|
|
|
|
<label className="text-[14px] font-medium leading-none text-[#001811]">Rule Category</label>
|
|
|
|
|
<CustomDropdown
|
|
|
|
|
options={RULE_CATEGORY_OPTIONS}
|
|
|
|
|
value={rule.category}
|
|
|
|
@@ -389,11 +487,16 @@ export default function AddPolicyEngine() {
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="flex flex-col gap-2">
|
|
|
|
|
<label className="text-[13px] font-semibold text-gray-700">Priority</label>
|
|
|
|
|
<label className="text-[14px] font-medium leading-none text-[#001811]">Priority</label>
|
|
|
|
|
{(() => {
|
|
|
|
|
const prevPriority = getPrevPriority(rule);
|
|
|
|
|
const nextPriority = getNextPriority(rule);
|
|
|
|
|
return (
|
|
|
|
|
<div className="flex items-center border border-gray-200 rounded-[10px] h-11 bg-white overflow-hidden w-[120px]">
|
|
|
|
|
<button
|
|
|
|
|
onClick={() => handleUpdateRule(rule.id, { priority: Math.max(1, rule.priority - 1) })}
|
|
|
|
|
className="flex-1 flex items-center justify-center h-full hover:bg-gray-50 text-gray-500"
|
|
|
|
|
onClick={() => prevPriority !== null && handleUpdateRule(rule.id, { priority: prevPriority })}
|
|
|
|
|
disabled={prevPriority === null}
|
|
|
|
|
className="flex-1 flex items-center justify-center h-full hover:bg-gray-50 text-gray-500 disabled:opacity-40 disabled:cursor-not-allowed disabled:hover:bg-transparent"
|
|
|
|
|
>
|
|
|
|
|
<Minus size={16} />
|
|
|
|
|
</button>
|
|
|
|
@@ -401,12 +504,15 @@ export default function AddPolicyEngine() {
|
|
|
|
|
{rule.priority}
|
|
|
|
|
</span>
|
|
|
|
|
<button
|
|
|
|
|
onClick={() => handleUpdateRule(rule.id, { priority: Math.min(10, rule.priority + 1) })}
|
|
|
|
|
className="flex-1 flex items-center justify-center h-full hover:bg-gray-50 text-gray-500"
|
|
|
|
|
onClick={() => nextPriority !== null && handleUpdateRule(rule.id, { priority: nextPriority })}
|
|
|
|
|
disabled={nextPriority === null}
|
|
|
|
|
className="flex-1 flex items-center justify-center h-full hover:bg-gray-50 text-gray-500 disabled:opacity-40 disabled:cursor-not-allowed disabled:hover:bg-transparent"
|
|
|
|
|
>
|
|
|
|
|
<Plus size={16} />
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
})()}
|
|
|
|
|
{rules.some(r => r.id !== rule.id && r.priority === rule.priority) && (
|
|
|
|
|
<span className="text-red-500 text-xs mt-1">Priority already exists</span>
|
|
|
|
|
)}
|
|
|
|
@@ -420,7 +526,7 @@ export default function AddPolicyEngine() {
|
|
|
|
|
{rule.conditions.map((condition, cIdx) => (
|
|
|
|
|
<div key={condition.id} className="flex items-end gap-3">
|
|
|
|
|
<div className="flex-1 flex flex-col gap-2">
|
|
|
|
|
<label className="text-[12px] font-medium text-gray-500">Condition</label>
|
|
|
|
|
<label className="text-[14px] font-medium leading-none text-[#001811]">Condition</label>
|
|
|
|
|
<CustomDropdown
|
|
|
|
|
options={CONDITION_OPTIONS}
|
|
|
|
|
value={condition.condition}
|
|
|
|
@@ -429,7 +535,7 @@ export default function AddPolicyEngine() {
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="flex-1 flex flex-col gap-2">
|
|
|
|
|
<label className="text-[12px] font-medium text-gray-500">Operator</label>
|
|
|
|
|
<label className="text-[14px] font-medium leading-none text-[#001811]">Operator</label>
|
|
|
|
|
<CustomDropdown
|
|
|
|
|
options={OPERATOR_OPTIONS}
|
|
|
|
|
value={condition.operator}
|
|
|
|
@@ -438,7 +544,7 @@ export default function AddPolicyEngine() {
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="flex-1 flex flex-col gap-2">
|
|
|
|
|
<label className="text-[12px] font-medium text-gray-500">Value</label>
|
|
|
|
|
<label className="text-[14px] font-medium leading-none text-[#001811]">Value</label>
|
|
|
|
|
<CustomInput
|
|
|
|
|
value={condition.value}
|
|
|
|
|
onChange={(e) => handleUpdateCondition(rule.id, condition.id, { value: e.target.value })}
|
|
|
|
@@ -446,24 +552,24 @@ export default function AddPolicyEngine() {
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
{cIdx < rule.conditions.length - 1 ? (
|
|
|
|
|
<div className="w-[120px] flex flex-col gap-2">
|
|
|
|
|
<label className="text-[12px] font-medium text-gray-500">Logic</label>
|
|
|
|
|
<CustomDropdown
|
|
|
|
|
options={LOGIC_OPTIONS}
|
|
|
|
|
<div className="w-[163px] flex flex-col gap-2">
|
|
|
|
|
<label className="text-[14px] font-medium leading-none text-[#001811]">Logic</label>
|
|
|
|
|
<LogicDropdown
|
|
|
|
|
value={condition.logic}
|
|
|
|
|
onChange={(val) => handleUpdateCondition(rule.id, condition.id, { logic: val })}
|
|
|
|
|
placeholder="AND"
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
) : (
|
|
|
|
|
<div className="flex items-center">
|
|
|
|
|
<div className="w-[163px] flex items-center">
|
|
|
|
|
<CustomButton
|
|
|
|
|
variant="secondary"
|
|
|
|
|
className="!bg-[#E8F3EF] !text-[#1E7D5C] hover:!bg-[#d9ece4] !px-3 !h-11"
|
|
|
|
|
leftIcon={<Plus size={16} />}
|
|
|
|
|
className="!w-full !justify-center !bg-[#EAFAF5] hover:!bg-[#d9ece4] !px-4 !gap-2.5 !h-[49px] !rounded-[12px] whitespace-nowrap"
|
|
|
|
|
leftIcon={<Plus size={16} color="#14704E" />}
|
|
|
|
|
onClick={() => handleAddCondition(rule.id)}
|
|
|
|
|
>
|
|
|
|
|
<span className="font-bold text-[14px] leading-none text-center bg-gradient-to-b from-[#1B9869] to-[#14704E] bg-clip-text text-transparent">
|
|
|
|
|
Add Condition
|
|
|
|
|
</span>
|
|
|
|
|
</CustomButton>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
@@ -471,9 +577,9 @@ export default function AddPolicyEngine() {
|
|
|
|
|
{rule.conditions.length > 1 && (
|
|
|
|
|
<button
|
|
|
|
|
onClick={() => handleDeleteCondition(rule.id, condition.id)}
|
|
|
|
|
className="w-11 h-11 flex items-center justify-center bg-red-50 text-red-500 rounded-[10px] hover:bg-red-100 transition-colors"
|
|
|
|
|
className="w-11 h-11 flex items-center justify-center bg-red-50 text-[#D40000] rounded-[10px] hover:bg-red-100 transition-colors"
|
|
|
|
|
>
|
|
|
|
|
<Trash2 size={16} />
|
|
|
|
|
<Trash2 size={16} strokeWidth={1.5} color="#D40000" />
|
|
|
|
|
</button>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
@@ -489,7 +595,7 @@ export default function AddPolicyEngine() {
|
|
|
|
|
{rule.actions.map((action, aIdx) => (
|
|
|
|
|
<div key={action.id} className="flex items-end gap-3">
|
|
|
|
|
<div className="flex-1 flex flex-col gap-2">
|
|
|
|
|
<label className="text-[12px] font-medium text-gray-500">Action Type</label>
|
|
|
|
|
<label className="text-[14px] font-medium leading-none text-[#001811]">Action Type</label>
|
|
|
|
|
<CustomDropdown
|
|
|
|
|
options={ACTION_TYPE_OPTIONS}
|
|
|
|
|
value={action.actionType}
|
|
|
|
@@ -498,7 +604,7 @@ export default function AddPolicyEngine() {
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="flex-1 flex flex-col gap-2">
|
|
|
|
|
<label className="text-[12px] font-medium text-gray-500">Room Type / Tier</label>
|
|
|
|
|
<label className="text-[14px] font-medium leading-none text-[#001811]">Room Type / Tier</label>
|
|
|
|
|
<CustomDropdown
|
|
|
|
|
options={ROOM_TYPE_TIER_OPTIONS}
|
|
|
|
|
value={action.roomTypeTier}
|
|
|
|
@@ -507,7 +613,7 @@ export default function AddPolicyEngine() {
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="flex-1 flex flex-col gap-2">
|
|
|
|
|
<label className="text-[12px] font-medium text-gray-500">Duration</label>
|
|
|
|
|
<label className="text-[14px] font-medium leading-none text-[#001811]">Duration</label>
|
|
|
|
|
<CustomInput
|
|
|
|
|
value={action.duration}
|
|
|
|
|
onChange={(e) => handleUpdateAction(rule.id, action.id, { duration: e.target.value })}
|
|
|
|
@@ -515,24 +621,21 @@ export default function AddPolicyEngine() {
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
{aIdx < rule.actions.length - 1 ? (
|
|
|
|
|
<div className="w-[120px] flex flex-col gap-2">
|
|
|
|
|
<label className="text-[12px] font-medium text-gray-500">Logic</label>
|
|
|
|
|
<CustomDropdown
|
|
|
|
|
options={LOGIC_OPTIONS}
|
|
|
|
|
value={action.logic}
|
|
|
|
|
onChange={(val) => handleUpdateAction(rule.id, action.id, { logic: val })}
|
|
|
|
|
placeholder="AND"
|
|
|
|
|
/>
|
|
|
|
|
<div className="w-[163px] flex flex-col gap-2">
|
|
|
|
|
<label className="text-[14px] font-medium leading-none text-[#001811]">Logic</label>
|
|
|
|
|
<LogicDropdown value={action.logic} readOnly />
|
|
|
|
|
</div>
|
|
|
|
|
) : (
|
|
|
|
|
<div className="flex items-center">
|
|
|
|
|
<div className="w-[163px] flex items-center">
|
|
|
|
|
<CustomButton
|
|
|
|
|
variant="secondary"
|
|
|
|
|
className="!bg-[#E8F3EF] !text-[#1E7D5C] hover:!bg-[#d9ece4] !px-3 !h-11"
|
|
|
|
|
leftIcon={<Plus size={16} />}
|
|
|
|
|
className="!w-full !justify-center !bg-[#EAFAF5] hover:!bg-[#d9ece4] !px-4 !gap-2.5 !h-[49px] !rounded-[12px] whitespace-nowrap"
|
|
|
|
|
leftIcon={<Plus size={16} color="#14704E" />}
|
|
|
|
|
onClick={() => handleAddAction(rule.id)}
|
|
|
|
|
>
|
|
|
|
|
<span className="font-bold text-[14px] leading-none text-center bg-gradient-to-b from-[#1B9869] to-[#14704E] bg-clip-text text-transparent">
|
|
|
|
|
Add
|
|
|
|
|
</span>
|
|
|
|
|
</CustomButton>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
@@ -540,9 +643,9 @@ export default function AddPolicyEngine() {
|
|
|
|
|
{rule.actions.length > 1 && (
|
|
|
|
|
<button
|
|
|
|
|
onClick={() => handleDeleteAction(rule.id, action.id)}
|
|
|
|
|
className="w-11 h-11 flex items-center justify-center bg-red-50 text-red-500 rounded-[10px] hover:bg-red-100 transition-colors"
|
|
|
|
|
className="w-11 h-11 flex items-center justify-center bg-red-50 text-[#D40000] rounded-[10px] hover:bg-red-100 transition-colors"
|
|
|
|
|
>
|
|
|
|
|
<Trash2 size={16} />
|
|
|
|
|
<Trash2 size={16} strokeWidth={1.5} color="#D40000" />
|
|
|
|
|
</button>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
@@ -564,7 +667,7 @@ export default function AddPolicyEngine() {
|
|
|
|
|
<div className="fixed bottom-0 left-0 right-0 bg-white border-t border-gray-200 px-8 py-4 flex items-center justify-between z-10 shadow-[0_-4px_10px_rgba(0,0,0,0.02)]">
|
|
|
|
|
<div className="flex items-center gap-3">
|
|
|
|
|
<span className="text-[14px] font-semibold text-gray-600">Status:</span>
|
|
|
|
|
<CustomStatus status="Active" />
|
|
|
|
|
<CustomStatus status={status} />
|
|
|
|
|
</div>
|
|
|
|
|
<div className="flex items-center gap-3">
|
|
|
|
|
<CustomButton
|
|
|
|
|