Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
124 changes: 10 additions & 114 deletions src/admin/automations/automations-form/automations-rules-form/index.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import { Label, Select, Button } from "@medusajs/ui"
import { Button } from "@medusajs/ui"
import { useAvailableEvents } from "../../../../hooks/api/available-events"
import { OPERATOR_TYPES } from "../../../../modules/mpn-automation/types/types"
import { Controller, useFieldArray } from "react-hook-form"
import { useFieldArray } from "react-hook-form"
import { useMemo } from "react"
import { Trash, Plus } from "@medusajs/icons"
import { RuleValueInput } from "./rule-value-input"
import { Plus } from "@medusajs/icons"
import { RuleItem } from "./rule-item"

export function AutomationsRulesForm({
form,
Expand Down Expand Up @@ -76,116 +75,13 @@ export function AutomationsRulesForm({
</div>
)}
{fields.map((field, index) => (
<div
<RuleItem
key={field?.id ?? `rule-${index}`}
className="flex flex-col gap-2 p-4 border rounded-lg"
>
<div className="flex items-start justify-between gap-4">
<div className="flex-1 flex flex-col gap-2">
<Controller
name={`rules.items.${index}.attribute`}
control={form.control}
render={({ field, fieldState }) => (
<>
<Label>Attribute</Label>
<Select
key={`attribute-${index}-${eventAttributes.length}`}
value={field.value ?? ""}
onValueChange={(value) => {
field.onChange(value)
}}
>
<Select.Trigger>
<Select.Value placeholder="Select the attribute" />
</Select.Trigger>
<Select.Content>
{eventAttributes.map(
(attribute, attrIndex) => (
<Select.Item
key={
attribute.value ||
`attr-${index}-${attrIndex}`
}
value={
attribute.value || "ss"
}
>
{attribute.label}{" "}
<span className="text-xs text-gray-500">
({attribute.value})
</span>
</Select.Item>
)
)}
</Select.Content>
</Select>
{fieldState.error && (
<span className="text-red-500 text-sm">
{fieldState.error.message}
</span>
)}
</>
)}
/>
<Controller
name={`rules.items.${index}.operator`}
control={form.control}
render={({ field, fieldState }) => (
<>
<Label>Operator</Label>
<Select
key={`operator-${index}-${eventAttributes.length}-${field.value ?? ""}`}
value={field.value ?? ""}
onValueChange={(value) => {
field.onChange(value as string)
}}
>
<Select.Trigger>
<Select.Value placeholder="Select the operator" />
</Select.Trigger>
<Select.Content>
{OPERATOR_TYPES.map(
(operator, opIndex) => (
<Select.Item
key={
operator.value ||
`op-${opIndex}`
}
value={operator.value}
>
{operator.label}
</Select.Item>
)
)}
</Select.Content>
</Select>
{fieldState.error && (
<span className="text-red-500 text-sm">
{fieldState.error.message}
</span>
)}
</>
)}
/>
<RuleValueInput
control={form.control}
name={`rules.items.${index}.rule_values.0.value`}
operator={form.watch(
`rules.items.${index}.operator`
)}
/>
</div>
<Button
type="button"
variant="secondary"
size="small"
onClick={() => handleRemoveRule(index)}
className="mt-2"
>
<Trash />
</Button>
</div>
</div>
control={form.control}
index={index}
eventAttributes={eventAttributes}
onRemove={() => handleRemoveRule(index)}
/>
))}
<Button
type="button"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
import { Label, Select, Button, Text, Hint } from "@medusajs/ui"
import { Controller, useWatch, Control } from "react-hook-form"
import { Trash } from "@medusajs/icons"
import { OPERATOR_TYPES } from "../../../../modules/mpn-automation/types/types"
import { RuleValueInput } from "./rule-value-input"
import { Attribute } from "../../../../modules/mpn-automation/types/types"

interface RuleItemProps {
control: Control<any>
index: number
eventAttributes: Attribute[]
onRemove: () => void
}

export function RuleItem({
control,
index,
eventAttributes,
onRemove,
}: RuleItemProps) {
const selectedAttributeValue = useWatch({
control,
name: `rules.items.${index}.attribute`,
})

const operatorValue = useWatch({
control,
name: `rules.items.${index}.operator`,
})

// Find the selected attribute metadata
const selectedAttribute = selectedAttributeValue && eventAttributes.length
? (eventAttributes.find(
(attr: Attribute) => attr.value === selectedAttributeValue
) as Attribute | undefined)
: null

return (
<div className="flex flex-col gap-2 p-4 border rounded-lg">
<div className="flex items-start justify-between gap-4">
<div className="flex-1 flex flex-col gap-2">
<Controller
name={`rules.items.${index}.attribute`}
control={control}
render={({ field, fieldState }) => (
<>
<Label>Attribute</Label>
<Select
key={`attribute-${index}-${eventAttributes.length}`}
value={field.value ?? ""}
onValueChange={(value) => {
field.onChange(value)
}}
>
<Select.Trigger>
<Select.Value placeholder="Select the attribute" />
</Select.Trigger>
<Select.Content>
{eventAttributes.map((attribute, attrIndex) => (
<Select.Item
key={
attribute.value ||
`attr-${index}-${attrIndex}`
}
value={attribute.value || ""}
>
{attribute.label}{" "}
<span className="text-xs text-gray-500">
({attribute.value})
</span>
</Select.Item>
))}
</Select.Content>
</Select>
{fieldState.error && (
<span className="text-red-500 text-sm">
{fieldState.error.message}
</span>
)}
{selectedAttribute?.description && (
<Hint className="mt-1">
{selectedAttribute.description}
</Hint>
)}
</>
)}
/>
<Controller
name={`rules.items.${index}.operator`}
control={control}
render={({ field, fieldState }) => (
<>
<Label>Operator</Label>
<Select
key={`operator-${index}-${eventAttributes.length}-${field.value ?? ""}`}
value={field.value ?? ""}
onValueChange={(value) => {
field.onChange(value as string)
}}
>
<Select.Trigger>
<Select.Value placeholder="Select the operator" />
</Select.Trigger>
<Select.Content>
{OPERATOR_TYPES.map((operator, opIndex) => (
<Select.Item
key={operator.value || `op-${opIndex}`}
value={operator.value}
>
{operator.label}
</Select.Item>
))}
</Select.Content>
</Select>
{fieldState.error && (
<span className="text-red-500 text-sm">
{fieldState.error.message}
</span>
)}
</>
)}
/>
<RuleValueInput
control={control}
name={`rules.items.${index}.rule_values.0.value`}
operator={operatorValue}
/>
{selectedAttribute?.examples &&
selectedAttribute.examples.length > 0 && (
<div className="mt-0">
<Text size="xsmall" className="text-gray-600 mb-1">
Examples:
</Text>
<div className="flex flex-wrap gap-1">
{selectedAttribute.examples.map(
(example, exampleIndex) => (
<span
key={`example-${index}-${exampleIndex}`}
className="inline-flex items-center px-2 py-1 rounded-md bg-gray-100 text-xs text-gray-700"
>
{example}
</span>
)
)}
</div>
</div>
)}
</div>
<Button
type="button"
variant="secondary"
size="small"
onClick={onRemove}
className="mt-2"
>
<Trash />
</Button>
</div>
</div>
)
}

Loading