CustomizeScriptSetting.tsx 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. import React, { 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';
  5. import { oneDark } from 'react-syntax-highlighter/dist/cjs/styles/prism';
  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 CustomizeScriptSetting = (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. customizeScript:
  22. adminCustomizeContainer.state.currentCustomizeScript || '',
  23. });
  24. }, [adminCustomizeContainer.state.currentCustomizeScript, reset]);
  25. const onSubmit = useCallback(
  26. async (data) => {
  27. try {
  28. // Update container state before API call
  29. await adminCustomizeContainer.changeCustomizeScript(
  30. data.customizeScript,
  31. );
  32. await adminCustomizeContainer.updateCustomizeScript();
  33. toastSuccess(
  34. t('toaster.update_successed', {
  35. target: t('admin:customize_settings.custom_script'),
  36. ns: 'commons',
  37. }),
  38. );
  39. } catch (err) {
  40. toastError(err);
  41. }
  42. },
  43. [t, adminCustomizeContainer],
  44. );
  45. return (
  46. <React.Fragment>
  47. <div className="row">
  48. <div className="col-12">
  49. <h2 className="admin-setting-header">
  50. {t('admin:customize_settings.custom_script')}
  51. </h2>
  52. <Card className="card custom-card bg-body-tertiary mb-3">
  53. <CardBody className="px-0 py-2">
  54. {t('admin:customize_settings.write_java')}
  55. <br />
  56. {t('admin:customize_settings.reflect_change')}
  57. </CardBody>
  58. </Card>
  59. <form onSubmit={handleSubmit(onSubmit)}>
  60. <div>
  61. <textarea
  62. className="form-control mb-2"
  63. rows={8}
  64. {...register('customizeScript')}
  65. />
  66. </div>
  67. <button
  68. type="button"
  69. className="btn btn-link text-muted p-0"
  70. data-bs-toggle="collapse"
  71. data-bs-target="#collapseExampleScript"
  72. aria-expanded="false"
  73. aria-controls="collapseExampleScript"
  74. >
  75. <span
  76. className="material-symbols-outlined me-1"
  77. aria-hidden="true"
  78. >
  79. navigate_next
  80. </span>
  81. Example for Google Tag Manager
  82. </button>
  83. <div className="collapse" id="collapseExampleScript">
  84. <PrismAsyncLight style={oneDark} language="javascript">
  85. {`(function(w,d,s,l,i){
  86. w[l]=w[l]||[];
  87. w[l].push({'gtm.start':new Date().getTime(),event:'gtm.js'});
  88. var f=d.getElementsByTagName(s)[0],
  89. j=d.createElement(s),
  90. dl=l!='dataLayer'?'&l='+l:'';
  91. j.async=true;
  92. j.src='https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
  93. })(window,document,'script','dataLayer','GTM-XXXXXX');`}
  94. </PrismAsyncLight>
  95. </div>
  96. <AdminUpdateButtonRow
  97. type="submit"
  98. disabled={adminCustomizeContainer.state.retrieveError != null}
  99. />
  100. </form>
  101. </div>
  102. </div>
  103. </React.Fragment>
  104. );
  105. };
  106. const CustomizeScriptSettingWrapper = withUnstatedContainers(
  107. CustomizeScriptSetting,
  108. [AdminCustomizeContainer],
  109. );
  110. export default CustomizeScriptSettingWrapper;