FPSMS-frontend
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

269 lines
9.0 KiB

  1. "use client";
  2. import { InventoryLotLineResult, InventoryResult } from "@/app/api/inventory";
  3. import { useTranslation } from "react-i18next";
  4. import SearchBox, { Criterion } from "../SearchBox";
  5. import { useCallback, useEffect, useMemo, useState } from "react";
  6. import { isEqual, orderBy, uniq, uniqBy } from "lodash";
  7. import SearchResults, { Column } from "../SearchResults";
  8. import { CheckCircleOutline, DoDisturb } from "@mui/icons-material";
  9. import InventoryTable from "./InventoryTable";
  10. import { defaultPagingController } from "../SearchResults/SearchResults";
  11. import InventoryLotLineTable from "./InventoryLotLineTable";
  12. import { SearchInventory, SearchInventoryLotLine, fetchInventories, fetchInventoryLotLines } from "@/app/api/inventory/actions";
  13. import { PrinterCombo } from "@/app/api/settings/printer";
  14. interface Props {
  15. inventories: InventoryResult[];
  16. printerCombo?: PrinterCombo[];
  17. }
  18. type SearchQuery = Partial<
  19. Omit<
  20. InventoryResult,
  21. | "id"
  22. | "qty"
  23. | "uomCode"
  24. | "uomUdfudesc"
  25. | "germPerSmallestUnit"
  26. | "qtyPerSmallestUnit"
  27. | "itemSmallestUnit"
  28. | "price"
  29. | "description"
  30. | "category"
  31. >
  32. >;
  33. type SearchParamNames = keyof SearchQuery;
  34. const InventorySearch: React.FC<Props> = ({ inventories, printerCombo }) => {
  35. const { t } = useTranslation(["inventory", "common"]);
  36. // Inventory
  37. const [filteredInventories, setFilteredInventories] = useState<InventoryResult[]>([]);
  38. const [inventoriesPagingController, setInventoriesPagingController] = useState(defaultPagingController)
  39. const [inventoriesTotalCount, setInventoriesTotalCount] = useState(0)
  40. const [selectedInventory, setSelectedInventory] = useState<InventoryResult | null>(null)
  41. // Inventory Lot Line
  42. const [filteredInventoryLotLines, setFilteredInventoryLotLines] = useState<InventoryLotLineResult[]>([]);
  43. const [inventoryLotLinesPagingController, setInventoryLotLinesPagingController] = useState(defaultPagingController)
  44. const [inventoryLotLinesTotalCount, setInventoryLotLinesTotalCount] = useState(0)
  45. const defaultInputs = useMemo(() => ({
  46. itemId: "",
  47. itemCode: "",
  48. itemName: "",
  49. itemType: "",
  50. onHandQty: "",
  51. onHoldQty: "",
  52. unavailableQty: "",
  53. availableQty: "",
  54. currencyName: "",
  55. status: "",
  56. baseUom: "",
  57. uomShortDesc: "",
  58. latestMarketUnitPrice: "",
  59. latestMupUpdatedDate: "",
  60. }), [])
  61. const [inputs, setInputs] = useState<Record<SearchParamNames, string>>(defaultInputs);
  62. const searchCriteria: Criterion<SearchParamNames>[] = useMemo(
  63. () => [
  64. { label: t("Code"), paramName: "itemCode", type: "text" },
  65. { label: t("Name"), paramName: "itemName", type: "text" },
  66. {
  67. label: t("Type"),
  68. paramName: "itemType",
  69. type: "select",
  70. options: uniq(inventories.map((i) => i.itemType)),
  71. },
  72. // {
  73. // label: t("Status"),
  74. // paramName: "status",
  75. // type: "select",
  76. // options: uniq(inventories.map((i) => i.status)),
  77. // },
  78. ],
  79. [t],
  80. );
  81. // Inventory
  82. const refetchInventoryData = useCallback(async (
  83. query: Record<SearchParamNames, string>,
  84. actionType: "reset" | "search" | "paging" | "init",
  85. pagingController: typeof defaultPagingController,
  86. ) => {
  87. console.log("%c Action Type 1.", "color:red", actionType)
  88. // Avoid loading data again
  89. if (actionType === "paging" && pagingController === defaultPagingController) {
  90. return
  91. }
  92. console.log("%c Action Type 2.", "color:blue", actionType)
  93. const params: SearchInventory = {
  94. code: query?.itemCode ?? '',
  95. name: query?.itemName ?? '',
  96. type: query?.itemType.toLowerCase() === "all" ? '' : query?.itemType ?? '',
  97. pageNum: pagingController.pageNum - 1,
  98. pageSize: pagingController.pageSize
  99. }
  100. const response = await fetchInventories(params)
  101. if (response) {
  102. setInventoriesTotalCount(response.total);
  103. switch (actionType) {
  104. case "init":
  105. case "reset":
  106. case "search":
  107. setFilteredInventories(() => response.records);
  108. break;
  109. case "paging":
  110. setFilteredInventories((fi) =>
  111. // orderBy(
  112. uniqBy([...fi, ...response.records], "id")
  113. // , ["id"], ["desc"])
  114. );
  115. }
  116. }
  117. }, [])
  118. useEffect(() => {
  119. refetchInventoryData(defaultInputs, "init", defaultPagingController)
  120. }, [])
  121. useEffect(() => {
  122. // if (!isEqual(inventoriesPagingController, defaultPagingController)) {
  123. refetchInventoryData(inputs, "paging", inventoriesPagingController)
  124. // }
  125. }, [inventoriesPagingController])
  126. // Inventory Lot Line
  127. const refetchInventoryLotLineData = useCallback(async (
  128. itemId: number | null,
  129. actionType: "reset" | "search" | "paging",
  130. pagingController: typeof defaultPagingController,
  131. ) => {
  132. if (!itemId) {
  133. setSelectedInventory(null)
  134. setInventoryLotLinesTotalCount(0);
  135. setFilteredInventoryLotLines([])
  136. return
  137. }
  138. // Avoid loading data again
  139. if (actionType === "paging" && pagingController === defaultPagingController) {
  140. return
  141. }
  142. const params: SearchInventoryLotLine = {
  143. itemId: itemId,
  144. pageNum: pagingController.pageNum - 1,
  145. pageSize: pagingController.pageSize
  146. }
  147. const response = await fetchInventoryLotLines(params)
  148. if (response) {
  149. setInventoryLotLinesTotalCount(response.total);
  150. switch (actionType) {
  151. case "reset":
  152. case "search":
  153. setFilteredInventoryLotLines(() => response.records);
  154. break;
  155. case "paging":
  156. setFilteredInventoryLotLines((fi) =>
  157. // orderBy(
  158. uniqBy([...fi, ...response.records], "id"),
  159. // ["id"], ["desc"])
  160. );
  161. }
  162. }
  163. }, [])
  164. useEffect(() => {
  165. // if (!isEqual(inventoryLotLinesPagingController, defaultPagingController)) {
  166. refetchInventoryLotLineData(selectedInventory?.itemId ?? null, "paging", inventoryLotLinesPagingController)
  167. // }
  168. }, [inventoryLotLinesPagingController])
  169. // Reset
  170. const onReset = useCallback(() => {
  171. refetchInventoryData(defaultInputs, "reset", defaultPagingController);
  172. refetchInventoryLotLineData(null, "reset", defaultPagingController);
  173. // setFilteredInventories(inventories);
  174. setInputs(() => defaultInputs)
  175. setInventoriesPagingController(() => defaultPagingController)
  176. setInventoryLotLinesPagingController(() => defaultPagingController)
  177. }, []);
  178. // Click Row
  179. const onInventoryRowClick = useCallback((item: InventoryResult) => {
  180. refetchInventoryLotLineData(item.itemId, "search", defaultPagingController)
  181. setSelectedInventory(item)
  182. setInventoryLotLinesPagingController(() => defaultPagingController)
  183. }, [])
  184. // On Search
  185. const onSearch = useCallback((query: Record<SearchParamNames, string>) => {
  186. refetchInventoryData(query, "search", defaultPagingController)
  187. refetchInventoryLotLineData(null, "search", defaultPagingController);
  188. setInputs(() => query)
  189. setInventoriesPagingController(() => defaultPagingController)
  190. setInventoryLotLinesPagingController(() => defaultPagingController)
  191. }, [refetchInventoryData])
  192. console.log("", "color: #666", inventoriesPagingController)
  193. return (
  194. <>
  195. <SearchBox
  196. criteria={searchCriteria}
  197. onSearch={(query) => {
  198. onSearch(query)
  199. // console.log(query)
  200. // console.log(inventories)
  201. // setInputs(() => query)
  202. // refetchInventoryData(query, "search", defaultPagingController)
  203. // setFilteredInventories(
  204. // inventories.filter(
  205. // (i) =>
  206. // i.itemCode.toLowerCase().includes(query.itemCode.toLowerCase()) &&
  207. // i.itemName.toLowerCase().includes(query.itemName.toLowerCase()) &&
  208. // (query.itemType == "All" ||
  209. // i.itemType.toLowerCase().includes(query.itemType.toLowerCase())) &&
  210. // (query.status == "All" ||
  211. // i.status.toLowerCase().includes(query.status.toLowerCase())),
  212. // ),
  213. // );
  214. }}
  215. onReset={onReset}
  216. />
  217. <InventoryTable
  218. inventories={filteredInventories}
  219. pagingController={inventoriesPagingController}
  220. setPagingController={setInventoriesPagingController}
  221. totalCount={inventoriesTotalCount}
  222. onRowClick={onInventoryRowClick}
  223. />
  224. <InventoryLotLineTable
  225. inventoryLotLines={filteredInventoryLotLines}
  226. pagingController={inventoryLotLinesPagingController}
  227. setPagingController={setInventoryLotLinesPagingController}
  228. totalCount={inventoryLotLinesTotalCount}
  229. inventory={selectedInventory}
  230. printerCombo={printerCombo ?? []}
  231. onStockTransferSuccess={() =>
  232. refetchInventoryLotLineData(selectedInventory?.itemId ?? null, "search", inventoryLotLinesPagingController)
  233. }
  234. onStockAdjustmentSuccess={() =>
  235. refetchInventoryLotLineData(selectedInventory?.itemId ?? null, "search", inventoryLotLinesPagingController)
  236. }
  237. />
  238. </>
  239. );
  240. };
  241. export default InventorySearch;