From 19e023c80fc085b1c673872038093f1a172d096e Mon Sep 17 00:00:00 2001 From: Nix13 Date: Thu, 15 Oct 2020 00:34:37 +0300 Subject: [PATCH] settings on redux; some fix with theme --- src/pages/App/App.tsx | 16 ++++++++++------ src/pages/Modals/LoginModal.tsx | 23 ++++++++++++++++------- src/pages/Navbar/Navbar.tsx | 4 +++- src/pages/User/Settings/Appearance.tsx | 16 +++++++--------- src/pages/User/Settings/General.tsx | 20 ++++++++++---------- src/pages/User/Settings/Security.tsx | 2 +- src/store/ducks/index.ts | 3 ++- src/store/ducks/userSettings.ts | 19 +++++++++++++++++++ src/types/store.d.ts | 7 +++++++ 9 files changed, 75 insertions(+), 35 deletions(-) create mode 100644 src/store/ducks/userSettings.ts diff --git a/src/pages/App/App.tsx b/src/pages/App/App.tsx index eae012d..0f760b9 100644 --- a/src/pages/App/App.tsx +++ b/src/pages/App/App.tsx @@ -26,11 +26,13 @@ import Users from "../Users/Users"; import {getVersion, version} from "../../api/api"; import Settings from "../User/Settings/Settings"; import {setUser} from "../../store/ducks/currentUser"; +import {setSettings} from "../../store/ducks/userSettings"; type Props = { notifications: React.ReactNode[] - setUser: (user: UserType) => void modal: React.ReactNode + setUser: SetUser + setSettings: SetSettings }; type State = {} @@ -45,10 +47,11 @@ class App extends React.Component { if(cachedTheme) document.body.setAttribute('theme', cachedTheme); - const { setUser } = props; - fetchCurrentUser().then((user: UserType) => { + const { setUser, setSettings } = props; + fetchCurrentUser().then(user => { setUser(user); - fetchUserSettings().then((settings: UserSettingsType) => { + fetchUserSettings().then(settings => { + setSettings(settings); if(settings.theme !== cachedTheme) { localStorage.setItem('theme', settings.theme); document.body.setAttribute('theme', settings.theme); @@ -64,7 +67,7 @@ class App extends React.Component { getVersion().then(res => { if(version !== res.version) { - console.log(`Current back-end version: ${res.version}. Clearing cache`); + console.debug(`Current back-end version: ${res.version}. Clearing cache`); caches.keys().then(names => { names.forEach(name => caches.delete(name).catch(console.error)) @@ -130,6 +133,7 @@ export default connect( modal: state.modal }), dispatch => ({ - setUser: (userData: UserType) => dispatch(setUser(userData)) + setUser: (userData: UserType) => dispatch(setUser(userData)), + setSettings: (settings: UserSettingsType) => dispatch(setSettings(settings)) }) )(App); diff --git a/src/pages/Modals/LoginModal.tsx b/src/pages/Modals/LoginModal.tsx index e549914..0a9ca84 100644 --- a/src/pages/Modals/LoginModal.tsx +++ b/src/pages/Modals/LoginModal.tsx @@ -13,12 +13,15 @@ import Input from "../../ui/Input/Input"; import {setUser} from "../../store/ducks/currentUser"; import {addNotification} from "../../store/ducks/notifications"; import {hideModal, setModal} from "../../store/ducks/modal"; +import {fetchUserSettings} from "../../api/users"; +import {setSettings} from "../../store/ducks/userSettings"; type Props = { - setUser: (user: UserType) => void - addNotification: (notification: React.ReactNode) => void - setModal: (modal: React.ReactNode | null) => void - hideModal: () => void + setUser: SetUser + addNotification: AddNotification + setModal: SetModal + hideModal: HideModal + setSettings: SetSettings }; type State = { @@ -36,7 +39,7 @@ class LoginModal extends React.Component { loginAndFetchToken = (event: FormEvent) => { event.preventDefault(); - const { setUser, addNotification, setModal } = this.props; + const { setUser, addNotification, setModal, setSettings } = this.props; const { login: log, password, recaptcha } = this.state; login(log, password, recaptcha).then(user => { @@ -50,8 +53,13 @@ class LoginModal extends React.Component { ); addNotification(successful); setModal(null); - }) - .catch((r: ApiError) => { + + fetchUserSettings().then(settings => { + localStorage.setItem('theme', settings.theme); + document.body.setAttribute('theme', settings.theme); + setSettings(settings); + }); + }).catch((r: ApiError) => { this.setState({ error: errors[r.code] }); if(r.code === 9) this.setState({ recaptchaNeeded: true }); }); @@ -105,6 +113,7 @@ class LoginModal extends React.Component { export default connect(null, dispatch => ({ setUser: (user: UserType) => dispatch(setUser(user)), + setSettings: (settings: UserSettingsType) => dispatch(setSettings(settings)), addNotification: (notification: React.ReactNode) => dispatch(addNotification(notification)), setModal: (modal: React.ReactNode | null) => dispatch(setModal(modal)), hideModal: () => dispatch(hideModal()) diff --git a/src/pages/Navbar/Navbar.tsx b/src/pages/Navbar/Navbar.tsx index 032405b..c0c8b7e 100644 --- a/src/pages/Navbar/Navbar.tsx +++ b/src/pages/Navbar/Navbar.tsx @@ -30,7 +30,9 @@ class Navbar extends React.Component { logout = () => { this.props.logout(); localStorage.removeItem('user'); - userLogout().then(); + localStorage.removeItem('theme'); + document.querySelector('body')!!.removeAttribute('theme'); + userLogout().catch(() => {}); }; changeSize = () => { diff --git a/src/pages/User/Settings/Appearance.tsx b/src/pages/User/Settings/Appearance.tsx index 28c6cd6..9e8e710 100644 --- a/src/pages/User/Settings/Appearance.tsx +++ b/src/pages/User/Settings/Appearance.tsx @@ -1,12 +1,13 @@ import Button from "../../../ui/Button/Button"; import Group from "../../../ui/Group/Group"; import React, {FormEvent} from "react"; -import {fetchUserSettings, updateUserAppearanceSettings} from "../../../api/users"; +import {updateUserAppearanceSettings} from "../../../api/users"; import {connect} from "react-redux"; import {setUser} from "../../../store/ducks/currentUser"; type Props = { setUser: SetUser + settings: UserSettingsType } type State = { @@ -15,13 +16,7 @@ type State = { class Appearance extends React.Component { state: State = { - theme: 'dark' - } - - componentDidMount() { - fetchUserSettings().then(settings => { - this.setState({ theme: settings.theme }) - }) + theme: this.props.settings.theme } saveTheme = (event: FormEvent) => { @@ -59,7 +54,10 @@ class Appearance extends React.Component { } } -export default connect(null, +export default connect( + (state: StoreState) => ({ + settings: state.userSettings + }), dispatch => ({ setUser: (user: UserType) => dispatch(setUser(user)) }) diff --git a/src/pages/User/Settings/General.tsx b/src/pages/User/Settings/General.tsx index fe36c61..55618c0 100644 --- a/src/pages/User/Settings/General.tsx +++ b/src/pages/User/Settings/General.tsx @@ -1,10 +1,12 @@ import React, {ChangeEvent, FormEvent} from "react"; import Button from "../../../ui/Button/Button"; import Group from "../../../ui/Group/Group"; -import {fetchUserSettings, updateUserGeneralSettings, uploadAvatar} from "../../../api/users"; +import {updateUserGeneralSettings, uploadAvatar} from "../../../api/users"; +import {connect} from "react-redux"; type Props = { - setUser: (user: UserType) => void + setUser: SetUser + settings: UserSettingsType } type State = { @@ -15,13 +17,7 @@ type State = { class General extends React.Component { state: State = { - useGravatar: false, avatar: null - } - - componentDidMount() { - fetchUserSettings().then(settings => { - this.setState({ useGravatar: settings.use_gravatar }) - }) + useGravatar: this.props.settings.use_gravatar, avatar: null } onChangeAvatar = (event: ChangeEvent) => { @@ -62,4 +58,8 @@ class General extends React.Component { } } -export default General; +export default connect( + (state: StoreState) => ({ + settings: state.userSettings + }) +)(General); diff --git a/src/pages/User/Settings/Security.tsx b/src/pages/User/Settings/Security.tsx index 68a88b2..a28367d 100644 --- a/src/pages/User/Settings/Security.tsx +++ b/src/pages/User/Settings/Security.tsx @@ -55,7 +55,7 @@ class Security extends React.Component<{}, State> { placeholder={'Новый E-mail ещё раз'} type={'email'} value={email2} - onChange={e => this.setState({ email1: e.target.value })} + onChange={e => this.setState({ email2: e.target.value })} /> diff --git a/src/store/ducks/index.ts b/src/store/ducks/index.ts index daa3c02..0090b53 100644 --- a/src/store/ducks/index.ts +++ b/src/store/ducks/index.ts @@ -2,5 +2,6 @@ import {combineReducers} from "redux"; import currentUser from './currentUser' import modal from "./modal"; import notifications from './notifications' +import userSettings from './userSettings'; -export default combineReducers({ currentUser, modal, notifications }) +export default combineReducers({ currentUser, modal, notifications, userSettings }) diff --git a/src/store/ducks/userSettings.ts b/src/store/ducks/userSettings.ts new file mode 100644 index 0000000..e17d396 --- /dev/null +++ b/src/store/ducks/userSettings.ts @@ -0,0 +1,19 @@ +const SET_SETTINGS = 'unmei/userSettings/SET_SETTINGS'; + +const reducer = (state={}, action: Action<{settings: UserSettingsType}>) => { + switch (action.type) { + case SET_SETTINGS: + state = Object.assign({}, state, action.payload.settings); + return state; + default: + return state; + } +} + +const setSettings = (settings: UserSettingsType) => ({ + type: SET_SETTINGS, + payload: { settings } +}); + +export default reducer; +export { setSettings } diff --git a/src/types/store.d.ts b/src/types/store.d.ts index bbf0289..3f954a2 100644 --- a/src/types/store.d.ts +++ b/src/types/store.d.ts @@ -1,11 +1,18 @@ type StoreState = { currentUser: UserType + userSettings: UserSettingsType notifications: React.ReactNode[] modal: React.ReactNode } +type Action = { + type: string + payload: T +} + type SetUser = (user: UserType) => void type LogoutUser = () => void +type SetSettings = (settings: UserSettingsType) => void type SetModal = (modal: React.ReactNode | null) => void type HideModal = () => void type AddNotification = (notification: React.ReactNode) => void