redux ducks

This commit is contained in:
2020-10-13 14:37:25 +03:00
parent a2b629a850
commit d545e3e65e
23 changed files with 124 additions and 114 deletions
+3 -3
View File
@@ -1,14 +1,14 @@
import React from "react"; import React from "react";
import {activateAccount} from "../api/users"; import {activateAccount} from "../api/users";
import {connect} from "react-redux"; import {connect} from "react-redux";
import {addNotification} from "../store/actions";
import errors from "../api/errors"; import errors from "../api/errors";
import Loading from "../ui/Loading"; import Loading from "../ui/Loading";
import {addNotification} from "../store/ducks/notifications";
type Props = { type Props = {
history: { push: (path: string) => void } history: { push: (path: string) => void }
match: { params: { token: string } } match: { params: { token: string } }
addNotification: (notification: React.ReactNode) => void addNotification: AddNotification
}; };
type State = { type State = {
@@ -64,4 +64,4 @@ export default connect(null,
dispatch => ({ dispatch => ({
addNotification: (notification: React.ReactNode) => dispatch(addNotification(notification)) addNotification: (notification: React.ReactNode) => dispatch(addNotification(notification))
}) })
)(ActivateAccount); )(ActivateAccount);
+3 -2
View File
@@ -11,9 +11,10 @@ import BBEditor from "../../../ui/BBEditor/BBEditor";
import parser from 'bbcode-to-react'; import parser from 'bbcode-to-react';
import Title from "../../../ui/Title/Title"; import Title from "../../../ui/Title/Title";
import {connect} from "react-redux"; import {connect} from "react-redux";
import {addNotification, setModal} from "../../../store/actions";
import ConfirmPopout from "../../../ui/ConfirmPopout/ConfirmPopout"; import ConfirmPopout from "../../../ui/ConfirmPopout/ConfirmPopout";
import NotificationMessage from "../../../ui/Notifications/NotificationMessage"; import NotificationMessage from "../../../ui/Notifications/NotificationMessage";
import {setModal} from "../../../store/ducks/modal";
import {addNotification} from "../../../store/ducks/notifications";
type Props = { type Props = {
postId: number postId: number
@@ -147,4 +148,4 @@ export default connect(null,
setPopout: (modal: React.ReactNode | null) => dispatch(setModal(modal)), setPopout: (modal: React.ReactNode | null) => dispatch(setModal(modal)),
addNotification: (notification: React.ReactNode) => dispatch(addNotification(notification)) addNotification: (notification: React.ReactNode) => dispatch(addNotification(notification))
}) })
)(APModifyPost); )(APModifyPost);
+2 -2
View File
@@ -3,9 +3,9 @@ import {connect} from "react-redux";
import {fetchUser, updateUser} from "../../../api/users"; import {fetchUser, updateUser} from "../../../api/users";
import Loading from "../../../ui/Loading"; import Loading from "../../../ui/Loading";
import './APUser.sass'; import './APUser.sass';
import {addNotification} from "../../../store/actions";
import NotificationMessage from "../../../ui/Notifications/NotificationMessage"; import NotificationMessage from "../../../ui/Notifications/NotificationMessage";
import Button from "../../../ui/Button/Button"; import Button from "../../../ui/Button/Button";
import {addNotification} from "../../../store/ducks/notifications";
type Props = { type Props = {
userId: number userId: number
@@ -90,4 +90,4 @@ export default connect(
dispatch(addNotification(notification)) dispatch(addNotification(notification))
} }
}) })
)(ModifyUser); )(ModifyUser);
+2 -4
View File
@@ -8,7 +8,6 @@ import Main from "../Main/Main"
import NotFoundError from "../NotFoundError"; import NotFoundError from "../NotFoundError";
import {fetchCurrentUser, fetchUserSettings} from "../../api/users"; import {fetchCurrentUser, fetchUserSettings} from "../../api/users";
import {connect} from "react-redux"; import {connect} from "react-redux";
import {setUser} from "../../store/actions";
import Character from "../Character/Character"; import Character from "../Character/Character";
// @ts-ignore // @ts-ignore
import parser from 'bbcode-to-react'; import parser from 'bbcode-to-react';
@@ -26,6 +25,7 @@ import PasswordRestore from "../PasswordRestore/PasswordRestore";
import Users from "../Users/Users"; import Users from "../Users/Users";
import {getVersion, version} from "../../api/api"; import {getVersion, version} from "../../api/api";
import Settings from "../User/Settings/Settings"; import Settings from "../User/Settings/Settings";
import {setUser} from "../../store/ducks/currentUser";
type Props = { type Props = {
notifications: React.ReactNode[] notifications: React.ReactNode[]
@@ -130,8 +130,6 @@ export default connect(
modal: state.modal modal: state.modal
}), }),
dispatch => ({ dispatch => ({
setUser: (userData: UserType) => { setUser: (userData: UserType) => dispatch(setUser(userData))
dispatch(setUser(userData))
}
}) })
)(App); )(App);
+6 -8
View File
@@ -6,9 +6,9 @@ import './Comments.sass';
import Loading from "../../ui/Loading"; import Loading from "../../ui/Loading";
import {fetchUser} from "../../api/users"; import {fetchUser} from "../../api/users";
import {connect} from "react-redux"; import {connect} from "react-redux";
import {addNotification} from "../../store/actions";
import NotificationMessage from "../../ui/Notifications/NotificationMessage"; import NotificationMessage from "../../ui/Notifications/NotificationMessage";
import Button from "../../ui/Button/Button"; import Button from "../../ui/Button/Button";
import {addNotification} from "../../store/ducks/notifications";
type Props = { type Props = {
comments: CommentType[] comments: CommentType[]
@@ -48,7 +48,7 @@ class Comments extends React.Component<Props, State> {
event.preventDefault(); event.preventDefault();
const { sendComment, addNotification } = this.props; const { sendComment, addNotification } = this.props;
const { commentText } = this.state; const { commentText } = this.state;
if(commentText === '') { if(commentText === '') {
const notification = ( const notification = (
<NotificationMessage level={"error"}> <NotificationMessage level={"error"}>
@@ -84,7 +84,7 @@ class Comments extends React.Component<Props, State> {
const { users, commentText } = this.state; const { users, commentText } = this.state;
if(!user) return <Loading/>; if(!user) return <Loading/>;
return ( return (
<div className="Comments"> <div className="Comments">
{user.authorized && {user.authorized &&
<form onSubmit={this.sendComment}> <form onSubmit={this.sendComment}>
@@ -96,7 +96,7 @@ class Comments extends React.Component<Props, State> {
<FontAwesomeIcon onClick={event => this.addTagToComment(event, 'spoiler')} icon={faExclamationTriangle}/> <FontAwesomeIcon onClick={event => this.addTagToComment(event, 'spoiler')} icon={faExclamationTriangle}/>
<FontAwesomeIcon onClick={event => this.addTagToComment(event, 'color', 'white')} icon={faTint}/> <FontAwesomeIcon onClick={event => this.addTagToComment(event, 'color', 'white')} icon={faTint}/>
</div> </div>
<textarea <textarea
className={'Comments_TextArea'} className={'Comments_TextArea'}
placeholder={'Текст комментария'} placeholder={'Текст комментария'}
value={commentText} value={commentText}
@@ -126,8 +126,6 @@ class Comments extends React.Component<Props, State> {
export default connect(null, export default connect(null,
dispatch => ({ dispatch => ({
addNotification: (notification: React.ReactNode) => { addNotification: (notification: React.ReactNode) => dispatch(addNotification(notification))
dispatch(addNotification(notification))
}
}) })
)(Comments); )(Comments);
+3 -1
View File
@@ -2,7 +2,6 @@ import React, {FormEvent, ChangeEvent} from "react";
import Modal from "../../ui/Modal/Modal"; import Modal from "../../ui/Modal/Modal";
import {login} from "../../api/auth"; import {login} from "../../api/auth";
import {connect} from "react-redux"; import {connect} from "react-redux";
import {addNotification, hideModal, setModal, setUser} from "../../store/actions";
import './LoginModal.sass' import './LoginModal.sass'
import {Link} from "react-router-dom"; import {Link} from "react-router-dom";
import errors from "../../api/errors"; import errors from "../../api/errors";
@@ -11,6 +10,9 @@ import Recaptcha from '../../ui/Recaptcha/Recaptcha'
import Button from "../../ui/Button/Button"; import Button from "../../ui/Button/Button";
import RegisterModal from "./RegisterModal"; import RegisterModal from "./RegisterModal";
import Input from "../../ui/Input/Input"; 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";
type Props = { type Props = {
setUser: (user: UserType) => void setUser: (user: UserType) => void
+2 -1
View File
@@ -4,10 +4,11 @@ import Recaptcha from '../../ui/Recaptcha/Recaptcha'
import './RegisterModal.sass' import './RegisterModal.sass'
import {registerUser} from "../../api/auth"; import {registerUser} from "../../api/auth";
import {connect} from "react-redux"; import {connect} from "react-redux";
import {addNotification, setModal} from "../../store/actions";
import NotificationMessage from "../../ui/Notifications/NotificationMessage"; import NotificationMessage from "../../ui/Notifications/NotificationMessage";
import Button from "../../ui/Button/Button"; import Button from "../../ui/Button/Button";
import Input from "../../ui/Input/Input"; import Input from "../../ui/Input/Input";
import {addNotification} from "../../store/ducks/notifications";
import {setModal} from "../../store/ducks/modal";
type Props = { type Props = {
addNotification: (notification: React.ReactNode) => void addNotification: (notification: React.ReactNode) => void
+2 -1
View File
@@ -3,12 +3,13 @@ import './Navbar.sass'
import {connect} from "react-redux"; import {connect} from "react-redux";
import {userLogout} from "../../api/auth"; import {userLogout} from "../../api/auth";
import {Link} from "react-router-dom"; import {Link} from "react-router-dom";
import {logout, setModal} from "../../store/actions";
import {hasAccessToAdminPanel} from "../../utils"; import {hasAccessToAdminPanel} from "../../utils";
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome'; import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
import {faBars} from '@fortawesome/free-solid-svg-icons'; import {faBars} from '@fortawesome/free-solid-svg-icons';
import RegisterModal from "../Modals/RegisterModal"; import RegisterModal from "../Modals/RegisterModal";
import LoginModal from "../Modals/LoginModal"; import LoginModal from "../Modals/LoginModal";
import {logout} from "../../store/ducks/currentUser";
import {setModal} from "../../store/ducks/modal";
type Props = { type Props = {
setModal: SetModal setModal: SetModal
+2 -2
View File
@@ -13,10 +13,10 @@ import {
} from "../../api/novels"; } from "../../api/novels";
import {Link} from "react-router-dom"; import {Link} from "react-router-dom";
import Loading from "../../ui/Loading"; import Loading from "../../ui/Loading";
import {TranslateExitStatus, TranslatePlatform, TranslateStatus} from "../../api/api"; import {TranslateExitStatus, TranslateStatus} from "../../api/api";
import Comments from "../Comments/Comments"; import Comments from "../Comments/Comments";
import {hideModal, setModal} from "../../store/actions";
import LoadingModal from "../Modals/LoadingModal"; import LoadingModal from "../Modals/LoadingModal";
import {hideModal, setModal} from "../../store/ducks/modal";
type Props = { type Props = {
currentUser: UserType currentUser: UserType
+14 -3
View File
@@ -2,13 +2,18 @@ import Button from "../../../ui/Button/Button";
import Group from "../../../ui/Group/Group"; import Group from "../../../ui/Group/Group";
import React, {FormEvent} from "react"; import React, {FormEvent} from "react";
import {fetchUserSettings, updateUserAppearanceSettings} from "../../../api/users"; import {fetchUserSettings, updateUserAppearanceSettings} from "../../../api/users";
import {setUser} from "../../../store/actions"; import {connect} from "react-redux";
import {setUser} from "../../../store/ducks/currentUser";
type Props = {
setUser: SetUser
}
type State = { type State = {
theme: Theme theme: Theme
} }
class Appearance extends React.Component<{}, State> { class Appearance extends React.Component<Props, State> {
state: State = { state: State = {
theme: 'dark' theme: 'dark'
} }
@@ -23,6 +28,8 @@ class Appearance extends React.Component<{}, State> {
event.preventDefault(); event.preventDefault();
const { theme } = this.state; const { theme } = this.state;
const { setUser } = this.props;
updateUserAppearanceSettings(theme).then(user => { updateUserAppearanceSettings(theme).then(user => {
setUser(user); setUser(user);
@@ -52,4 +59,8 @@ class Appearance extends React.Component<{}, State> {
} }
} }
export default Appearance; export default connect(null,
dispatch => ({
setUser: (user: UserType) => dispatch(setUser(user))
})
)(Appearance);
+2 -2
View File
@@ -3,12 +3,12 @@ import Group from "../../../ui/Group/Group";
import {connect} from "react-redux"; import {connect} from "react-redux";
import NotFoundError from "../../NotFoundError"; import NotFoundError from "../../NotFoundError";
import './Settings.sass'; import './Settings.sass';
import {setUser} from "../../../store/actions";
import Tabs from "../../../ui/Tabs/Tabs"; import Tabs from "../../../ui/Tabs/Tabs";
import TabItem from "../../../ui/Tabs/TabItem"; import TabItem from "../../../ui/Tabs/TabItem";
import Appearance from "./Appearance"; import Appearance from "./Appearance";
import General from "./General"; import General from "./General";
import Security from "./Security"; import Security from "./Security";
import {setUser} from "../../../store/ducks/currentUser";
enum TabsNames { enum TabsNames {
General, General,
@@ -32,7 +32,7 @@ class Settings extends React.Component<Props, State> {
} }
render() { render() {
const { currentUser, match: { params: { userId } } } = this.props; const { currentUser, match: { params: { userId } }, setUser } = this.props;
const { currentTab } = this.state const { currentTab } = this.state
if(parseInt(userId) !== currentUser.id) return <NotFoundError/>; if(parseInt(userId) !== currentUser.id) return <NotFoundError/>;
+2 -3
View File
@@ -7,8 +7,8 @@ import Loading from "../../ui/Loading";
import NovelItem from "../../ui/NovelItem/NovelItem"; import NovelItem from "../../ui/NovelItem/NovelItem";
import {connect} from "react-redux"; import {connect} from "react-redux";
import Button from "../../ui/Button/Button"; import Button from "../../ui/Button/Button";
import {addNotification} from "../../store/actions";
import NotificationMessage from "../../ui/Notifications/NotificationMessage"; import NotificationMessage from "../../ui/Notifications/NotificationMessage";
import {addNotification} from "../../store/ducks/notifications";
type Props = { type Props = {
match: { params: { userId: string } } match: { params: { userId: string } }
@@ -69,8 +69,7 @@ class User extends React.Component<Props, State> {
</NotificationMessage> </NotificationMessage>
); );
this.props.addNotification(notification); this.props.addNotification(notification);
});
})
} }
render() { render() {
-9
View File
@@ -1,9 +0,0 @@
enum ActionTypes {
SET_USER = 'SET_USER',
LOGOUT = 'LOGOUT',
ADD_NOTIFICATION = 'ADD_NOTIFICATION',
SET_MODAL = 'SET_MODAL',
HIDE_MODAL = 'HIDE_MODAL'
}
export default ActionTypes;
-27
View File
@@ -1,27 +0,0 @@
import ActionTypes from "./actionTypes";
import React from "react";
const setUser = (userData: UserType) => ({
type: ActionTypes.SET_USER,
userData
});
const logout = () => ({
type: ActionTypes.LOGOUT
});
const addNotification = (notification: React.ReactNode) => ({
type: ActionTypes.ADD_NOTIFICATION,
notification
});
const setModal = (modal: React.ReactNode | null) => ({
type: ActionTypes.SET_MODAL,
modal
});
const hideModal = () => ({
type: ActionTypes.HIDE_MODAL
})
export { setUser, logout,
addNotification,
setModal, hideModal };
@@ -1,23 +1,22 @@
import ActionTypes from "../actionTypes"; const SET_USER = 'unmei/currentUser/SET_USER';
const LOGOUT = 'unmei/currentUser/LOGOUT';
const initialState = { const initialState = {
authorized: false authorized: false
}; };
type Action = { type Action = {
type: string type: string
userData: UserType userData: UserType
} };
const reducer = (state = initialState, action: Action) => {
export default (state = initialState, action: Action) => {
switch (action.type) { switch (action.type) {
case ActionTypes.SET_USER: case SET_USER:
if(action.userData) { if(action.userData) {
state = Object.assign({}, state, action.userData); state = Object.assign({}, state, action.userData);
state.authorized = true; state.authorized = true;
} }
return state; return state;
case ActionTypes.LOGOUT: case LOGOUT:
state = { state = {
authorized: false authorized: false
}; };
@@ -25,4 +24,15 @@ export default (state = initialState, action: Action) => {
default: default:
return state return state
} }
} }
const setUser = (userData: UserType) => ({
type: SET_USER,
userData
});
const logout = () => ({
type: LOGOUT
});
export default reducer;
export { setUser, logout }
+6
View File
@@ -0,0 +1,6 @@
import {combineReducers} from "redux";
import currentUser from './currentUser'
import modal from "./modal";
import notifications from './notifications'
export default combineReducers({ currentUser, modal, notifications })
+36
View File
@@ -0,0 +1,36 @@
import React from "react";
// Actions
const SET_MODAL = 'unmei/modal/SET_MODAL';
const HIDE_MODAL = 'unmei/modal/HIDE_MODAL';
// Reducer
const initialState: React.ReactNode | null = null;
type Action = {
type: string
modal: React.ReactNode | null
}
const reducer = (state=initialState, action: Action) => {
switch (action.type) {
case SET_MODAL: {
return action.modal;
}
case HIDE_MODAL: {
return null;
}
default: return state;
}
}
// Action creators
const setModal = (modal: React.ReactNode | null) => ({
type: SET_MODAL,
modal
});
const hideModal = () => ({
type: HIDE_MODAL
});
export default reducer;
export { setModal, hideModal }
@@ -1,20 +1,30 @@
import React from "react"; import React from "react";
import ActionTypes from "../actionTypes";
// Actions
const ADD_NOTIFICATION = 'unmei/notifications/ADD_NOTIFICATION';
// Reducer
const initialState: React.ReactNode[] = []; const initialState: React.ReactNode[] = [];
type Action = { type Action = {
type: string type: string
notification: React.ReactNode notification: React.ReactNode
} };
const reducer = (state = initialState, action: Action) => {
export default (state = initialState, action: Action) => {
switch (action.type) { switch (action.type) {
case ActionTypes.ADD_NOTIFICATION: { case ADD_NOTIFICATION: {
if(state.length === 3) if(state.length === 3)
return [...state.slice(1), action.notification]; return [...state.slice(1), action.notification];
return [...state, action.notification]; return [...state, action.notification];
} }
default: return state; default: return state;
} }
} }
// Actions creator
const addNotification = (notification: React.ReactNode) => ({
type: ADD_NOTIFICATION,
notification
});
export default reducer;
export { addNotification };
-21
View File
@@ -1,21 +0,0 @@
import React from "react";
import ActionTypes from "../actionTypes";
const initialState: React.ReactNode | null = null;
type Action = {
type: string
modal: React.ReactNode | null
}
export default (state=initialState, action: Action) => {
switch (action.type) {
case ActionTypes.SET_MODAL: {
return action.modal;
}
case ActionTypes.HIDE_MODAL: {
return null;
}
default: return state;
}
}
-6
View File
@@ -1,6 +0,0 @@
import {combineReducers} from "redux";
import currentUser from "./currentUser";
import notifications from "./notifications";
import modal from "./modal";
export default combineReducers({ currentUser, notifications, modal })
+1 -1
View File
@@ -1,6 +1,6 @@
import {createStore} from "redux"; import {createStore} from "redux";
import {composeWithDevTools} from "redux-devtools-extension"; import {composeWithDevTools} from "redux-devtools-extension";
import reducers from "./reducers/reducers"; import reducers from "./ducks/index";
const composeEnhancers = composeWithDevTools({ const composeEnhancers = composeWithDevTools({
trace: true trace: true
+2 -2
View File
@@ -3,7 +3,7 @@ import Button from "../Button/Button";
import './ConfirmPopout.sass' import './ConfirmPopout.sass'
import '../Modal/Modal.sass'; import '../Modal/Modal.sass';
import {connect} from "react-redux"; import {connect} from "react-redux";
import {hideModal} from "../../store/actions"; import {hideModal} from "../../store/ducks/modal";
type Props = { type Props = {
hideModal: () => void hideModal: () => void
@@ -50,4 +50,4 @@ export default connect(null,
dispatch => ({ dispatch => ({
hideModal: () => dispatch(hideModal()) hideModal: () => dispatch(hideModal())
}) })
)(ConfirmPopout); )(ConfirmPopout);
+1 -1
View File
@@ -1,7 +1,7 @@
import React from "react"; import React from "react";
import './Modal.sass' import './Modal.sass'
import {connect} from "react-redux"; import {connect} from "react-redux";
import {setModal} from "../../store/actions"; import {setModal} from "../../store/ducks/modal";
type Props = { type Props = {
setModal: (modal: React.ReactNode | null) => void setModal: (modal: React.ReactNode | null) => void