diff --git a/apps/web/src/constants/cache.ts b/apps/web/src/constants/cache.ts
index 5a3433f2..b5310b1b 100644
--- a/apps/web/src/constants/cache.ts
+++ b/apps/web/src/constants/cache.ts
@@ -44,4 +44,10 @@ export const CACHE = {
company: {
key: '/company',
},
+ supplier: {
+ key: '/supplier',
+ },
+ suppliers: {
+ key: '/suppliers',
+ },
}
diff --git a/apps/web/src/ui/components/commons/supplier-select/index.tsx b/apps/web/src/ui/components/commons/supplier-select/index.tsx
new file mode 100644
index 00000000..565f0bde
--- /dev/null
+++ b/apps/web/src/ui/components/commons/supplier-select/index.tsx
@@ -0,0 +1,81 @@
+import { Button, Pagination, Spinner } from '@nextui-org/react'
+import { Icon } from '@/ui/components/commons/icon'
+import { Select } from '@/ui/components/commons/select'
+import { Dialog } from '../dialog'
+import { useSupplierSelect } from './use-supplier-select'
+
+type SupplierSelectProps = {
+ defeaultSupplierId?: string
+ className?: string
+ onSelectChange: (supplierId: string) => void
+}
+
+export const SupplierSelect = ({
+ className,
+ defeaultSupplierId,
+ onSelectChange,
+}: SupplierSelectProps) => {
+ const {
+ suppliers,
+ isFetching,
+ page,
+ totalPages,
+ selectedSupplierName,
+ handleSupplierIdChange,
+ handleSupplierPageChange,
+ } = useSupplierSelect(onSelectChange, defeaultSupplierId)
+
+ return isFetching ? (
+
+ ) : (
+
+
+
+ )
+}
diff --git a/apps/web/src/ui/components/commons/supplier-select/use-supplier-select.ts b/apps/web/src/ui/components/commons/supplier-select/use-supplier-select.ts
new file mode 100644
index 00000000..2304786f
--- /dev/null
+++ b/apps/web/src/ui/components/commons/supplier-select/use-supplier-select.ts
@@ -0,0 +1,85 @@
+import { CACHE } from '@/constants'
+import { useApi, useCache, useToast, useUrlParamNumber } from '@/ui/hooks'
+import { Supplier } from '@stocker/core/entities'
+import { useEffect, useState } from 'react'
+import { useAuthContext } from '../../contexts/auth-context'
+
+export function useSupplierSelect(
+ onSelectChange: (supplierId: string) => void,
+ defeaultSelectedSupplierId?: string,
+) {
+ const [supplierId, setSupplierId] = useState(defeaultSelectedSupplierId)
+ const { suppliersService } = useApi()
+ const { company } = useAuthContext()
+ const { showError } = useToast()
+ const [page, setPage] = useUrlParamNumber('supplierPage', 1)
+ const [expandedItems, setExpandedItems] = useState<{ [key: string]: boolean }>({})
+
+ function handleSupplierIdChange(supplierId: string) {
+ setSupplierId(supplierId)
+ onSelectChange(supplierId)
+ }
+
+ async function fetchSupplier() {
+ if (!supplierId) return
+
+ const response = await suppliersService.getSupplier(supplierId)
+ if (response.isFailure) {
+ showError(response.errorMessage)
+ return
+ }
+ return response.body
+ }
+
+ async function fetchSuppliers() {
+ if (!company) return
+
+ const response = await suppliersService.listSuppliers({
+ page,
+ companyId: company.id,
+ })
+ if (response.isFailure) {
+ showError(response.errorMessage)
+ return
+ }
+ return response.body
+ }
+
+ const { data: supplierData } = useCache({
+ fetcher: fetchSupplier,
+ key: CACHE.supplier.key,
+ dependencies: [supplierId],
+ })
+
+ const { data: suppliersData, isFetching } = useCache({
+ fetcher: fetchSuppliers,
+ key: CACHE.suppliers.key,
+ dependencies: [page],
+ })
+
+ function handlePageChange(page: number) {
+ setPage(page)
+ }
+
+ function handleAccordionClick(id: string) {
+ setExpandedItems((prev) => ({
+ ...prev,
+ [id]: !prev[id],
+ }))
+ }
+
+ const suppliers = suppliersData ? suppliersData.items.map(Supplier.create) : []
+ const itemsCount = suppliersData ? suppliersData.itemsCount : 0
+
+ return {
+ isFetching,
+ totalPages: Math.ceil(itemsCount / 10),
+ page,
+ suppliers,
+ selectedSupplierName: supplierData?.name,
+ expandedItems,
+ handleSupplierIdChange,
+ handleAccordionClick,
+ handleSupplierPageChange: handlePageChange,
+ }
+}
diff --git a/apps/web/src/ui/components/pages/products/register-product-form/index.tsx b/apps/web/src/ui/components/pages/products/register-product-form/index.tsx
index 0c96b682..0e5425a4 100644
--- a/apps/web/src/ui/components/pages/products/register-product-form/index.tsx
+++ b/apps/web/src/ui/components/pages/products/register-product-form/index.tsx
@@ -8,6 +8,8 @@ import { useRegisterProductForm } from './use-register-product-form'
import { ImageInput } from '@/ui/components/commons/image-input'
import type { ImageInputRef } from '@/ui/components/commons/image-input/types'
import { CategorySelect } from '@/ui/components/commons/category-select'
+import { SupplierSelect } from '@/ui/components/commons/supplier-select'
+
type RegisterProductFormProps = {
onCancel: VoidFunction
@@ -66,7 +68,18 @@ export const RegisterProductForm = ({ onSubmit, onCancel }: RegisterProductFormP
/>
-
+
(
+
+
+ {errors.supplierId && (
+
{errors.supplierId?.message}
+ )}
+
+ )}
+ />
(value === '' ? undefined : value))
diff --git a/apps/web/src/ui/components/pages/products/update-product-form/index.tsx b/apps/web/src/ui/components/pages/products/update-product-form/index.tsx
index 4ab9e466..07979c58 100644
--- a/apps/web/src/ui/components/pages/products/update-product-form/index.tsx
+++ b/apps/web/src/ui/components/pages/products/update-product-form/index.tsx
@@ -10,6 +10,7 @@ import { ImageInput } from '@/ui/components/commons/image-input'
import type { ImageInputRef } from '@/ui/components/commons/image-input/types'
import { useUpdateProductForm } from './use-update-product-form'
import { CategorySelect } from '@/ui/components/commons/category-select'
+import { SupplierSelect } from '@/ui/components/commons/supplier-select'
type RegisterProductFormProps = {
product: Product
@@ -87,7 +88,18 @@ export const UpdateProductForm = ({
/>
-
+
(
+
+
+ {errors.supplierId && (
+
{errors.supplierId?.message}
+ )}
+
+ )}
+ />