SyncExecution.tsx 3.6 KB

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