SyncExecution.tsx 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. import {
  2. FC, useCallback, useEffect, useState,
  3. } from 'react';
  4. import { useTranslation } from 'react-i18next';
  5. import { toastError, toastSuccess } from '~/client/util/toastr';
  6. import LabeledProgressBar from '~/components/Admin/Common/LabeledProgressBar';
  7. import { SocketEventName } from '~/interfaces/websocket';
  8. import { useAdminSocket } from '~/stores/socket-io';
  9. import { useSWRxExternalUserGroupList } from '../../stores/external-user-group';
  10. type SyncExecutionProps = {
  11. requestSyncAPI: (e) => Promise<void>
  12. AdditionalForm?: FC
  13. }
  14. export const SyncExecution = ({
  15. requestSyncAPI,
  16. AdditionalForm = () => <></>,
  17. }: SyncExecutionProps): JSX.Element => {
  18. const { t } = useTranslation('admin');
  19. const { data: socket } = useAdminSocket();
  20. const { mutate: mutateExternalUserGroups } = useSWRxExternalUserGroupList();
  21. const [syncStatus, setSyncStatus] = useState<'beforeSync' | 'syncExecuting' | 'syncCompleted' | 'syncFailed'>('beforeSync');
  22. const [progress, setProgress] = useState({
  23. total: 0,
  24. current: 0,
  25. });
  26. useEffect(() => {
  27. if (socket != null) {
  28. socket.off(SocketEventName.GroupSyncProgress);
  29. socket.on(SocketEventName.GroupSyncProgress, (data) => {
  30. setSyncStatus('syncExecuting');
  31. setProgress({
  32. total: data.totalCount,
  33. current: data.count,
  34. });
  35. });
  36. socket.off(SocketEventName.GroupSyncCompleted);
  37. socket.on(SocketEventName.GroupSyncCompleted, () => {
  38. setSyncStatus('syncCompleted');
  39. mutateExternalUserGroups();
  40. toastSuccess(t('external_user_group.sync_succeeded'));
  41. });
  42. socket.off(SocketEventName.GroupSyncFailed);
  43. socket.on(SocketEventName.GroupSyncFailed, () => {
  44. setSyncStatus('syncFailed');
  45. mutateExternalUserGroups();
  46. toastError(t('external_user_group.sync_failed'));
  47. });
  48. }
  49. }, [socket, mutateExternalUserGroups, t]);
  50. const onSyncBtnClick = useCallback(async(e) => {
  51. e.preventDefault();
  52. try {
  53. await requestSyncAPI(e);
  54. setProgress({ total: 0, current: 0 });
  55. setSyncStatus('syncExecuting');
  56. }
  57. catch (errs) {
  58. toastError(t(errs[0]?.code));
  59. }
  60. }, [t, requestSyncAPI]);
  61. const renderProgressBar = () => {
  62. if (syncStatus === 'beforeSync') return null;
  63. let header;
  64. if (syncStatus === 'syncExecuting') {
  65. header = 'Processing..';
  66. }
  67. else if (syncStatus === 'syncCompleted') {
  68. header = 'Completed';
  69. }
  70. else {
  71. header = 'Failed';
  72. }
  73. return (
  74. <LabeledProgressBar
  75. header={header}
  76. currentCount={progress.current}
  77. totalCount={progress.total}
  78. />
  79. );
  80. };
  81. return (
  82. <>
  83. <h3 className="border-bottom mb-3">{t('external_user_group.execute_sync')}</h3>
  84. <div className="row">
  85. <div className="col-md-3"></div>
  86. <div className="col-md-9">
  87. {renderProgressBar()}
  88. </div>
  89. </div>
  90. <form onSubmit={onSyncBtnClick}>
  91. <AdditionalForm />
  92. <div className="row">
  93. <div className="col-md-3"></div>
  94. <div className="col-md-6"><button className="btn btn-primary" type="submit">{t('external_user_group.sync')}</button></div>
  95. </div>
  96. </form>
  97. </>
  98. );
  99. };