feat(FE-33): create customers table and details

This commit is contained in:
randy-ar
2025-10-09 04:34:56 +07:00
parent 21b9396323
commit 21cc01fe68
7 changed files with 418 additions and 243 deletions
@@ -1,33 +1,36 @@
'use client'
'use client';
import Button from "@/components/Button";
import DebouncedTextInput from "@/components/input/DebouncedTextInput";
import { useModal } from "@/components/Modal";
import ConfirmationModal from "@/components/modal/ConfirmationModal";
import Table from "@/components/Table";
import RowCollapseOptions from "@/components/table/RowCollapseOptions";
import RowDropdownOptions from "@/components/table/RowDropdownOptions";
import { isResponseSuccess } from "@/lib/api-helper";
import { cn } from "@/lib/helper";
import { CustomerApi } from "@/services/api/master-data";
import { useTableFilter } from "@/services/hooks/useTableFilter";
import { Customer } from "@/types/api/master-data/customer";
import { Icon } from "@iconify/react";
import {
CellContext,
ColumnDef,
import Button from '@/components/Button';
import DebouncedTextInput from '@/components/input/DebouncedTextInput';
import SelectInput, { OptionType } from '@/components/input/SelectInput';
import { useModal } from '@/components/Modal';
import ConfirmationModal from '@/components/modal/ConfirmationModal';
import Table from '@/components/Table';
import RowCollapseOptions from '@/components/table/RowCollapseOptions';
import RowDropdownOptions from '@/components/table/RowDropdownOptions';
import { ROWS_OPTIONS } from '@/config/constant';
import { isResponseSuccess } from '@/lib/api-helper';
import { cn } from '@/lib/helper';
import { CustomerApi } from '@/services/api/master-data';
import { useTableFilter } from '@/services/hooks/useTableFilter';
import { Customer } from '@/types/api/master-data/customer';
import { Icon } from '@iconify/react';
import {
CellContext,
ColumnDef,
ColumnSort,
SortingState,
} from "@tanstack/react-table";
import { useState } from "react";
import useSWR from "swr";
} from '@tanstack/react-table';
import { useState } from 'react';
import toast from 'react-hot-toast';
import useSWR from 'swr';
const RowOptionsMenu = ({
type = 'dropdown',
props,
deleteClickHandler,
} : {
type: 'dropdown' | 'collapse',
}: {
type: 'dropdown' | 'collapse';
props: CellContext<Customer, unknown>;
deleteClickHandler: () => void;
}) => {
@@ -37,25 +40,33 @@ const RowOptionsMenu = ({
className={cn(
{
'dropdown-content': type === 'dropdown',
'mt-2': type === 'collapse'
'mt-2': type === 'collapse',
},
'p-2.5 mr-2 flex flex-col gap-1 bg-base-100 rounded-box z-10 border border-black/10 shadow'
)
}
>
)}
>
<Button
href={`/master-data/customer/detail/?customerId=${props.row.original.id}`}
variant='ghost'
color='primary'
className='justify-start text-sm'
>
<Icon icon='mdi:eye-outline' width={16} height={16}/>
<Icon icon='mdi:eye-outline' width={16} height={16} />
Detail
</Button>
<Button
className='justify-start text-sm'
href={`/master-data/customer/detail/edit/?customerId=${props.row.original.id}`}
variant='ghost'
color='warning'
>
<Icon icon='material-symbols:edit-outline' width={16} height={16} />
Edit
</Button>
<Button
onClick={deleteClickHandler}
variant='ghost'
color='error'
className='text-error hover:text-inherit'
>
<Icon
@@ -64,10 +75,11 @@ const RowOptionsMenu = ({
height={16}
className='justify-start text-sm'
/>
Delete
</Button>
</div>
);
}
};
const CustomersTable = () => {
const {
@@ -76,31 +88,34 @@ const CustomersTable = () => {
setPage,
setPageSize,
toQueryString: getTableFilterQueryString,
} = useTableFilter ({
initial: { search: '', nameSort: '', picSort: ''},
} = useTableFilter({
initial: { search: '', nameSort: '', picSort: '' },
paramMap: {
page: 'page',
pageSize: 'limit',
nameSort: 'sort_name',
picSort: 'sort_pic',
}
},
});
// Fetch Data
const {
data: customers,
isLoading,
mutate: refreshCustomers
mutate: refreshCustomers,
} = useSWR(
`${CustomerApi.basePath}${getTableFilterQueryString()}`,
CustomerApi.getAllFetcher
);
// State
const deleteModal = useModal();
const [selectedCustomer, setSelectedCustomer] = useState<Customer | undefined>(undefined);
const [selectedCustomer, setSelectedCustomer] = useState<
Customer | undefined
>(undefined);
const [isDeleteLoading, setIsDeleteLoading] = useState(false);
// Columns Definition
const customersColumns: ColumnDef<Customer>[] = [
{
header: '#',
@@ -173,6 +188,24 @@ const CustomersTable = () => {
},
];
// Handler
const confirmationModalDeleteClickHandler = async () => {
setIsDeleteLoading(true);
await CustomerApi.delete(selectedCustomer?.id as number);
refreshCustomers();
deleteModal.closeModal();
toast.success('Successfully delete Customer!');
setIsDeleteLoading(false);
};
const searchChangeHandler = (e: React.ChangeEvent<HTMLInputElement>) => {
updateFilter('search', e.target.value);
};
const pageSizeChangeHandler = (val: OptionType | OptionType[] | null) => {
const newVal = val as OptionType;
setPageSize(newVal.value as number);
};
return (
<>
@@ -190,11 +223,22 @@ const CustomersTable = () => {
name='search'
placeholder='Cari Kandang'
value={tableFilterState.search}
onChange={searchChangeHandler}
className={{ wrapper: 'sm:max-w-3xs' }}
/>
</div>
<div className='flex flex-row justify-end'>
<SelectInput
label='Baris'
options={ROWS_OPTIONS}
value={{
label: String(tableFilterState.pageSize),
value: tableFilterState.pageSize,
}}
onChange={pageSizeChangeHandler}
className={{ wrapper: 'max-w-28' }}
/>
</div>
</div>
@@ -236,10 +280,11 @@ const CustomersTable = () => {
text: 'Ya',
color: 'error',
isLoading: isDeleteLoading,
onClick: confirmationModalDeleteClickHandler,
}}
/>
</>
);
}
};
export default CustomersTable;