CustomizeNoscriptSetting.tsx 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. import { type JSX, useCallback, useEffect } from 'react';
  2. import { useTranslation } from 'next-i18next';
  3. import { useForm } from 'react-hook-form';
  4. import PrismAsyncLight from 'react-syntax-highlighter/dist/esm/prism-async-light';
  5. import oneDark from 'react-syntax-highlighter/dist/esm/styles/prism/one-dark';
  6. import { Card, CardBody } from 'reactstrap';
  7. import AdminCustomizeContainer from '~/client/services/AdminCustomizeContainer';
  8. import { toastError, toastSuccess } from '~/client/util/toastr';
  9. import { withUnstatedContainers } from '../../UnstatedUtils';
  10. import AdminUpdateButtonRow from '../Common/AdminUpdateButtonRow';
  11. type Props = {
  12. adminCustomizeContainer: AdminCustomizeContainer;
  13. };
  14. const CustomizeNoscriptSetting = (props: Props): JSX.Element => {
  15. const { adminCustomizeContainer } = props;
  16. const { t } = useTranslation();
  17. const { register, handleSubmit, reset } = useForm();
  18. // Sync form with container state
  19. useEffect(() => {
  20. reset({
  21. customizeNoscript:
  22. adminCustomizeContainer.state.currentCustomizeNoscript || '',
  23. });
  24. }, [adminCustomizeContainer.state.currentCustomizeNoscript, reset]);
  25. const onSubmit = useCallback(
  26. async (data) => {
  27. try {
  28. // Update container state before API call
  29. await adminCustomizeContainer.changeCustomizeNoscript(
  30. data.customizeNoscript,
  31. );
  32. await adminCustomizeContainer.updateCustomizeNoscript();
  33. toastSuccess(
  34. t('toaster.update_successed', {
  35. target: t('admin:customize_settings.custom_noscript'),
  36. ns: 'commons',
  37. }),
  38. );
  39. } catch (err) {
  40. toastError(err);
  41. }
  42. },
  43. [t, adminCustomizeContainer],
  44. );
  45. return (
  46. <div className="row">
  47. <div className="col-12">
  48. <h2 className="admin-setting-header">
  49. {t('admin:customize_settings.custom_noscript')}
  50. </h2>
  51. <Card className="card custom-card bg-body-tertiary my-3">
  52. <CardBody className="px-0 py-2">
  53. <span
  54. // biome-ignore lint/security/noDangerouslySetInnerHtml: trusted translation markup
  55. dangerouslySetInnerHTML={{
  56. __html: t('admin:customize_settings.custom_noscript_detail'),
  57. }}
  58. />
  59. </CardBody>
  60. </Card>
  61. <form onSubmit={handleSubmit(onSubmit)}>
  62. <div>
  63. <textarea
  64. className="form-control mb-2"
  65. rows={8}
  66. {...register('customizeNoscript')}
  67. />
  68. </div>
  69. <button
  70. type="button"
  71. className="btn btn-link text-muted p-0"
  72. data-bs-toggle="collapse"
  73. data-bs-target="#collapseExampleHtml"
  74. aria-expanded="false"
  75. aria-controls="collapseExampleHtml"
  76. >
  77. <span className="material-symbols-outlined me-1" aria-hidden="true">
  78. navigate_next
  79. </span>
  80. Example for Google Tag Manager
  81. </button>
  82. <div className="collapse" id="collapseExampleHtml">
  83. <PrismAsyncLight style={oneDark} language="javascript">
  84. {`<iframe src="https://www.googletagmanager.com/ns.html?id=GTM-XXXXXXX"
  85. height="0"
  86. width="0"
  87. style="display:none;visibility:hidden"></iframe>`}
  88. </PrismAsyncLight>
  89. </div>
  90. <AdminUpdateButtonRow
  91. type="submit"
  92. disabled={adminCustomizeContainer.state.retrieveError != null}
  93. />
  94. </form>
  95. </div>
  96. </div>
  97. );
  98. };
  99. const CustomizeNoscriptSettingWrapper = withUnstatedContainers(
  100. CustomizeNoscriptSetting,
  101. [AdminCustomizeContainer],
  102. );
  103. export default CustomizeNoscriptSettingWrapper;