From 0e8216b0c9492f97b715b2dcd90ee3413e502cf3 Mon Sep 17 00:00:00 2001 From: efrilm Date: Fri, 12 Sep 2025 03:11:01 +0700 Subject: [PATCH] Vendor Api --- src/services/api.ts | 2 +- src/services/queries/vendor.ts | 36 +++ src/types/services/vendor.ts | 23 ++ .../apps/vendor/list/VendorListTable.tsx | 240 +++++++++--------- 4 files changed, 179 insertions(+), 122 deletions(-) create mode 100644 src/services/queries/vendor.ts create mode 100644 src/types/services/vendor.ts diff --git a/src/services/api.ts b/src/services/api.ts index beec3a6..7d72506 100644 --- a/src/services/api.ts +++ b/src/services/api.ts @@ -6,7 +6,7 @@ const getToken = () => { } export const api = axios.create({ - baseURL: 'https://api-pos.apskel.id/api/v1', + baseURL: 'http://127.0.0.1:4000/api/v1', headers: { 'Content-Type': 'application/json' }, diff --git a/src/services/queries/vendor.ts b/src/services/queries/vendor.ts new file mode 100644 index 0000000..ce35d99 --- /dev/null +++ b/src/services/queries/vendor.ts @@ -0,0 +1,36 @@ +import { useQuery } from '@tanstack/react-query' +import { api } from '../api' +import { Vendors } from '@/types/services/vendor' + +interface VendorQueryParams { + page?: number + limit?: number + search?: string +} + +export function useVendors(params: VendorQueryParams = {}) { + const { page = 1, limit = 10, search = '', ...filters } = params + + return useQuery({ + queryKey: ['vendors', { page, limit, search, ...filters }], + queryFn: async () => { + const queryParams = new URLSearchParams() + + queryParams.append('page', page.toString()) + queryParams.append('limit', limit.toString()) + + if (search) { + queryParams.append('search', search) + } + + Object.entries(filters).forEach(([key, value]) => { + if (value !== undefined && value !== null && value !== '') { + queryParams.append(key, value.toString()) + } + }) + + const res = await api.get(`/vendors?${queryParams.toString()}`) + return res.data.data + } + }) +} diff --git a/src/types/services/vendor.ts b/src/types/services/vendor.ts new file mode 100644 index 0000000..367a7d1 --- /dev/null +++ b/src/types/services/vendor.ts @@ -0,0 +1,23 @@ +export interface Vendor { + id: string + organization_id: string + name: string + email?: string + phone_number?: string + address?: string + contact_person?: string + tax_number?: string + payment_terms?: string + notes?: string + is_active: boolean + created_at: string + updated_at: string +} + +export interface Vendors { + vendors: Vendor[] + total_count: number + page: number + limit: number + total_pages: number +} diff --git a/src/views/apps/vendor/list/VendorListTable.tsx b/src/views/apps/vendor/list/VendorListTable.tsx index 754d059..9cf4527 100644 --- a/src/views/apps/vendor/list/VendorListTable.tsx +++ b/src/views/apps/vendor/list/VendorListTable.tsx @@ -1,7 +1,7 @@ 'use client' // React Imports -import { useEffect, useState, useMemo } from 'react' +import { useEffect, useState, useMemo, useCallback } from 'react' // Next Imports import Link from 'next/link' @@ -58,6 +58,9 @@ import { getLocalizedUrl } from '@/utils/i18n' // Style Imports import tableStyles from '@core/styles/table.module.css' import { formatCurrency } from '@/utils/transform' +import { useVendors } from '@/services/queries/vendor' +import { Vendor } from '@/types/services/vendor' +import Loading from '@/components/layout/shared/Loading' declare module '@tanstack/table-core' { interface FilterFns { @@ -68,7 +71,7 @@ declare module '@tanstack/table-core' { } } -type VendorTypeWithAction = VendorType & { +type VendorTypeWithAction = Vendor & { action?: string } @@ -120,17 +123,37 @@ const DebouncedInput = ({ // Column Definitions const columnHelper = createColumnHelper() -const VendorListTable = ({ tableData }: { tableData?: VendorType[] }) => { +const VendorListTable = () => { // States const [addVendorOpen, setAddVendorOpen] = useState(false) const [rowSelection, setRowSelection] = useState({}) - const [data, setData] = useState(...[tableData]) - const [filteredData, setFilteredData] = useState(data) const [globalFilter, setGlobalFilter] = useState('') + const [currentPage, setCurrentPage] = useState(1) + const [pageSize, setPageSize] = useState(10) + const [search, setSearch] = useState('') + + const { data, isLoading, error, isFetching } = useVendors({ + page: currentPage, + limit: pageSize, + search + }) + + const vendors = data?.vendors ?? [] + const totalCount = data?.total_count ?? 0 // Hooks const { lang: locale } = useParams() + const handlePageChange = useCallback((event: unknown, newPage: number) => { + setCurrentPage(newPage) + }, []) + + const handlePageSizeChange = useCallback((event: React.ChangeEvent) => { + const newPageSize = parseInt(event.target.value, 10) + setPageSize(newPageSize) + setCurrentPage(1) // Reset to first page + }, []) + const columns = useMemo[]>( () => [ { @@ -155,15 +178,14 @@ const VendorListTable = ({ tableData }: { tableData?: VendorType[] }) => { /> ) }, - columnHelper.accessor('name', { + columnHelper.accessor('contact_person', { header: 'Vendor', cell: ({ row }) => (
- {getAvatar({ photo: row.original.photo, name: row.original.name })}
- {row.original.name} + {row.original.contact_person} {row.original.email} @@ -171,87 +193,50 @@ const VendorListTable = ({ tableData }: { tableData?: VendorType[] }) => {
) }), - columnHelper.accessor('company', { + columnHelper.accessor('name', { header: 'Perusahaan', cell: ({ row }) => (
- {row.original.company} + {row.original.name}
) }), - columnHelper.accessor('telephone', { + columnHelper.accessor('phone_number', { header: 'Telepon', - cell: ({ row }) => {row.original.telephone} - }), - columnHelper.accessor('youPayable', { - header: () =>
Anda Hutang
, - cell: ({ row }) => ( -
- - {formatCurrency(row.original.youPayable)} - -
- ) - }), - columnHelper.accessor('theyPayable', { - header: () =>
Mereka Hutang
, - cell: ({ row }) => ( -
- - {formatCurrency(row.original.theyPayable)} - -
- ) + cell: ({ row }) => {row.original.phone_number} }) ], // eslint-disable-next-line react-hooks/exhaustive-deps - [data, filteredData] + [] ) const table = useReactTable({ - data: filteredData as VendorType[], + data: vendors as Vendor[], columns, filterFns: { fuzzy: fuzzyFilter }, state: { rowSelection, - globalFilter - }, - initialState: { + globalFilter, pagination: { - pageSize: 10 + pageIndex: currentPage, + pageSize } }, enableRowSelection: true, - globalFilterFn: fuzzyFilter, onRowSelectionChange: setRowSelection, getCoreRowModel: getCoreRowModel(), - onGlobalFilterChange: setGlobalFilter, - getFilteredRowModel: getFilteredRowModel(), - getSortedRowModel: getSortedRowModel(), - getPaginationRowModel: getPaginationRowModel(), - getFacetedRowModel: getFacetedRowModel(), - getFacetedUniqueValues: getFacetedUniqueValues(), - getFacetedMinMaxValues: getFacetedMinMaxValues() + manualPagination: true, + pageCount: Math.ceil(totalCount / pageSize) }) - const getAvatar = (params: Pick) => { - const { photo, name } = params - - if (photo) { - return - } else { - return {getInitials(name as string)} - } - } - return ( <> - + {/* */}
{
setGlobalFilter(String(value))} + value={search ?? ''} + onChange={value => setSearch(value as string)} placeholder='Cari Vendor' className='max-sm:is-full' /> @@ -289,75 +274,88 @@ const VendorListTable = ({ tableData }: { tableData?: VendorType[] }) => {
- - - {table.getHeaderGroups().map(headerGroup => ( - - {headerGroup.headers.map(header => ( - - ))} - - ))} - - {table.getFilteredRowModel().rows.length === 0 ? ( - - - - - - ) : ( - - {table - .getRowModel() - .rows.slice(0, table.getState().pagination.pageSize) - .map(row => { - return ( - - {row.getVisibleCells().map(cell => ( - - ))} - - ) - })} - - )} -
- {header.isPlaceholder ? null : ( - <> -
- {flexRender(header.column.columnDef.header, header.getContext())} - {{ - asc: , - desc: - }[header.column.getIsSorted() as 'asc' | 'desc'] ?? null} -
- - )} -
- Tidak ada data tersedia -
{flexRender(cell.column.columnDef.cell, cell.getContext())}
+ {isLoading ? ( + + ) : ( + + + {table.getHeaderGroups().map(headerGroup => ( + + {headerGroup.headers.map(header => ( + + ))} + + ))} + + {table.getFilteredRowModel().rows.length === 0 ? ( + + + + + + ) : ( + + {table + .getRowModel() + .rows.slice(0, table.getState().pagination.pageSize) + .map(row => { + return ( + + {row.getVisibleCells().map(cell => ( + + ))} + + ) + })} + + )} +
+ {header.isPlaceholder ? null : ( + <> +
+ {flexRender(header.column.columnDef.header, header.getContext())} + {{ + asc: , + desc: + }[header.column.getIsSorted() as 'asc' | 'desc'] ?? null} +
+ + )} +
+ Tidak ada data tersedia +
{flexRender(cell.column.columnDef.cell, cell.getContext())}
+ )}
- { - table.setPageIndex(page) - }} + ( + + )} + count={totalCount} + rowsPerPage={pageSize} + page={currentPage} + onPageChange={handlePageChange} + onRowsPerPageChange={handlePageSizeChange} + rowsPerPageOptions={[10, 25, 50]} + disabled={isLoading} />
- setAddVendorOpen(!addVendorOpen)} vendorData={data} setData={setData} - /> + /> */} ) }