Просмотр исходного кода

declear usePersonalSettingsInfo and use the data

kaori 3 лет назад
Родитель
Сommit
1e8824bbf6

+ 19 - 18
packages/app/src/client/services/PersonalContainer.js

@@ -65,47 +65,48 @@ export default class PersonalContainer extends Container {
     }
   }
 
+
   /**
    * Change name
    */
-  changeName(inputValue) {
-    this.setState({ name: inputValue });
-  }
+  // changeName(inputValue) {
+  //   this.setState({ name: inputValue });
+  // }
 
   /**
    * Change email
    */
-  changeEmail(inputValue) {
-    this.setState({ email: inputValue });
-  }
+  // changeEmail(inputValue) {
+  //   this.setState({ email: inputValue });
+  // }
 
   /**
    * Change Slack Member ID
    */
-  changeSlackMemberId(inputValue) {
-    this.setState({ slackMemberId: inputValue });
-  }
+  // changeSlackMemberId(inputValue) {
+  //   this.setState({ slackMemberId: inputValue });
+  // }
 
   /**
    * Change isEmailPublished
    */
-  changeIsEmailPublished(boolean) {
-    this.setState({ isEmailPublished: boolean });
-  }
+  // changeIsEmailPublished(boolean) {
+  //   this.setState({ isEmailPublished: boolean });
+  // }
 
   /**
    * Change lang
    */
-  changeLang(lang) {
-    this.setState({ lang });
-  }
+  // changeLang(lang) {
+  //   this.setState({ lang });
+  // }
 
   /**
    * Change isGravatarEnabled
    */
-  changeIsGravatarEnabled(boolean) {
-    this.setState({ isGravatarEnabled: boolean });
-  }
+  // changeIsGravatarEnabled(boolean) {
+  //   this.setState({ isGravatarEnabled: boolean });
+  // }
 
   /**
    * Update basic info

+ 3 - 6
packages/app/src/components/Me/ApiSettings.jsx

@@ -1,10 +1,8 @@
-
 import React from 'react';
 
 import PropTypes from 'prop-types';
 import { useTranslation } from 'react-i18next';
 
-import AppContainer from '~/client/services/AppContainer';
 import PersonalContainer from '~/client/services/PersonalContainer';
 import { toastSuccess, toastError } from '~/client/util/apiNotification';
 import { apiv3Put } from '~/client/util/apiv3-client';
@@ -14,14 +12,14 @@ import { withUnstatedContainers } from '../UnstatedUtils';
 
 class ApiSettings extends React.Component {
 
-  constructor(appContainer) {
+  constructor() {
     super();
 
     this.onClickSubmit = this.onClickSubmit.bind(this);
   }
 
   async onClickSubmit() {
-    const { t, appContainer, personalContainer } = this.props;
+    const { t, personalContainer } = this.props;
 
     try {
       await apiv3Put('/personal-setting/api-token');
@@ -99,7 +97,6 @@ class ApiSettings extends React.Component {
 
 ApiSettings.propTypes = {
   t: PropTypes.func.isRequired, // i18next
-  appContainer: PropTypes.instanceOf(AppContainer).isRequired,
   personalContainer: PropTypes.instanceOf(PersonalContainer).isRequired,
 };
 
@@ -111,6 +108,6 @@ const ApiSettingsWrapperFC = (props) => {
 /**
  * Wrapper component for using unstated
  */
-const ApiSettingsWrapper = withUnstatedContainers(ApiSettingsWrapperFC, [AppContainer, PersonalContainer]);
+const ApiSettingsWrapper = withUnstatedContainers(ApiSettingsWrapperFC, [PersonalContainer]);
 
 export default ApiSettingsWrapper;

+ 48 - 32
packages/app/src/components/Me/BasicInfoSettings.jsx

@@ -1,12 +1,13 @@
-
-import React, { Fragment } from 'react';
+import React, { useEffect } from 'react';
 
 import PropTypes from 'prop-types';
 import { useTranslation } from 'react-i18next';
 
+import AppContainer from '~/client/services/AppContainer';
 import PersonalContainer from '~/client/services/PersonalContainer';
 import { toastSuccess, toastError } from '~/client/util/apiNotification';
 import { localeMetadatas } from '~/client/util/i18n';
+import { usePersonalSettingsInfo } from '~/stores/personal-settings';
 
 import { withUnstatedContainers } from '../UnstatedUtils';
 
