TableWrapper.tsx 3.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. import { IconSearch } from "@tabler/icons-react";
  2. import { useState } from "react";
  3. import Alert from "react-bootstrap/Alert";
  4. import { deleteUser } from "src/api/backend";
  5. import { Button, LoadingPage } from "src/components";
  6. import { useUser, useUsers } from "src/hooks";
  7. import { intl } from "src/locale";
  8. import { DeleteConfirmModal, PermissionsModal, SetPasswordModal, UserModal } from "src/modals";
  9. import { showSuccess } from "src/notifications";
  10. import Table from "./Table";
  11. export default function TableWrapper() {
  12. const [editUserId, setEditUserId] = useState(0 as number | "new");
  13. const [editUserPermissionsId, setEditUserPermissionsId] = useState(0);
  14. const [editUserPasswordId, setEditUserPasswordId] = useState(0);
  15. const [deleteUserId, setDeleteUserId] = useState(0);
  16. const { isFetching, isLoading, isError, error, data } = useUsers(["permissions"]);
  17. const { data: currentUser } = useUser("me");
  18. if (isLoading) {
  19. return <LoadingPage />;
  20. }
  21. if (isError) {
  22. return <Alert variant="danger">{error?.message || "Unknown error"}</Alert>;
  23. }
  24. const handleDelete = async () => {
  25. await deleteUser(deleteUserId);
  26. showSuccess(intl.formatMessage({ id: "notification.user-deleted" }));
  27. };
  28. return (
  29. <div className="card mt-4">
  30. <div className="card-status-top bg-orange" />
  31. <div className="card-table">
  32. <div className="card-header">
  33. <div className="row w-full">
  34. <div className="col">
  35. <h2 className="mt-1 mb-0">{intl.formatMessage({ id: "users.title" })}</h2>
  36. </div>
  37. <div className="col-md-auto col-sm-12">
  38. <div className="ms-auto d-flex flex-wrap btn-list">
  39. <div className="input-group input-group-flat w-auto">
  40. <span className="input-group-text input-group-text-sm">
  41. <IconSearch size={16} />
  42. </span>
  43. <input
  44. id="advanced-table-search"
  45. type="text"
  46. className="form-control form-control-sm"
  47. autoComplete="off"
  48. />
  49. </div>
  50. <Button size="sm" className="btn-orange" onClick={() => setEditUserId("new")}>
  51. {intl.formatMessage({ id: "users.add" })}
  52. </Button>
  53. </div>
  54. </div>
  55. </div>
  56. </div>
  57. <Table
  58. data={data ?? []}
  59. isFetching={isFetching}
  60. currentUserId={currentUser?.id}
  61. onEditUser={(id: number) => setEditUserId(id)}
  62. onEditPermissions={(id: number) => setEditUserPermissionsId(id)}
  63. onSetPassword={(id: number) => setEditUserPasswordId(id)}
  64. onDeleteUser={(id: number) => setDeleteUserId(id)}
  65. onNewUser={() => setEditUserId("new")}
  66. />
  67. {editUserId ? <UserModal userId={editUserId} onClose={() => setEditUserId(0)} /> : null}
  68. {editUserPermissionsId ? (
  69. <PermissionsModal userId={editUserPermissionsId} onClose={() => setEditUserPermissionsId(0)} />
  70. ) : null}
  71. {deleteUserId ? (
  72. <DeleteConfirmModal
  73. title={intl.formatMessage({ id: "user.delete.title" })}
  74. onConfirm={handleDelete}
  75. onClose={() => setDeleteUserId(0)}
  76. invalidations={[["users"], ["user", deleteUserId]]}
  77. >
  78. {intl.formatMessage({ id: "user.delete.content" })}
  79. </DeleteConfirmModal>
  80. ) : null}
  81. {editUserPasswordId ? (
  82. <SetPasswordModal userId={editUserPasswordId} onClose={() => setEditUserPasswordId(0)} />
  83. ) : null}
  84. </div>
  85. </div>
  86. );
  87. }