RecentActivity.tsx 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. import React, {
  2. useState, useCallback, useEffect, type JSX,
  3. } from 'react';
  4. import { toastError } from '~/client/util/toastr';
  5. import type { IActivityHasId, ActivityHasTargetPage } from '~/interfaces/activity';
  6. import { useSWRxRecentActivity } from '~/stores/recent-activity';
  7. import loggerFactory from '~/utils/logger';
  8. import PaginationWrapper from '../PaginationWrapper';
  9. import { ActivityListItem } from './ActivityListItem';
  10. const logger = loggerFactory('growi:RecentActivity');
  11. type RecentActivityProps = {
  12. userId: string,
  13. }
  14. const hasTargetPage = (activity: IActivityHasId): activity is ActivityHasTargetPage => {
  15. return activity.user != null
  16. && typeof activity.user === 'object'
  17. && activity.target != null
  18. && typeof activity.target === 'object';
  19. };
  20. export const RecentActivity = (props: RecentActivityProps): JSX.Element => {
  21. const { userId } = props;
  22. const [activities, setActivities] = useState<ActivityHasTargetPage[]>([]);
  23. const [activePage, setActivePage] = useState(1);
  24. const [limit] = useState(10);
  25. const [offset, setOffset] = useState(0);
  26. const { data: paginatedData, error } = useSWRxRecentActivity(limit, offset, userId);
  27. const handlePage = useCallback(async(selectedPage: number) => {
  28. const newOffset = (selectedPage - 1) * limit;
  29. setOffset(newOffset);
  30. setActivePage(selectedPage);
  31. }, [limit]);
  32. useEffect(() => {
  33. if (error) {
  34. logger.error('Failed to fetch recent activity data', error);
  35. toastError(error);
  36. return;
  37. }
  38. if (paginatedData) {
  39. const activitiesWithPages = paginatedData.docs
  40. .filter(hasTargetPage);
  41. setActivities(activitiesWithPages);
  42. }
  43. }, [paginatedData, error]);
  44. const totalItemsCount = paginatedData?.totalDocs || 0;
  45. const needsPagination = totalItemsCount > limit;
  46. return (
  47. <div className="page-list-container-activity">
  48. <ul className="page-list-ul page-list-ul-flat mb-3">
  49. {activities.map(activity => (
  50. <li key={`recent-activity-view:${activity._id}`} className="mt-4">
  51. <ActivityListItem props={{ activity }} />
  52. </li>
  53. ))}
  54. </ul>
  55. {needsPagination && (
  56. <PaginationWrapper
  57. activePage={activePage}
  58. changePage={handlePage}
  59. totalItemsCount={totalItemsCount}
  60. pagingLimit={limit}
  61. align="center"
  62. size="sm"
  63. />
  64. )}
  65. </div>
  66. );
  67. };