fix(core-flows): Handle variant creation duplicate inventory item ids (#8937)

* fix(core-flows): Handle variant creation duplicate inventory item ids

* disabled already selected options

* address feedback

* fix tests
This commit is contained in:
Adrien de Peretti
2024-09-02 18:36:42 +02:00
committed by GitHub
parent ddcb030ac7
commit 479e712c17
4 changed files with 154 additions and 16 deletions
@@ -14,7 +14,7 @@ import {
TrianglesMini,
XMarkMini,
} from "@medusajs/icons"
import { Text, clx } from "@medusajs/ui"
import { clx, Text } from "@medusajs/ui"
import { matchSorter } from "match-sorter"
import {
ComponentPropsWithoutRef,
@@ -35,6 +35,7 @@ import { genericForwardRef } from "../../common/generic-forward-ref"
type ComboboxOption = {
value: string
label: string
disabled?: boolean
}
type Value = string[] | string
@@ -96,13 +97,14 @@ const ComboboxImpl = <T extends Value = string>(
const handleValueChange = (newValues?: T) => {
// check if the value already exists in options
const exists = options.find((o) => {
if (isArrayValue) {
return newValues?.includes(o.value)
}
return o.value === newValues
})
const exists = options
.filter((o) => !o.disabled)
.find((o) => {
if (isArrayValue) {
return newValues?.includes(o.value)
}
return o.value === newValues
})
// If the value does not exist in the options, and the component has a handler
// for creating new options, call it.
@@ -290,13 +292,20 @@ const ComboboxImpl = <T extends Value = string>(
}}
aria-busy={isPending}
>
{results.map(({ value, label }) => (
{results.map(({ value, label, disabled }) => (
<PrimitiveComboboxItem
key={value}
value={value}
focusOnHover
setValueOnClick={false}
className="transition-fg bg-ui-bg-base data-[active-item=true]:bg-ui-bg-base-hover group flex cursor-pointer items-center gap-x-2 rounded-[4px] px-2 py-1.5"
disabled={disabled}
className={clx(
"transition-fg bg-ui-bg-base data-[active-item=true]:bg-ui-bg-base-hover group flex cursor-pointer items-center gap-x-2 rounded-[4px] px-2 py-1.5",
{
"text-ui-fg-disabled": disabled,
"bg-ui-bg-component": disabled,
}
)}
>
<PrimitiveComboboxItemCheck className="flex !size-5 items-center justify-center">
<EllipseMiniSolid />
@@ -1,6 +1,5 @@
import React from "react"
import { Button, Heading, IconButton, Input, Label } from "@medusajs/ui"
import { useFieldArray, UseFormReturn } from "react-hook-form"
import { useFieldArray, UseFormReturn, useWatch } from "react-hook-form"
import { XMarkMini } from "@medusajs/icons"
import { useTranslation } from "react-i18next"
@@ -24,6 +23,11 @@ function VariantSection({ form, variant, index }: VariantSectionProps) {
name: `variants.${index}.inventory`,
})
const inventoryFormData = useWatch({
control: form.control,
name: `variants.${index}.inventory`,
})
const items = useComboboxData({
queryKey: ["inventory_items"],
queryFn: (params) => sdk.admin.inventoryItem.list(params),
@@ -34,6 +38,21 @@ function VariantSection({ form, variant, index }: VariantSectionProps) {
})),
})
/**
* Will mark an option as disabled if another input already selected that option
* @param option
* @param inventoryIndex
*/
const isItemOptionDisabled = (
option: (typeof items.options)[0],
inventoryIndex: number
) => {
return inventoryFormData?.some(
(i, index) =>
index != inventoryIndex && i.inventory_item_id === option.value
)
}
return (
<div className="grid gap-y-4">
<div className="flex items-start justify-between gap-x-4">
@@ -81,7 +100,10 @@ function VariantSection({ form, variant, index }: VariantSectionProps) {
<Form.Control>
<Combobox
{...field}
options={items.options}
options={items.options.map((o) => ({
...o,
disabled: isItemOptionDisabled(o, inventoryIndex),
}))}
searchValue={items.searchValue}
onSearchValueChange={items.onSearchValueChange}
fetchNextPage={items.fetchNextPage}