FPSMS-frontend
No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.
 
 

158 líneas
4.6 KiB

  1. "use client";
  2. import SearchBox, { Criterion } from "../SearchBox";
  3. import { useCallback, useMemo, useState } from "react";
  4. import { useTranslation } from "react-i18next";
  5. import SearchResults, { Column } from "../SearchResults/index";
  6. import EditNote from "@mui/icons-material/EditNote";
  7. import DeleteIcon from "@mui/icons-material/Delete";
  8. import { useRouter } from "next/navigation";
  9. import { deleteDialog, successDialog } from "../Swal/CustomAlerts";
  10. import useUploadContext from "../UploadProvider/useUploadContext";
  11. import { downloadFile } from "@/app/utils/commonUtil";
  12. import { UserResult } from "@/app/api/user";
  13. import { deleteUser } from "@/app/api/user/actions";
  14. import QrCodeIcon from "@mui/icons-material/QrCode";
  15. import UserSearchLoading from "./UserSearchLoading";
  16. import { searchUsersByUsernameOrName } from "@/app/api/user/client";
  17. interface Props {
  18. users: UserResult[];
  19. }
  20. type SearchQuery = Partial<Omit<UserResult, "id">>;
  21. type SearchParamNames = keyof SearchQuery;
  22. const UserSearch: React.FC<Props> = ({ users }) => {
  23. const { t } = useTranslation("user");
  24. const [filteredUser, setFilteredUser] = useState(users);
  25. const [pagingController, setPagingController] = useState({
  26. pageNum: 1,
  27. pageSize: 10,
  28. });
  29. const router = useRouter();
  30. const { setIsUploading } = useUploadContext();
  31. const [isSearching, setIsSearching] = useState(false);
  32. const searchCriteria: Criterion<SearchParamNames>[] = useMemo(
  33. () => [
  34. {
  35. label: "用戶/姓名",
  36. paramName: "username",
  37. type: "text",
  38. },
  39. {
  40. label: t("staffNo"),
  41. paramName: "staffNo",
  42. type: "text",
  43. },
  44. ],
  45. [t],
  46. );
  47. const onUserClick = useCallback(
  48. (users: UserResult) => {
  49. console.log(users);
  50. router.push(`/settings/user/edit?id=${users.id}`);
  51. },
  52. [router, t],
  53. );
  54. const onDeleteClick = useCallback((users: UserResult) => {
  55. deleteDialog(async () => {
  56. await deleteUser(users.id);
  57. successDialog(t("Delete Success"), t);
  58. }, t);
  59. }, [t]);
  60. const columns = useMemo<Column<UserResult>[]>(
  61. () => [
  62. {
  63. name: "action",
  64. label: t("Edit"),
  65. onClick: onUserClick,
  66. buttonIcon: <EditNote />,
  67. sx: { width: "10%", minWidth: "80px" },
  68. },
  69. {
  70. name: "username",
  71. label: t("Username"),
  72. align: "left",
  73. headerAlign: "left",
  74. sx: { width: "22.5%", minWidth: "120px" },
  75. },
  76. {
  77. name: "name",
  78. label: t("name"),
  79. align: "left",
  80. headerAlign: "left",
  81. sx: { width: "22.5%", minWidth: "120px" },
  82. },
  83. {
  84. name: "staffNo",
  85. label: t("staffNo"),
  86. align: "left",
  87. headerAlign: "left",
  88. sx: { width: "22.5%", minWidth: "120px" },
  89. },
  90. {
  91. name: "action",
  92. label: t("Delete"),
  93. onClick: onDeleteClick,
  94. buttonIcon: <DeleteIcon />,
  95. color: "error",
  96. sx: { width: "10%", minWidth: "80px" },
  97. },
  98. ],
  99. [t, onUserClick, onDeleteClick],
  100. );
  101. return (
  102. <>
  103. <SearchBox
  104. criteria={searchCriteria}
  105. onSearch={async (query) => {
  106. setIsSearching(true);
  107. try {
  108. let results: UserResult[] = [];
  109. if (query.username && query.username.trim()) {
  110. results = await searchUsersByUsernameOrName(query.username);
  111. } else {
  112. results = users;
  113. }
  114. if (query.staffNo && query.staffNo.trim()) {
  115. results = results.filter((user) =>
  116. user.staffNo?.toString().includes(query.staffNo?.toString() || "")
  117. );
  118. }
  119. setFilteredUser(results);
  120. setPagingController({ pageNum: 1, pageSize: pagingController.pageSize });
  121. } catch (error) {
  122. console.error("Error searching users:", error);
  123. setFilteredUser(
  124. users.filter((user) => {
  125. const userMatch = !query.username ||
  126. user.username?.toLowerCase().includes(query.username?.toLowerCase() || "") ||
  127. user.name?.toLowerCase().includes(query.username?.toLowerCase() || "");
  128. const staffNoMatch = !query.staffNo ||
  129. user.staffNo?.toString().includes(query.staffNo?.toString() || "");
  130. return userMatch && staffNoMatch;
  131. })
  132. );
  133. } finally {
  134. setIsSearching(false);
  135. }
  136. }}
  137. />
  138. <SearchResults<UserResult>
  139. items={filteredUser}
  140. columns={columns}
  141. pagingController={pagingController}
  142. setPagingController={setPagingController}
  143. />
  144. </>
  145. );
  146. };
  147. export default UserSearch;