diff options
Diffstat (limited to 'src/modules/result/components/Table.tsx')
| -rw-r--r-- | src/modules/result/components/Table.tsx | 267 |
1 files changed, 133 insertions, 134 deletions
diff --git a/src/modules/result/components/Table.tsx b/src/modules/result/components/Table.tsx index 082f988..555c8af 100644 --- a/src/modules/result/components/Table.tsx +++ b/src/modules/result/components/Table.tsx @@ -1,9 +1,9 @@ "use client"; import { useResultStore } from "@/common/stores/useResultStore"; import { StockOpnameRes } from "@/common/types/stockOpname"; -import { Button, Dropdown, DropdownItem, DropdownMenu, DropdownTrigger, Pagination, Skeleton, Spacer, Spinner } from "@nextui-org/react" +import { Button, Dropdown, DropdownItem, DropdownMenu, DropdownTrigger, Pagination, Skeleton, Spacer, Spinner } from "@nextui-org/react"; import { keepPreviousData, useQuery } from "@tanstack/react-query"; -import styles from "./table.module.css" +import styles from "./table.module.css"; import clsxm from "@/common/libs/clsxm"; import DetailRow from "./DetailRow"; import { useDebounce } from "usehooks-ts"; @@ -16,165 +16,170 @@ import toast from "@/common/libs/toast"; import { Product } from "prisma/generated/client"; const Table = () => { - const credential = getClientCredential() + const credential = getClientCredential(); - const { filter: { company, search, show, page }, updateFilter } = useResultStore() - const debouncedSearch = useDebounce(search, 500) + const { + filter: { company, search, show, page }, + updateFilter, + } = useResultStore(); + const debouncedSearch = useDebounce(search, 500); useEffect(() => { - updateFilter('page', 1) - }, [company, debouncedSearch, show, updateFilter]) + updateFilter("page", 1); + }, [company, debouncedSearch, show, updateFilter]); const stockOpnames = useQuery({ - queryKey: ['stockOpnames', company, debouncedSearch, page, show], + queryKey: ["stockOpnames", company, debouncedSearch, page, show], queryFn: async () => { - const searchParams = new URLSearchParams() - if (!company) return null - searchParams.set('companyId', company) + const searchParams = new URLSearchParams(); + if (!company) return null; + searchParams.set("companyId", company); - const showValue = SHOWING_SELECTIONS.find((item) => item.key === show)?.value || '' - searchParams.set('show', showValue); + const showValue = SHOWING_SELECTIONS.find((item) => item.key === show)?.value || ""; + searchParams.set("show", showValue); - if (debouncedSearch) searchParams.set('search', debouncedSearch) + if (debouncedSearch) searchParams.set("search", debouncedSearch); - searchParams.set('page', page.toString()); + searchParams.set("page", page.toString()); - return await fetch(`/api/stock-opname?${searchParams}`) - .then(res => { - window.scrollTo({ top: 0, 'behavior': 'smooth' }) - return res.json() - }) + return await fetch(`/api/stock-opname?${searchParams}`).then((res) => { + window.scrollTo({ top: 0, behavior: "smooth" }); + return res.json(); + }); }, - placeholderData: keepPreviousData - }) + placeholderData: keepPreviousData, + }); - const { filter } = useResultStore() + const { filter } = useResultStore(); - const [exportLoad, setExportLoad] = useState<boolean>(false) + const [exportLoad, setExportLoad] = useState<boolean>(false); const exportResult = async () => { - setExportLoad(true) - const response = await fetch(`/api/stock-opname/export?companyId=${filter.company}`) - const buffer = await response.arrayBuffer() - console.log({ type: response.headers.get('type') }); - - const blob = new Blob([buffer], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' }) - const url = window.URL.createObjectURL(blob) - const a = document.createElement('a') - a.href = url - a.download = `export_${moment().format('MM_DD_HH_ss')}.xlsx` - document.body.appendChild(a) - a.click() - document.body.removeChild(a) - setExportLoad(false) - } + setExportLoad(true); + const response = await fetch(`/api/stock-opname/export?companyId=${filter.company}`); + const buffer = await response.arrayBuffer(); + + const blob = new Blob([buffer], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" }); + const url = window.URL.createObjectURL(blob); + const a = document.createElement("a"); + a.href = url; + a.download = `export_${moment().format("MM_DD_HH_ss")}.xlsx`; + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); + setExportLoad(false); + }; const toggleDifferent = async (id: number) => { - const response = await fetch(`/api/product/${id}/toggle-different`, { method: 'POST' }) - const product: Product = await response.json() - toast(`Berhasil mengubah status barang ${product.itemCode} ${product.name} menjadi ${product.isDifferent ? 'selisih' : 'aman'}`, { duration: 10000 }) - stockOpnames.refetch() - } + const response = await fetch(`/api/product/${id}/toggle-different`, { method: "POST" }); + const product: Product = await response.json(); + toast(`Berhasil mengubah status barang ${product.itemCode} ${product.name} menjadi ${product.isDifferent ? "selisih" : "aman"}`, { duration: 10000 }); + stockOpnames.refetch(); + }; const recompute = async (productId: number, companyId: string) => { - const response = await fetch(`/api/company/${companyId}/product/${productId}/compute-different`, { method: 'POST' }) - const stockOpname = await response.json() - toast(`Berhasil menghitung ulang status barang, hasilnya ${stockOpname.data.isDifferent ? 'selisih' : 'aman'}`) - stockOpnames.refetch() - } + const response = await fetch(`/api/company/${companyId}/product/${productId}/compute-different`, { method: "POST" }); + const stockOpname = await response.json(); + toast(`Berhasil menghitung ulang status barang, hasilnya ${stockOpname.data.isDifferent ? "selisih" : "aman"}`); + stockOpnames.refetch(); + }; - const isLoading = stockOpnames.isLoading || stockOpnames.isRefetching + const isLoading = stockOpnames.isLoading || stockOpnames.isRefetching; - const COL_LENGTH = 9 + const COL_LENGTH = 9; return ( <> <div className="flex"> <Button type="button" onPress={exportResult} disabled={exportLoad} variant="flat" className="ml-auto mb-4"> - {exportLoad ? <><Spinner size="sm" />Exporting...</> : 'Export'} + {exportLoad ? ( + <> + <Spinner size="sm" /> + Exporting... + </> + ) : ( + "Export" + )} </Button> </div> <div className="w-full flex-1 overflow-auto pb-4"> <table className="w-full"> <thead className={styles.thead}> - <th className={styles.th}>STATUS</th> - <th className={clsxm(styles.th, '!text-left')}>NAMA PRODUK</th> - <th className={styles.th}>TIM HITUNG 1</th> - <th className={styles.th}>TIM HITUNG 2</th> - <th className={styles.th}>TIM HITUNG 3</th> - <th className={styles.th}>TIM VERIFIKASI</th> - <th className={styles.th}>ON-HAND QTY</th> - <th className={styles.th}>GUDANG SELISIH</th> - <th className={styles.th}></th> + <tr> + <th className={styles.th}>STATUS</th> + <th className={clsxm(styles.th, "!text-left")}>NAMA PRODUK</th> + <th className={styles.th}>TIM HITUNG 1</th> + <th className={styles.th}>TIM HITUNG 2</th> + <th className={styles.th}>TIM HITUNG 3</th> + <th className={styles.th}>TIM VERIFIKASI</th> + <th className={styles.th}>ON-HAND QTY</th> + <th className={styles.th}>GUDANG SELISIH</th> + <th className={styles.th}></th> + </tr> </thead> <tbody className={styles.tbody}> - {!isLoading && stockOpnames.data?.result.map((stockOpname: StockOpnameRes['result']) => ( - <> - <tr key={stockOpname.id} className={clsxm("border-t border-neutral-200", { - "text-danger-600": stockOpname.isDifferent, - "text-success-600": !stockOpname.isDifferent - })} - > - <td className={styles.td}> - <div className={clsxm("w-full rounded-lg mr-1 p-1 text-xs text-white whitespace-nowrap", { - "bg-danger-600": stockOpname.isDifferent, - "bg-success-600": !stockOpname.isDifferent, - })}> - {stockOpname.isDifferent ? 'Selisih' : 'Aman'} - </div> - </td> - <td className={clsxm(styles.td, '!text-left flex min-w-[250px]')} aria-label="name"> - {stockOpname.itemCode ? `[${stockOpname.itemCode}] ` : ''} - {stockOpname.name} - {stockOpname.barcode ? ` [${stockOpname.barcode}]` : ''} - </td> - <td className={styles.td}> - {credential?.team == 'VERIFICATION' && typeof stockOpname.quantity.COUNT1 === 'number' ? stockOpname.quantity.COUNT1 : '-'} - </td> - <td className={styles.td}> - {credential?.team == 'VERIFICATION' && typeof stockOpname.quantity.COUNT2 === 'number' ? stockOpname.quantity.COUNT2 : '-'} - </td> - <td className={styles.td}> - {credential?.team == 'VERIFICATION' && typeof stockOpname.quantity.COUNT3 === 'number' ? stockOpname.quantity.COUNT3 : '-'} - </td> - <td className={styles.td}> - {credential?.team == 'VERIFICATION' && typeof stockOpname.quantity.VERIFICATION === 'number' ? stockOpname.quantity.VERIFICATION : '-'} - </td> - <td className={styles.td}> - {credential?.team == 'VERIFICATION' ? stockOpname.onhandQty : '-'} - </td> - <td className={styles.td}> - {credential?.team == 'VERIFICATION' ? stockOpname.differenceQty : '-'} - </td> - <td> - {credential?.team == 'VERIFICATION' && ( - <Dropdown> - <DropdownTrigger> - <Button variant="light" className="p-1 min-w-fit"> - <MoreVerticalIcon size={16} /> - </Button> - </DropdownTrigger> - <DropdownMenu> - <DropdownItem key="recompute" onPress={() => recompute(stockOpname.id, company)}> - Re-compute - </DropdownItem> - <DropdownItem key="toggleDifferent" onPress={() => toggleDifferent(stockOpname.id)}> - Tandai {stockOpname.isDifferent ? 'aman' : 'selisih'} - </DropdownItem> - </DropdownMenu> - </Dropdown> - )} - </td> - </tr> - - <DetailRow productId={stockOpname.id} /> - </> - ))} + {!isLoading && + stockOpnames.data?.result.map((stockOpname: StockOpnameRes["result"]) => ( + <> + <tr + key={stockOpname.id} + className={clsxm("border-t border-neutral-200", { + "text-danger-600": stockOpname.isDifferent, + "text-success-600": !stockOpname.isDifferent, + })} + > + <td className={styles.td}> + <div + className={clsxm("w-full rounded-lg mr-1 p-1 text-xs text-white whitespace-nowrap", { + "bg-danger-600": stockOpname.isDifferent, + "bg-success-600": !stockOpname.isDifferent, + })} + > + {stockOpname.isDifferent ? "Selisih" : "Aman"} + </div> + </td> + <td className={clsxm(styles.td, "!text-left flex min-w-[250px]")} aria-label="name"> + {stockOpname.itemCode ? `[${stockOpname.itemCode}] ` : ""} + {stockOpname.name} + {stockOpname.barcode ? ` [${stockOpname.barcode}]` : ""} + </td> + <td className={styles.td}>{credential?.team == "VERIFICATION" && typeof stockOpname.quantity.COUNT1 === "number" ? stockOpname.quantity.COUNT1 : "-"}</td> + <td className={styles.td}>{credential?.team == "VERIFICATION" && typeof stockOpname.quantity.COUNT2 === "number" ? stockOpname.quantity.COUNT2 : "-"}</td> + <td className={styles.td}>{credential?.team == "VERIFICATION" && typeof stockOpname.quantity.COUNT3 === "number" ? stockOpname.quantity.COUNT3 : "-"}</td> + <td className={styles.td}>{credential?.team == "VERIFICATION" && typeof stockOpname.quantity.VERIFICATION === "number" ? stockOpname.quantity.VERIFICATION : "-"}</td> + <td className={styles.td}>{credential?.team == "VERIFICATION" ? stockOpname.onhandQty : "-"}</td> + <td className={styles.td}>{credential?.team == "VERIFICATION" ? stockOpname.differenceQty : "-"}</td> + <td> + {credential?.team == "VERIFICATION" && ( + <Dropdown> + <DropdownTrigger> + <Button variant="light" className="p-1 min-w-fit"> + <MoreVerticalIcon size={16} /> + </Button> + </DropdownTrigger> + <DropdownMenu> + <DropdownItem key="recompute" onPress={() => recompute(stockOpname.id, company)}> + Re-compute + </DropdownItem> + <DropdownItem key="toggleDifferent" onPress={() => toggleDifferent(stockOpname.id)}> + Tandai {stockOpname.isDifferent ? "aman" : "selisih"} + </DropdownItem> + </DropdownMenu> + </Dropdown> + )} + </td> + </tr> + + <DetailRow productId={stockOpname.id} /> + </> + ))} {!isLoading && stockOpnames.data?.result.length === 0 && ( <tr> - <td colSpan={COL_LENGTH} className="text-center text-neutral-600 py-4">Belum ada data untuk ditampilkan</td> + <td colSpan={COL_LENGTH} className="text-center text-neutral-600 py-4"> + Belum ada data untuk ditampilkan + </td> </tr> )} @@ -191,19 +196,13 @@ const Table = () => { )} </tbody> </table> - </div> <Spacer y={4} /> - <Pagination - page={stockOpnames.data?.page || 1} - total={stockOpnames.data?.totalPage || 1} - onChange={(page) => updateFilter('page', page)} - className="min-h-[36px] m-0 p-0" - /> + <Pagination page={stockOpnames.data?.page || 1} total={stockOpnames.data?.totalPage || 1} onChange={(page) => updateFilter("page", page)} className="min-h-[36px] m-0 p-0" /> </> - ) -} + ); +}; -export default Table
\ No newline at end of file +export default Table; |
