MailSetting.tsx 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. import React, { useCallback, useEffect } from 'react';
  2. import { useTranslation } from 'next-i18next';
  3. import { useForm } from 'react-hook-form';
  4. import AdminAppContainer from '~/client/services/AdminAppContainer';
  5. import { toastSuccess, toastError } from '~/client/util/toastr';
  6. import { withUnstatedContainers } from '../../UnstatedUtils';
  7. import { SesSetting } from './SesSetting';
  8. import { SmtpSetting } from './SmtpSetting';
  9. type Props = {
  10. adminAppContainer: AdminAppContainer,
  11. }
  12. const MailSetting = (props: Props) => {
  13. const { t } = useTranslation(['admin', 'commons']);
  14. const { adminAppContainer } = props;
  15. const transmissionMethods = ['smtp', 'ses'];
  16. const {
  17. register,
  18. handleSubmit,
  19. reset,
  20. watch,
  21. } = useForm();
  22. // Watch the transmission method to dynamically switch between SMTP and SES settings
  23. const currentTransmissionMethod = watch('transmissionMethod', adminAppContainer.state.transmissionMethod || 'smtp');
  24. // Reset form when adminAppContainer state changes
  25. useEffect(() => {
  26. reset({
  27. fromAddress: adminAppContainer.state.fromAddress || '',
  28. transmissionMethod: adminAppContainer.state.transmissionMethod || 'smtp',
  29. smtpHost: adminAppContainer.state.smtpHost || '',
  30. smtpPort: adminAppContainer.state.smtpPort || '',
  31. smtpUser: adminAppContainer.state.smtpUser || '',
  32. smtpPassword: adminAppContainer.state.smtpPassword || '',
  33. sesAccessKeyId: adminAppContainer.state.sesAccessKeyId || '',
  34. sesSecretAccessKey: adminAppContainer.state.sesSecretAccessKey || '',
  35. });
  36. }, [
  37. adminAppContainer.state.fromAddress,
  38. adminAppContainer.state.transmissionMethod,
  39. adminAppContainer.state.smtpHost,
  40. adminAppContainer.state.smtpPort,
  41. adminAppContainer.state.smtpUser,
  42. adminAppContainer.state.smtpPassword,
  43. adminAppContainer.state.sesAccessKeyId,
  44. adminAppContainer.state.sesSecretAccessKey,
  45. reset,
  46. ]);
  47. const onSubmit = useCallback(async(data) => {
  48. try {
  49. // Await all setState completions before API call
  50. await Promise.all([
  51. adminAppContainer.changeFromAddress(data.fromAddress),
  52. adminAppContainer.changeTransmissionMethod(data.transmissionMethod),
  53. adminAppContainer.changeSmtpHost(data.smtpHost),
  54. adminAppContainer.changeSmtpPort(data.smtpPort),
  55. adminAppContainer.changeSmtpUser(data.smtpUser),
  56. adminAppContainer.changeSmtpPassword(data.smtpPassword),
  57. adminAppContainer.changeSesAccessKeyId(data.sesAccessKeyId),
  58. adminAppContainer.changeSesSecretAccessKey(data.sesSecretAccessKey),
  59. ]);
  60. await adminAppContainer.updateMailSettingHandler();
  61. toastSuccess(t('toaster.update_successed', { target: t('admin:app_setting.mail_settings'), ns: 'commons' }));
  62. }
  63. catch (err) {
  64. toastError(err);
  65. }
  66. }, [adminAppContainer, t]);
  67. async function sendTestEmailHandler() {
  68. const { adminAppContainer } = props;
  69. try {
  70. await adminAppContainer.sendTestEmail();
  71. toastSuccess(t('admin:app_setting.success_to_send_test_email'));
  72. }
  73. catch (err) {
  74. toastError(err);
  75. }
  76. }
  77. return (
  78. <form onSubmit={handleSubmit(onSubmit)}>
  79. {!adminAppContainer.state.isMailerSetup && (
  80. <div className="alert alert-danger"><span className="material-symbols-outlined">error</span> {t('admin:app_setting.mailer_is_not_set_up')}</div>
  81. )}
  82. <div className="row mb-4">
  83. <label className="col-md-3 col-form-label text-end">{t('admin:app_setting.from_e-mail_address')}</label>
  84. <div className="col-md-6">
  85. <input
  86. className="form-control"
  87. type="text"
  88. placeholder={`${t('eg')} mail@growi.org`}
  89. {...register('fromAddress')}
  90. />
  91. </div>
  92. </div>
  93. <div className="row mb-2">
  94. <label className="form-label text-start text-md-end col-md-3 col-form-label">
  95. {t('admin:app_setting.transmission_method')}
  96. </label>
  97. <div className="col-md-6 py-2">
  98. {transmissionMethods.map((method) => {
  99. return (
  100. <div key={method} className="form-check form-check-inline">
  101. <input
  102. type="radio"
  103. className="form-check-input"
  104. id={`transmission-method-radio-${method}`}
  105. value={method}
  106. {...register('transmissionMethod')}
  107. />
  108. <label className="form-label form-check-label" htmlFor={`transmission-method-radio-${method}`}>{t(`admin:app_setting.${method}_label`)}</label>
  109. </div>
  110. );
  111. })}
  112. </div>
  113. </div>
  114. {currentTransmissionMethod === 'smtp' && <SmtpSetting register={register} />}
  115. {currentTransmissionMethod === 'ses' && <SesSetting register={register} />}
  116. <div className="row my-3">
  117. <div className="col-md-3"></div>
  118. <div className="col-md-9">
  119. <button type="submit" className="btn btn-primary" disabled={adminAppContainer.state.retrieveError != null}>
  120. { t('Update') }
  121. </button>
  122. {adminAppContainer.state.transmissionMethod === 'smtp' && (
  123. <button type="button" className="btn btn-secondary ms-4" onClick={sendTestEmailHandler}>
  124. {t('admin:app_setting.send_test_email')}
  125. </button>
  126. )}
  127. </div>
  128. </div>
  129. </form>
  130. );
  131. };
  132. /**
  133. * Wrapper component for using unstated
  134. */
  135. const MailSettingWrapper = withUnstatedContainers(MailSetting, [AdminAppContainer]);
  136. export default MailSettingWrapper;