@@ -15,19 +16,9 @@ class BasicInfoSettings extends React.Component {
 
   constructor() {
     super();
-
     this.onClickSubmit = this.onClickSubmit.bind(this);
   }
 
-  async componentDidMount() {
-    try {
-      await this.props.personalContainer.retrievePersonalData();
-    }
-    catch (err) {
-      toastError(err);
-    }
-  }
-
   async onClickSubmit() {
     const { t, personalContainer } = this.props;
 
@@ -41,11 +32,14 @@ class BasicInfoSettings extends React.Component {
   }
 
   render() {
-    const { t, personalContainer } = this.props;
-    const { registrationWhiteList } = personalContainer.state;
+    const {
+      t, appContainer, personalSettingsInfo, mutatePersonalSettingsInfo, error,
+    } = this.props;
+    const { registrationWhiteList } = appContainer.getConfig();
+
 
     return (
-      <Fragment>
+      <>
 
         <div className="form-group row">
           <label htmlFor="userForm[name]" className="text-left text-md-right col-md-3 col-form-label">{t('Name')}</label>
@@ -54,8 +48,8 @@ class BasicInfoSettings extends React.Component {
               className="form-control"
               type="text"
               name="userForm[name]"
-              defaultValue={personalContainer.state.name}
-              onChange={(e) => { personalContainer.changeName(e.target.value) }}
+              defaultValue={personalSettingsInfo.name}
+              onChange={(e) => { mutatePersonalSettingsInfo({ ...personalSettingsInfo, name: e.target.value }) }}
             />
           </div>
         </div>
@@ -67,8 +61,8 @@ class BasicInfoSettings extends React.Component {
               className="form-control"
               type="text"
               name="userForm[email]"
-              defaultValue={personalContainer.state.email}
-              onChange={(e) => { personalContainer.changeEmail(e.target.value) }}
+              defaultValue={personalSettingsInfo.email}
+              onChange={(e) => { mutatePersonalSettingsInfo({ ...personalSettingsInfo, email: e.target.value }) }}
             />
             {registrationWhiteList.length !== 0 && (
               <div className="form-text text-muted">
@@ -90,8 +84,8 @@ class BasicInfoSettings extends React.Component {
                 id="radioEmailShow"
                 className="custom-control-input"
                 name="userForm[isEmailPublished]"
-                checked={personalContainer.state.isEmailPublished}
-                onChange={() => { personalContainer.changeIsEmailPublished(true) }}
+                checked={personalSettingsInfo.isEmailPublished}
+                onChange={() => mutatePersonalSettingsInfo({ ...personalSettingsInfo, isEmailPublished: true })}
               />
               <label className="custom-control-label" htmlFor="radioEmailShow">{t('Show')}</label>
             </div>
@@ -101,8 +95,8 @@ class BasicInfoSettings extends React.Component {
                 id="radioEmailHide"
                 className="custom-control-input"
                 name="userForm[isEmailPublished]"
-                checked={!personalContainer.state.isEmailPublished}
-                onChange={() => { personalContainer.changeIsEmailPublished(false) }}
+                checked={!personalSettingsInfo.isEmailPublished}
+                onChange={() => mutatePersonalSettingsInfo({ ...personalSettingsInfo, isEmailPublished: false })}
               />
               <label className="custom-control-label" htmlFor="radioEmailHide">{t('Hide')}</label>
             </div>
@@ -120,8 +114,8 @@ class BasicInfoSettings extends React.Component {
                     id={`radioLang${meta.id}`}
                     className="custom-control-input"
                     name="userForm[lang]"
-                    checked={personalContainer.state.lang === meta.id}
-                    onChange={() => { personalContainer.changeLang(meta.id) }}
+                    checked={personalSettingsInfo.lang === meta.id}
+                    onChange={() => { mutatePersonalSettingsInfo({ ...personalSettingsInfo, lang: meta.id }) }}
                   />
                   <label className="custom-control-label" htmlFor={`radioLang${meta.id}`}>{meta.displayName}</label>
                 </div>
@@ -135,10 +129,10 @@ class BasicInfoSettings extends React.Component {
             <input
               className="form-control"
               type="text"
-              key={personalContainer.state.slackMemberId}
+              key={personalSettingsInfo.slackMemberId}
               name="userForm[slackMemberId]"
-              defaultValue={personalContainer.state.slackMemberId}
-              onChange={(e) => { personalContainer.changeSlackMemberId(e.target.value) }}
+              defaultValue={personalSettingsInfo.slackMemberId}
+              onChange={(e) => { mutatePersonalSettingsInfo({ ...personalSettingsInfo, slackMemberId: e.target.value }) }}
             />
           </div>
         </div>
@@ -150,14 +144,14 @@ class BasicInfoSettings extends React.Component {
               type="button"
               className="btn btn-primary"
               onClick={this.onClickSubmit}
-              disabled={personalContainer.state.retrieveError != null}
+              disabled={error != null}
             >
               {t('Update')}
             </button>
           </div>
         </div>
 
-      </Fragment>
+      </>
     );
   }
 
@@ -165,17 +159,39 @@ class BasicInfoSettings extends React.Component {
 
 BasicInfoSettings.propTypes = {
   t: PropTypes.func.isRequired, // i18next
+  appContainer: PropTypes.instanceOf(AppContainer).isRequired,
   personalContainer: PropTypes.instanceOf(PersonalContainer).isRequired,
+  personalSettingsInfo: PropTypes.object,
+  mutatePersonalSettingsInfo: PropTypes.func,
+  error: PropTypes.object,
 };
 
 const BasicInfoSettingsWrapperFC = (props) => {
   const { t } = useTranslation();
-  return <BasicInfoSettings t={t} {...props} />;
+  // const { data: personalSettingsInfo, mutate: mutatePersonalSettingsInfo, sync: syncPersonalSettingsInfo } = usePersonalSettingsInfo();
+  const swrResult = usePersonalSettingsInfo();
+
+
+  useEffect(() => {
+    // Sync only when getting personal settings data from DB
+    swrResult.sync();
+    // eslint-disable-next-line react-hooks/exhaustive-deps
+  }, [swrResult.personalSettingsDataFromDB]);
+
+  return (
+    <BasicInfoSettings
+      t={t}
+      personalSettingsInfo={swrResult.data || {}}
+      mutatePersonalSettingsInfo={swrResult.mutate}
+      error={swrResult.error}
+      {...props}
+    />
+  );
 };
 
 /**
  * Wrapper component for using unstated
  */
-const BasicInfoSettingsWrapper = withUnstatedContainers(BasicInfoSettingsWrapperFC, [PersonalContainer]);
+const BasicInfoSettingsWrapper = withUnstatedContainers(BasicInfoSettingsWrapperFC, [AppContainer, PersonalContainer]);
 
 export default BasicInfoSettingsWrapper;

+ 9 - 13
packages/app/src/components/Me/PasswordSettings.jsx

@@ -1,14 +1,12 @@
-
 import React from 'react';
 
 import PropTypes from 'prop-types';
 import { useTranslation } from 'react-i18next';
 
-import PersonalContainer from '~/client/services/PersonalContainer';
 import { toastSuccess, toastError } from '~/client/util/apiNotification';
 import { apiv3Get, apiv3Put } from '~/client/util/apiv3-client';
+import { usePersonalSettingsInfo } from '~/stores/personal-settings';
 
-import { withUnstatedContainers } from '../UnstatedUtils';
 
 class PasswordSettings extends React.Component {
 
@@ -43,7 +41,7 @@ class PasswordSettings extends React.Component {
   }
 
   async onClickSubmit() {
-    const { t, personalContainer } = this.props;
+    const { t, mutatePersonalSetting } = this.props;
     const { oldPassword, newPassword, newPasswordConfirm } = this.state;
 
     try {
@@ -51,7 +49,9 @@ class PasswordSettings extends React.Component {
         oldPassword, newPassword, newPasswordConfirm,
       });
       this.setState({ oldPassword: '', newPassword: '', newPasswordConfirm: '' });
-      await personalContainer.retrievePersonalData();
+      if (mutatePersonalSetting != null) {
+        mutatePersonalSetting();
+      }
       toastSuccess(t('toaster.update_successed', { target: t('Password') }));
     }
     catch (err) {
@@ -155,17 +155,13 @@ class PasswordSettings extends React.Component {
 
 PasswordSettings.propTypes = {
   t: PropTypes.func.isRequired, // i18next
-  personalContainer: PropTypes.instanceOf(PersonalContainer).isRequired,
+  mutatePersonalSetting: PropTypes.func,
 };
 
 const PasswordSettingsWrapperFC = (props) => {
   const { t } = useTranslation();
-  return <PasswordSettings t={t} {...props} />;
+  const { data: personalSettingsInfoData, mutate: mutatePersonalSetting, sync: syncPersonalSettingsInfo } = usePersonalSettingsInfo();
+  return <PasswordSettings t={t} mutatePersonalSetting={mutatePersonalSetting} syncPersonalSettingsInfo={syncPersonalSettingsInfo} {...props} />;
 };
 
-/**
- * Wrapper component for using unstated
- */
-const PasswordSettingsWrapper = withUnstatedContainers(PasswordSettingsWrapperFC, [PersonalContainer]);
-
-export default PasswordSettingsWrapper;
+export default PasswordSettingsWrapperFC;

+ 33 - 0
packages/app/src/stores/personal-settings.tsx

@@ -1,9 +1,42 @@
 import useSWR, { SWRResponse } from 'swr';
 
+
+import { Nullable } from '~/interfaces/common';
 import { IExternalAccount } from '~/interfaces/external-account';
+import { IUser } from '~/interfaces/user';
 
 import { apiv3Get } from '../client/util/apiv3-client';
 
+import { useStaticSWR } from './use-static-swr';
+
+// retrievePersonalData
+export const useSWRxPersonalSettingsInfo = (): SWRResponse<IUser, Error> => {
+  return useSWR(
+    '/personal-setting',
+    endpoint => apiv3Get(endpoint).then(response => response.data.currentUser),
+  );
+};
+
+export type IPersonalSettingsInfoOption = {
+  personalSettingsDataFromDB: Nullable<IUser>,
+  sync: () => void;
+}
+
+export const usePersonalSettingsInfo = (): SWRResponse<IUser, Error> & IPersonalSettingsInfoOption => {
+  const { data: personalSettingsDataFromDB } = useSWRxPersonalSettingsInfo();
+
+  const swrResult = useStaticSWR<IUser, Error>('personalSettingsInfo', undefined);
+
+  return {
+    ...swrResult,
+    personalSettingsDataFromDB,
+    sync: (): void => {
+      const { mutate } = swrResult;
+      mutate(personalSettingsDataFromDB);
+    },
+  };
+};
+
 
 export const useSWRxPersonalExternalAccounts = (): SWRResponse<IExternalAccount[], Error> => {
   return useSWR(