TableWrapper.tsx 3.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. import { IconHelp, IconSearch } from "@tabler/icons-react";
  2. import { useState } from "react";
  3. import Alert from "react-bootstrap/Alert";
  4. import { deleteAccessList } from "src/api/backend";
  5. import { Button, LoadingPage } from "src/components";
  6. import { useAccessLists } from "src/hooks";
  7. import { T } from "src/locale";
  8. import { showAccessListModal, showDeleteConfirmModal, showHelpModal } from "src/modals";
  9. import { showObjectSuccess } from "src/notifications";
  10. import Table from "./Table";
  11. export default function TableWrapper() {
  12. const [search, setSearch] = useState("");
  13. const { isFetching, isLoading, isError, error, data } = useAccessLists(["owner", "items", "clients"]);
  14. if (isLoading) {
  15. return <LoadingPage />;
  16. }
  17. if (isError) {
  18. return <Alert variant="danger">{error?.message || "Unknown error"}</Alert>;
  19. }
  20. const handleDelete = async (id: number) => {
  21. await deleteAccessList(id);
  22. showObjectSuccess("access-list", "deleted");
  23. };
  24. let filtered = null;
  25. if (search && data) {
  26. filtered = data?.filter((item) => {
  27. return item.name.toLowerCase().includes(search);
  28. });
  29. } else if (search !== "") {
  30. // this can happen if someone deletes the last item while searching
  31. setSearch("");
  32. }
  33. return (
  34. <div className="card mt-4">
  35. <div className="card-status-top bg-cyan" />
  36. <div className="card-table">
  37. <div className="card-header">
  38. <div className="row w-full">
  39. <div className="col">
  40. <h2 className="mt-1 mb-0">
  41. <T id="access-lists" />
  42. </h2>
  43. </div>
  44. <div className="col-md-auto col-sm-12">
  45. <div className="ms-auto d-flex flex-wrap btn-list">
  46. {data?.length ? (
  47. <div className="input-group input-group-flat w-auto">
  48. <span className="input-group-text input-group-text-sm">
  49. <IconSearch size={16} />
  50. </span>
  51. <input
  52. id="advanced-table-search"
  53. type="text"
  54. className="form-control form-control-sm"
  55. autoComplete="off"
  56. onChange={(e: any) => setSearch(e.target.value.toLowerCase().trim())}
  57. />
  58. </div>
  59. ) : null}
  60. <Button size="sm" onClick={() => showHelpModal("AccessLists", "cyan")}>
  61. <IconHelp size={20} />
  62. </Button>
  63. {data?.length ? (
  64. <Button size="sm" className="btn-cyan" onClick={() => showAccessListModal("new")}>
  65. <T id="object.add" tData={{ object: "access-list" }} />
  66. </Button>
  67. ) : null}
  68. </div>
  69. </div>
  70. </div>
  71. </div>
  72. <Table
  73. data={filtered ?? data ?? []}
  74. isFetching={isFetching}
  75. isFiltered={!!filtered}
  76. onEdit={(id: number) => showAccessListModal(id)}
  77. onDelete={(id: number) =>
  78. showDeleteConfirmModal({
  79. title: <T id="object.delete" tData={{ object: "access-list" }} />,
  80. onConfirm: () => handleDelete(id),
  81. invalidations: [["access-lists"], ["access-list", id]],
  82. children: <T id="object.delete.content" tData={{ object: "access-list" }} />,
  83. })
  84. }
  85. onNew={() => showAccessListModal("new")}
  86. />
  87. </div>
  88. </div>
  89. );
  90. }