@@ -54,12 +54,24 @@ const getCategoriesAtLevel = (
|
||||
return parent?.children ?? []
|
||||
}
|
||||
|
||||
const extractList = <T,>(payload: unknown): T[] => {
|
||||
if (Array.isArray(payload)) return payload
|
||||
if (payload && typeof payload === 'object' && 'data' in payload) {
|
||||
const maybeData = (payload as { data?: unknown }).data
|
||||
return Array.isArray(maybeData) ? (maybeData as T[]) : []
|
||||
}
|
||||
return []
|
||||
}
|
||||
|
||||
const ProductsSelect: FC<Props> = (props) => {
|
||||
const { error_text, onProductSelect, value, onChange, ...rest } = props
|
||||
const [selectedPath, setSelectedPath] = useState<string[]>([])
|
||||
|
||||
const { data: categoriesData } = useGetCategories()
|
||||
const categories = categoriesData?.data ?? []
|
||||
const categories = useMemo(
|
||||
() => extractList<CategoryType>(categoriesData),
|
||||
[categoriesData],
|
||||
)
|
||||
|
||||
const levelsToShow = useMemo(() => {
|
||||
const levels = [0]
|
||||
@@ -75,11 +87,7 @@ const ProductsSelect: FC<Props> = (props) => {
|
||||
}, [categories, selectedPath])
|
||||
|
||||
const activeCategoryId = selectedPath.at(-1) ?? ''
|
||||
const activeCategory = activeCategoryId
|
||||
? findCategoryById(categories, activeCategoryId)
|
||||
: null
|
||||
const isLeafCategory = !!activeCategory && !(activeCategory.children?.length)
|
||||
const canLoadProducts = isLeafCategory
|
||||
const canLoadProducts = !!activeCategoryId
|
||||
|
||||
const { data: productsData } = useGetProducts(activeCategoryId || undefined, {
|
||||
enabled: canLoadProducts,
|
||||
@@ -90,23 +98,28 @@ const ProductsSelect: FC<Props> = (props) => {
|
||||
enabled: needsResolve,
|
||||
})
|
||||
|
||||
const productItems = useMemo(
|
||||
() => (productsData?.data ?? []).map((product) => ({
|
||||
label: product.title,
|
||||
value: product.id,
|
||||
})),
|
||||
const products = useMemo(
|
||||
() => extractList<ProductType>(productsData),
|
||||
[productsData],
|
||||
)
|
||||
|
||||
const resolveProducts = useMemo(
|
||||
() => extractList<ProductType>(resolveProductsData),
|
||||
[resolveProductsData],
|
||||
)
|
||||
|
||||
const productItems = useMemo(
|
||||
() => products.map((product) => ({
|
||||
label: product.title,
|
||||
value: product.id,
|
||||
})),
|
||||
[products],
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
if (!value) {
|
||||
setSelectedPath([])
|
||||
return
|
||||
}
|
||||
if (!value || selectedPath.length || !categories.length) return
|
||||
|
||||
if (selectedPath.length || !categories.length) return
|
||||
|
||||
const product = resolveProductsData?.data?.find((item) => item.id === value)
|
||||
const product = resolveProducts.find((item) => item.id === value)
|
||||
if (!product?.category) return
|
||||
|
||||
const categoryId = typeof product.category === 'string'
|
||||
@@ -117,7 +130,7 @@ const ProductsSelect: FC<Props> = (props) => {
|
||||
if (!path) return
|
||||
|
||||
setSelectedPath(path)
|
||||
}, [value, resolveProductsData, categories, selectedPath.length])
|
||||
}, [value, resolveProducts, categories, selectedPath.length])
|
||||
|
||||
useEffect(() => {
|
||||
if (!value) {
|
||||
@@ -125,11 +138,11 @@ const ProductsSelect: FC<Props> = (props) => {
|
||||
return
|
||||
}
|
||||
|
||||
const product = productsData?.data?.find((item) => item.id === value)
|
||||
?? resolveProductsData?.data?.find((item) => item.id === value)
|
||||
const product = products.find((item) => item.id === value)
|
||||
?? resolveProducts.find((item) => item.id === value)
|
||||
|
||||
onProductSelect?.(product)
|
||||
}, [value, productsData, resolveProductsData, onProductSelect])
|
||||
}, [value, products, resolveProducts, onProductSelect])
|
||||
|
||||
const emitProductChange = (nextValue: string) => {
|
||||
onChange?.({
|
||||
@@ -145,7 +158,7 @@ const ProductsSelect: FC<Props> = (props) => {
|
||||
const handleProductChange = (e: ChangeEvent<HTMLSelectElement>) => {
|
||||
onChange?.(e)
|
||||
|
||||
const product = productsData?.data?.find((item) => item.id === e.target.value)
|
||||
const product = products.find((item) => item.id === e.target.value)
|
||||
onProductSelect?.(product)
|
||||
}
|
||||
|
||||
@@ -175,7 +188,7 @@ const ProductsSelect: FC<Props> = (props) => {
|
||||
value={value}
|
||||
onChange={handleProductChange}
|
||||
error_text={error_text}
|
||||
disabled={!canLoadProducts}
|
||||
disabled={!activeCategoryId}
|
||||
{...rest}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -2,7 +2,7 @@ import axios from "@/config/axios";
|
||||
import type {
|
||||
AddTicketType,
|
||||
AttributeResponseType,
|
||||
CategoriesResponseType,
|
||||
CategoryType,
|
||||
MyRequestsResponseType,
|
||||
RequestDetailResponseType,
|
||||
RequestType,
|
||||
@@ -11,7 +11,7 @@ import type {
|
||||
} from "../type/Types";
|
||||
|
||||
export const getCategories = async () => {
|
||||
const { data } = await axios.get<CategoriesResponseType>(`/public/categories`);
|
||||
const { data } = await axios.get<CategoryType[]>(`/public/category/tree?isActive=true`);
|
||||
return data;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user