AuditLogManagement.tsx 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. import React, { FC, useState, useCallback } from 'react';
  2. import { format } from 'date-fns';
  3. import { useTranslation } from 'react-i18next';
  4. import {
  5. SupportedActionType, AllSupportedActionType, PageActions, CommentActions,
  6. } from '~/interfaces/activity';
  7. import { useSWRxActivityList } from '~/stores/activity';
  8. import PaginationWrapper from '../PaginationWrapper';
  9. import { ActivityTable } from './AuditLog/ActivityTable';
  10. import { DateRangePicker } from './AuditLog/DateRangePicker';
  11. import { SearchUsernameTypeahead } from './AuditLog/SearchUsernameTypeahead';
  12. import { SelectActionDropdown } from './AuditLog/SelectActionDropdown';
  13. const formatDate = (date: Date | null) => {
  14. if (date == null) {
  15. return '';
  16. }
  17. return format(new Date(date), 'yyyy-MM-dd');
  18. };
  19. const PAGING_LIMIT = 10;
  20. export const AuditLogManagement: FC = () => {
  21. const { t } = useTranslation();
  22. /*
  23. * State
  24. */
  25. const [activePage, setActivePage] = useState<number>(1);
  26. const offset = (activePage - 1) * PAGING_LIMIT;
  27. const [startDate, setStartDate] = useState<Date | null>(null);
  28. const [endDate, setEndDate] = useState<Date | null>(null);
  29. const [selectedUsernames, setSelectedUsernames] = useState<string[]>([]);
  30. const [actionMap, setActionMap] = useState(
  31. new Map<SupportedActionType, boolean>(AllSupportedActionType.map(action => [action, true])),
  32. );
  33. /*
  34. * Fetch
  35. */
  36. const selectedDate = { startDate: formatDate(startDate), endDate: formatDate(endDate) };
  37. const selectedActionList = Array.from(actionMap.entries()).filter(v => v[1]).map(v => v[0]);
  38. const searchFilter = { actions: selectedActionList, dates: selectedDate, usernames: selectedUsernames };
  39. const { data: activityListData, error } = useSWRxActivityList(PAGING_LIMIT, offset, searchFilter);
  40. const activityList = activityListData?.docs != null ? activityListData.docs : [];
  41. const totalActivityNum = activityListData?.totalDocs != null ? activityListData.totalDocs : 0;
  42. const isLoading = activityListData === undefined && error == null;
  43. /*
  44. * Functions
  45. */
  46. const setActivePageHandler = useCallback((selectedPageNum: number) => {
  47. setActivePage(selectedPageNum);
  48. }, []);
  49. const datePickerChangedHandler = useCallback((dateList: Date[] | null[]) => {
  50. setActivePage(1);
  51. setStartDate(dateList[0]);
  52. setEndDate(dateList[1]);
  53. }, []);
  54. const actionCheckboxChangedHandler = useCallback((action: SupportedActionType) => {
  55. setActivePage(1);
  56. actionMap.set(action, !actionMap.get(action));
  57. setActionMap(new Map(actionMap.entries()));
  58. }, [actionMap, setActionMap]);
  59. const multipleActionCheckboxChangedHandler = useCallback((actions: SupportedActionType[], isChecked) => {
  60. setActivePage(1);
  61. actions.forEach(action => actionMap.set(action, isChecked));
  62. setActionMap(new Map(actionMap.entries()));
  63. }, [actionMap, setActionMap]);
  64. const setUsernamesHandler = useCallback((usernames: string[]) => {
  65. setSelectedUsernames(usernames);
  66. }, []);
  67. // eslint-disable-next-line max-len
  68. const activityCounter = `<b>${activityList.length === 0 ? 0 : offset + 1}</b> - <b>${(PAGING_LIMIT * activePage) - (PAGING_LIMIT - activityList.length)}</b> of <b>${totalActivityNum}<b/>`;
  69. return (
  70. <div data-testid="admin-auditlog">
  71. <h2 className="admin-setting-header mb-3">{t('AuditLog')}</h2>
  72. <div className="form-inline mb-3">
  73. <SearchUsernameTypeahead
  74. onChange={setUsernamesHandler}
  75. />
  76. <DateRangePicker
  77. startDate={startDate}
  78. endDate={endDate}
  79. onChangeDatePicker={datePickerChangedHandler}
  80. />
  81. <SelectActionDropdown
  82. dropdownItems={[
  83. { actionCategory: 'Page', actionNames: PageActions },
  84. { actionCategory: 'Comment', actionNames: CommentActions },
  85. ]}
  86. actionMap={actionMap}
  87. onChangeAction={actionCheckboxChangedHandler}
  88. onChangeMultipleAction={multipleActionCheckboxChangedHandler}
  89. />
  90. </div>
  91. { isLoading
  92. ? (
  93. <div className="text-muted text-center mb-5">
  94. <i className="fa fa-2x fa-spinner fa-pulse mr-1"></i>
  95. </div>
  96. )
  97. : (
  98. <>
  99. <p
  100. className="ml-2"
  101. // eslint-disable-next-line react/no-danger
  102. dangerouslySetInnerHTML={{ __html: activityCounter }}
  103. />
  104. <ActivityTable activityList={activityList} />
  105. <PaginationWrapper
  106. activePage={activePage}
  107. changePage={setActivePageHandler}
  108. totalItemsCount={totalActivityNum}
  109. pagingLimit={PAGING_LIMIT}
  110. align="center"
  111. size="sm"
  112. />
  113. </>
  114. )
  115. }
  116. </div>
  117. );
  118. };