InAppNotificationPage.tsx 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. import type { FC } from 'react';
  2. import React, { useState, useEffect, useCallback } from 'react';
  3. import { useTranslation } from 'next-i18next';
  4. import { apiv3Put, apiv3Post } from '~/client/util/apiv3-client';
  5. import { InAppNotificationStatuses } from '~/interfaces/in-app-notification';
  6. import { useShowPageLimitationXL } from '~/stores/context';
  7. import loggerFactory from '~/utils/logger';
  8. import { useSWRxInAppNotifications, useSWRxInAppNotificationStatus } from '../../stores/in-app-notification';
  9. import CustomNavAndContents from '../CustomNavigation/CustomNavAndContents';
  10. import { LoadingSpinnerPulse } from '../LoadingSpinnerPulse';
  11. import PaginationWrapper from '../PaginationWrapper';
  12. import InAppNotificationList from './InAppNotificationList';
  13. const logger = loggerFactory('growi:InAppNotificationPage');
  14. export const InAppNotificationPage: FC = () => {
  15. const { t } = useTranslation('commons');
  16. const { mutate } = useSWRxInAppNotificationStatus();
  17. const { data: showPageLimitationXL } = useShowPageLimitationXL();
  18. const limit = showPageLimitationXL != null ? showPageLimitationXL : 20;
  19. const updateNotificationStatus = useCallback(async() => {
  20. try {
  21. await apiv3Post('/in-app-notification/read');
  22. mutate();
  23. }
  24. catch (err) {
  25. logger.error(err);
  26. }
  27. }, [mutate]);
  28. useEffect(() => {
  29. updateNotificationStatus();
  30. }, [updateNotificationStatus]);
  31. const InAppNotificationCategoryByStatus = (status?: InAppNotificationStatuses) => {
  32. const [activePage, setActivePage] = useState(1);
  33. const offset = (activePage - 1) * limit;
  34. let categoryStatus;
  35. switch (status) {
  36. case InAppNotificationStatuses.STATUS_UNOPENED:
  37. categoryStatus = InAppNotificationStatuses.STATUS_UNOPENED;
  38. break;
  39. default:
  40. }
  41. const { data: notificationData, mutate: mutateNotificationData } = useSWRxInAppNotifications(limit, offset, categoryStatus);
  42. const { mutate: mutateAllNotificationData } = useSWRxInAppNotifications(limit, offset, undefined);
  43. const setAllNotificationPageNumber = (selectedPageNumber): void => {
  44. setActivePage(selectedPageNumber);
  45. };
  46. if (notificationData == null) {
  47. return (
  48. <div className="wiki" data-testid="grw-in-app-notification-page-spinner">
  49. <div className="text-muted text-center">
  50. <span className="me-1"><LoadingSpinnerPulse /></span>
  51. </div>
  52. </div>
  53. );
  54. }
  55. const updateUnopendNotificationStatusesToOpened = async() => {
  56. await apiv3Put('/in-app-notification/all-statuses-open');
  57. // mutate notification statuses in 'UNREAD' Category
  58. mutateNotificationData();
  59. // mutate notification statuses in 'ALL' Category
  60. mutateAllNotificationData();
  61. };
  62. return (
  63. <>
  64. {(status === InAppNotificationStatuses.STATUS_UNOPENED && notificationData.totalDocs > 0)
  65. && (
  66. <div className="mb-2 d-flex justify-content-end">
  67. <button
  68. type="button"
  69. className="btn btn-outline-primary"
  70. onClick={updateUnopendNotificationStatusesToOpened}
  71. >
  72. {t('in_app_notification.mark_all_as_read')}
  73. </button>
  74. </div>
  75. )}
  76. { notificationData != null && notificationData.docs.length === 0
  77. // no items
  78. ? t('in_app_notification.mark_all_as_read')
  79. // render list-group
  80. : (
  81. <InAppNotificationList inAppNotificationData={notificationData} />
  82. )
  83. }
  84. {notificationData.totalDocs > 0 && (
  85. <div className="mt-4">
  86. <PaginationWrapper
  87. activePage={activePage}
  88. changePage={setAllNotificationPageNumber}
  89. totalItemsCount={notificationData.totalDocs}
  90. pagingLimit={notificationData.limit}
  91. align="center"
  92. size="sm"
  93. />
  94. </div>
  95. ) }
  96. </>
  97. );
  98. };
  99. const navTabMapping = {
  100. user_infomation: {
  101. Icon: () => <></>,
  102. Content: () => InAppNotificationCategoryByStatus(),
  103. i18n: t('in_app_notification.all'),
  104. },
  105. external_accounts: {
  106. Icon: () => <></>,
  107. Content: () => InAppNotificationCategoryByStatus(InAppNotificationStatuses.STATUS_UNOPENED),
  108. i18n: t('in_app_notification.unopend'),
  109. },
  110. };
  111. return (
  112. <div data-testid="grw-in-app-notification-page">
  113. <CustomNavAndContents navTabMapping={navTabMapping} tabContentClasses={['mt-4']} />
  114. </div>
  115. );
  116. };
  117. InAppNotificationPage.displayName = 'InAppNotificationPage';