main
Саске Учиха 2 years ago
parent 50b72cd033
commit 877a55a3a8

@ -4,10 +4,14 @@ Ararat International School - платформа по обучению игры
### Стэк:
- React.js
- Express.js
- Tailwind css
- TypeScript
- Mobx (временно)
- Redux toolkit
- Tailwind css
- Express.js
- Mongo DB
#### V 0.02
- Mobx заменен Redux toolkit
#### V 0.01
- Добавлена главная страница

@ -8,14 +8,15 @@
"name": "araratchess",
"version": "0.0.0",
"dependencies": {
"@reduxjs/toolkit": "^1.9.5",
"@types/axios": "^0.14.0",
"@types/react-redux": "^7.1.25",
"@types/react-router-dom": "^5.3.3",
"axios": "^1.4.0",
"mobx": "^6.9.1",
"mobx-react-lite": "^4.0.3",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-hook-form": "^7.45.2",
"react-redux": "^8.1.1",
"react-router-dom": "^6.14.2"
},
"devDependencies": {
@ -366,6 +367,17 @@
"@babel/core": "^7.0.0-0"
}
},
"node_modules/@babel/runtime": {
"version": "7.22.6",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.6.tgz",
"integrity": "sha512-wDb5pWm4WDdF6LFUde3Jl8WzPA+3ZbxYqkC6xAXuD3irdEHN1k0NfTRrJD8ZD378SJ61miMLCqIOXYhd8x+AJQ==",
"dependencies": {
"regenerator-runtime": "^0.13.11"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/template": {
"version": "7.22.5",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.5.tgz",
@ -960,6 +972,29 @@
"node": ">= 8"
}
},
"node_modules/@reduxjs/toolkit": {
"version": "1.9.5",
"resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.9.5.tgz",
"integrity": "sha512-Rt97jHmfTeaxL4swLRNPD/zV4OxTes4la07Xc4hetpUW/vc75t5m1ANyxG6ymnEQ2FsLQsoMlYB2vV1sO3m8tQ==",
"dependencies": {
"immer": "^9.0.21",
"redux": "^4.2.1",
"redux-thunk": "^2.4.2",
"reselect": "^4.1.8"
},
"peerDependencies": {
"react": "^16.9.0 || ^17.0.0 || ^18",
"react-redux": "^7.2.1 || ^8.0.2"
},
"peerDependenciesMeta": {
"react": {
"optional": true
},
"react-redux": {
"optional": true
}
}
},
"node_modules/@remix-run/router": {
"version": "1.7.2",
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.7.2.tgz",
@ -982,6 +1017,15 @@
"resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.11.tgz",
"integrity": "sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA=="
},
"node_modules/@types/hoist-non-react-statics": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz",
"integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==",
"dependencies": {
"@types/react": "*",
"hoist-non-react-statics": "^3.3.0"
}
},
"node_modules/@types/json-schema": {
"version": "7.0.12",
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz",
@ -1007,11 +1051,22 @@
"version": "18.2.7",
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.7.tgz",
"integrity": "sha512-GRaAEriuT4zp9N4p1i8BDBYmEyfo+xQ3yHjJU4eiK5NDa1RmUZG+unZABUTK4/Ox/M+GaHwb6Ow8rUITrtjszA==",
"dev": true,
"devOptional": true,
"dependencies": {
"@types/react": "*"
}
},
"node_modules/@types/react-redux": {
"version": "7.1.25",
"resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.25.tgz",
"integrity": "sha512-bAGh4e+w5D8dajd6InASVIyCo4pZLJ66oLb80F9OBLO1gKESbZcRCJpTT6uLXX+HAB57zw1WTdwJdAsewuTweg==",
"dependencies": {
"@types/hoist-non-react-statics": "^3.3.0",
"@types/react": "*",
"hoist-non-react-statics": "^3.3.0",
"redux": "^4.0.0"
}
},
"node_modules/@types/react-router": {
"version": "5.1.20",
"resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.20.tgz",
@ -1042,6 +1097,11 @@
"integrity": "sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==",
"dev": true
},
"node_modules/@types/use-sync-external-store": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz",
"integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA=="
},
"node_modules/@typescript-eslint/eslint-plugin": {
"version": "5.62.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz",
@ -2341,6 +2401,14 @@
"node": ">=4"
}
},
"node_modules/hoist-non-react-statics": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
"integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==",
"dependencies": {
"react-is": "^16.7.0"
}
},
"node_modules/ignore": {
"version": "5.2.4",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz",
@ -2350,6 +2418,15 @@
"node": ">= 4"
}
},
"node_modules/immer": {
"version": "9.0.21",
"resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz",
"integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/immer"
}
},
"node_modules/import-fresh": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
@ -2644,39 +2721,6 @@
"node": "*"
}
},
"node_modules/mobx": {
"version": "6.9.1",
"resolved": "https://registry.npmjs.org/mobx/-/mobx-6.9.1.tgz",
"integrity": "sha512-7V41hvBmzCQg5n/xoZi2qkhREbnF3wHbzbIdR1sLJhVt6yWq2Zq0FlNahEt/RccOmEIjipvBqeQ4mlOEyMhaaA==",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/mobx"
}
},
"node_modules/mobx-react-lite": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/mobx-react-lite/-/mobx-react-lite-4.0.3.tgz",
"integrity": "sha512-wEE1oT5zvDdvplG4HnRrFgPwg5GFVVrEtl42Er85k23zeu3om8H8wbDPgdbQP88zAihVsik6xJfw6VnzUl8fQw==",
"dependencies": {
"use-sync-external-store": "^1.2.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/mobx"
},
"peerDependencies": {
"mobx": "^6.9.0",
"react": "^16.8.0 || ^17 || ^18"
},
"peerDependenciesMeta": {
"react-dom": {
"optional": true
},
"react-native": {
"optional": true
}
}
},
"node_modules/ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
@ -3124,6 +3168,54 @@
"react": "^16.8.0 || ^17 || ^18"
}
},
"node_modules/react-is": {
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
},
"node_modules/react-redux": {
"version": "8.1.1",
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-8.1.1.tgz",
"integrity": "sha512-5W0QaKtEhj+3bC0Nj0NkqkhIv8gLADH/2kYFMTHxCVqQILiWzLv6MaLuV5wJU3BQEdHKzTfcvPN0WMS6SC1oyA==",
"dependencies": {
"@babel/runtime": "^7.12.1",
"@types/hoist-non-react-statics": "^3.3.1",
"@types/use-sync-external-store": "^0.0.3",
"hoist-non-react-statics": "^3.3.2",
"react-is": "^18.0.0",
"use-sync-external-store": "^1.0.0"
},
"peerDependencies": {
"@types/react": "^16.8 || ^17.0 || ^18.0",
"@types/react-dom": "^16.8 || ^17.0 || ^18.0",
"react": "^16.8 || ^17.0 || ^18.0",
"react-dom": "^16.8 || ^17.0 || ^18.0",
"react-native": ">=0.59",
"redux": "^4 || ^5.0.0-beta.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
},
"react-dom": {
"optional": true
},
"react-native": {
"optional": true
},
"redux": {
"optional": true
}
}
},
"node_modules/react-redux/node_modules/react-is": {
"version": "18.2.0",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
"integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w=="
},
"node_modules/react-refresh": {
"version": "0.14.0",
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.0.tgz",
@ -3184,6 +3276,32 @@
"node": ">=8.10.0"
}
},
"node_modules/redux": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz",
"integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==",
"dependencies": {
"@babel/runtime": "^7.9.2"
}
},
"node_modules/redux-thunk": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.2.tgz",
"integrity": "sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q==",
"peerDependencies": {
"redux": "^4"
}
},
"node_modules/regenerator-runtime": {
"version": "0.13.11",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
"integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg=="
},
"node_modules/reselect": {
"version": "4.1.8",
"resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.8.tgz",
"integrity": "sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ=="
},
"node_modules/resolve": {
"version": "1.22.2",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz",

@ -10,14 +10,15 @@
"preview": "vite preview"
},
"dependencies": {
"@reduxjs/toolkit": "^1.9.5",
"@types/axios": "^0.14.0",
"@types/react-redux": "^7.1.25",
"@types/react-router-dom": "^5.3.3",
"axios": "^1.4.0",
"mobx": "^6.9.1",
"mobx-react-lite": "^4.0.3",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-hook-form": "^7.45.2",
"react-redux": "^8.1.1",
"react-router-dom": "^6.14.2"
},
"devDependencies": {

@ -1,28 +1,33 @@
import { useEffect, useContext } from "react"
import { useEffect } from "react"
import RequireAuth from "./components/Auth/RequireAuth"
import OnlyUnauthorized from "./components/Auth/OnlyUnauthorized"
import IndexPage from "./pages/IndexPage"
import LoginForm from "./components/LoginForm"
import RegisterForm from "./components/RegisterForm"
import { BrowserRouter, Routes, Route } from 'react-router-dom'
import { Context } from "./main"
import { observer } from "mobx-react-lite"
import { checkAuth, userSlice } from "./store/reducers/UserSlice";
import { useAppDispatch, useAppSelector } from "./hooks/redux"
function App() {
const {store} = useContext(Context);
const {isLoading} = useAppSelector(state => state.UserSlice);
const {storeLoad} = userSlice.actions
const dispatch = useAppDispatch();
useEffect(()=>{
const CheckLogin = async () => {
if(localStorage.getItem('token')) {
await store.checkAuth();
await dispatch(checkAuth());
} else {
store.storeLoad();
dispatch(storeLoad());
}
}
CheckLogin().catch(console.error);
}, [])
}, [dispatch, storeLoad])
if(!store.isLoading) {
if(!isLoading) {
return (
<BrowserRouter>
<Routes>
@ -35,4 +40,4 @@ function App() {
}
}
export default observer(App)
export default App

@ -1,18 +1,17 @@
import { FC, PropsWithChildren, useContext } from 'react'
import { FC, PropsWithChildren } from 'react'
import { useLocation, Navigate } from 'react-router-dom';
import { Context } from "../../main"
import { observer } from "mobx-react-lite"
import { useAppSelector } from '../../hooks/redux';
const OnlyUnauthorized: FC<PropsWithChildren> = observer(({children}) => {
const OnlyUnauthorized: FC<PropsWithChildren> = ({children}) => {
const {store} = useContext(Context);
const {isAuth} = useAppSelector(state => state.UserSlice);
const location = useLocation();
if (store.isAuth) {
if (isAuth) {
return <Navigate to="/" state={{ from: location }} replace />;
}
return children;
})
}
export default OnlyUnauthorized;

@ -1,18 +1,17 @@
import { FC, PropsWithChildren, useContext } from 'react'
import { FC, PropsWithChildren } from 'react'
import { useLocation, Navigate } from 'react-router-dom';
import { Context } from "../../main"
import { observer } from "mobx-react-lite"
import { useAppSelector } from '../../hooks/redux';
const RequireAuth: FC<PropsWithChildren> = observer(({children}) => {
const RequireAuth: FC<PropsWithChildren> = ({children}) => {
const {store} = useContext(Context);
const {isAuth} = useAppSelector(state => state.UserSlice);
const location = useLocation();
if (!store.isAuth) {
if (!isAuth) {
return <Navigate to="/login" state={{ from: location }} replace />;
}
return children;
})
}
export default RequireAuth;

@ -1,10 +1,17 @@
import { FC, useContext } from 'react'
import { FC } from 'react'
import MenuItem from './MenuItem';
import { Link } from 'react-router-dom';
import { Context } from '../../../main';
import { logout } from "../../../store/reducers/UserSlice";
import { useAppDispatch } from "../../../hooks/redux"
const Menu: FC = () => {
const {store} = useContext(Context);
const dispatch = useAppDispatch();
const logoutHandler = async () => {
await dispatch(logout());
}
return (
<nav>
<ul className='border-b pb-5'>
@ -19,7 +26,7 @@ const Menu: FC = () => {
</ul>
<ul className='pt-5'>
<li className='mb-2'><Link to='/' className='text-slate-400'>Настройки</Link></li>
<li className='mb-2 text-slate-400 cursor-pointer' onClick={() => void store.logout()}>Выход</li>
<li className='mb-2 text-slate-400 cursor-pointer' onClick={ () => void logoutHandler() }>Выход</li>
</ul>
</nav>
)

@ -1,21 +1,19 @@
import { useContext } from "react"
import { FC } from 'react'
import { Context } from "../../main"
import { observer } from "mobx-react-lite"
import { useAppSelector } from '../../hooks/redux';
const UserInfo: FC = () => {
const UserInfo: FC = observer(() => {
const {store} = useContext(Context);
const {user} = useAppSelector(state => state.UserSlice);
return (
<div className='flex items-center mb-12'>
<div className="mr-3 w-12 h-12"><img src={store.user.avatar} className='w-[inherit] h-[inherit]' alt="avatar"/></div>
<div className="mr-3 w-12 h-12"><img src={user.avatar} className='w-[inherit] h-[inherit]' alt="avatar"/></div>
<div className="">
<p className='text-lg font-medium'>{store.user.name + ' ' + store.user.sname}</p>
<p className='text-base'>{store.user.email}</p>
<p className='text-lg font-medium'>{user.name + ' ' + user.sname}</p>
<p className='text-base'>{user.email}</p>
</div>
</div>
)
})
}
export default UserInfo;

@ -1,9 +1,10 @@
/* eslint-disable @typescript-eslint/no-misused-promises */
import {FC, useContext} from 'react'
import {FC, useEffect} from 'react'
import { useForm, SubmitHandler } from "react-hook-form";
import { Context } from '../main';
import Logo from '../assets/logo.png'
import { Link, useNavigate } from 'react-router-dom';
import { useAppSelector, useAppDispatch } from '../hooks/redux';
import { login } from '../store/reducers/UserSlice';
type Form = {
email: string,
@ -11,17 +12,22 @@ type Form = {
};
const LoginForm: FC = () => {
const navigate = useNavigate();
const {store} = useContext(Context);
const dispatch = useAppDispatch();
const {isAuth} = useAppSelector(state => state.UserSlice);
const { register, handleSubmit, formState: {isSubmitSuccessful} } = useForm<Form>();
const { register, handleSubmit } = useForm<Form>();
const onSubmit: SubmitHandler<Form> = async (data) => {
await store.login(data.email, data.password);
if(store.isAuth) {
useEffect(() => {
if(isSubmitSuccessful) {
if(isAuth) {
navigate('/');
}
}
}, [isSubmitSuccessful]) // eslint-disable-line react-hooks/exhaustive-deps
const onSubmit: SubmitHandler<Form> = async (data) => {
await dispatch(login({email: data.email, password: data.password}));
}
return (
<section className="flex items-center h-screen">

@ -1,9 +1,10 @@
/* eslint-disable @typescript-eslint/no-misused-promises */
import {FC, useContext} from 'react'
import {FC, useEffect} from 'react'
import { useForm, SubmitHandler } from "react-hook-form";
import { useNavigate, Link } from 'react-router-dom';
import { Context } from '../main';
import Logo from '../assets/logo.png'
import { useAppSelector, useAppDispatch } from '../hooks/redux';
import { registration } from '../store/reducers/UserSlice';
const RegisterForm: FC = () => {
@ -16,15 +17,21 @@ const RegisterForm: FC = () => {
};
const navigate = useNavigate();
const {store} = useContext(Context);
const dispatch = useAppDispatch();
const {isAuth} = useAppSelector(state => state.UserSlice);
const { register, handleSubmit, watch, formState: {isSubmitSuccessful} } = useForm<Form>();
const { register, handleSubmit, watch } = useForm<Form>();
const onSubmit: SubmitHandler<Form> = async (data) => {
await store.registration(data.email, data.name, data.sname, data.password);
if(store.isAuth) {
useEffect(() => {
if(isSubmitSuccessful) {
if(isAuth) {
navigate('/');
}
}
}, [isSubmitSuccessful]) // eslint-disable-line react-hooks/exhaustive-deps
const onSubmit: SubmitHandler<Form> = async (data) => {
await dispatch(registration({email: data.email, name: data.name, sname: data.sname, password: data.password}));
}
return (
<section className="flex items-center h-screen">

@ -0,0 +1,5 @@
import { TypedUseSelectorHook, useDispatch, useSelector } from "react-redux";
import { AppDispatch, RootState } from "../store/store";
export const useAppDispatch = () => useDispatch<AppDispatch>();
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;

@ -1,22 +1,16 @@
import React, { createContext } from 'react'
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.tsx'
import './index.css'
import Store from './store/store.ts'
import { store } from './store/store.ts'
import { Provider } from 'react-redux'
interface State {
store: Store
}
const store = new Store();
export const Context = createContext<State>({store});
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<Context.Provider value={{store}}>
<Provider store={store()}>
<App />
</Context.Provider>
</Provider>
</React.StrictMode>,
)

@ -0,0 +1,3 @@
export interface ServerError {
error: string
}

@ -0,0 +1,140 @@
import { createSlice, createAsyncThunk } from "@reduxjs/toolkit"
import { User } from "../../models/User"
import { AuthResponse } from "../../models/response/AuthResponse";
import AuthService from "../../services/AuthService";
import { ServerError } from "../../models/response/ServerError";
import { AxiosError } from 'axios';
import { API_URL } from "../../http";
import axios from "axios";
export interface UserState {
user: User;
isAuth: boolean;
isLoading: boolean;
}
const initialState: UserState = {
user: {
_id: '',
email: '',
name: '',
sname: ''
},
isAuth: false,
isLoading: true
}
export const registration = createAsyncThunk<User, {email: string, name: string, sname: string, password: string}>(
'userSlice/registration',
async (user, {rejectWithValue}) => {
try {
const {email, name, sname, password} = user;
const response = await AuthService.registration(email, name, sname, password);
localStorage.setItem('token', response.data.accessToken);
return response.data.user;
} catch (error) {
const err = error as AxiosError;
const e = err.response?.data as ServerError
return rejectWithValue(e.error);
}
}
)
export const login = createAsyncThunk<User, {email: string, password: string}>(
'userSlice/login',
async (user, {rejectWithValue}) => {
try {
const {email, password} = user;
const response = await AuthService.login(email, password);
localStorage.setItem('token', response.data.accessToken);
return response.data.user;
} catch ( error ) {
const err = error as AxiosError;
const e = err.response?.data as ServerError
return rejectWithValue(e.error);
}
}
)
export const checkAuth = createAsyncThunk<User>(
'userSlice/checkAuth',
async (_, {rejectWithValue}) => {
try {
const response = await axios.get<AuthResponse>(`${API_URL}/auth/refresh`, {withCredentials: true});
localStorage.setItem('token', response.data.accessToken);
return response.data.user;
} catch (error) {
const err = error as AxiosError;
const e = err.response?.data as ServerError
return rejectWithValue(e.error);
}
}
)
export const logout = createAsyncThunk<boolean>(
'userSlice/logout',
async (_, {rejectWithValue}) => {
try {
await AuthService.logout();
localStorage.removeItem('token');
return true;
} catch (error) {
const err = error as AxiosError;
const e = err.response?.data as ServerError
return rejectWithValue(e.error);
}
}
)
export const userSlice = createSlice({
name: 'userSlice',
initialState,
reducers: {
storeLoad(state) {
state.isLoading = false;
}
},
extraReducers: (builder) => {
builder
.addCase(registration.fulfilled, (state, { payload }) => {
state.isAuth = true;
state.user = payload;
})
.addCase(registration.rejected, (_, { payload }) => {
console.log(payload);
})
.addCase(login.fulfilled, (state, { payload }) => {
state.isAuth = true;
state.user = payload;
})
.addCase(login.rejected, (_, { payload }) => {
console.log(payload);
})
.addCase(checkAuth.pending, (state) => {
state.isLoading = true;
})
.addCase(checkAuth.fulfilled, (state, action) => {
state.user = action.payload;
state.isAuth = true;
state.isLoading = false;
})
.addCase(checkAuth.rejected, (state, { payload }) => {
state.isLoading = false;
console.log(payload);
})
.addCase(logout.fulfilled, (state) => {
state.isAuth = false;
state.user = {} as User;
})
.addCase(logout.rejected, (_, { payload }) => {
console.log(payload);
})
}
})
export default userSlice.reducer;

@ -1,79 +1,16 @@
import { User } from "../models/User"
import { makeAutoObservable } from "mobx";
import AuthService from "../services/AuthService";
import axios from "axios";
import { AuthResponse } from "../models/response/AuthResponse";
import { API_URL } from "../http";
import { combineReducers, configureStore } from "@reduxjs/toolkit";
import UserSlice from "./reducers/UserSlice";
export default class Store {
user = {} as User;
isAuth = false;
isLoading = true;
const rootReducer = combineReducers({
UserSlice
})
constructor() {
makeAutoObservable(this);
}
setAuth(bool: boolean) {
this.isAuth = bool;
}
setUser(user: User) {
this.user = user;
}
setLoading(bool: boolean) {
this.isLoading = bool;
}
async registration (email: string, name: string, sname: string, password: string) {
try {
const response = await AuthService.registration(email, name, sname, password);
localStorage.setItem('token', response.data.accessToken);
this.setAuth(true);
this.setUser(response.data.user)
} catch (e) {
console.log(e)
}
}
async login (email: string, password: string) {
try {
const response = await AuthService.login(email, password);
localStorage.setItem('token', response.data.accessToken);
this.setAuth(true);
this.setUser(response.data.user)
} catch (e) {
console.log(e)
}
}
async logout () {
try {
await AuthService.logout();
localStorage.removeItem('token');
this.setAuth(false);
this.setUser({} as User);
} catch (e) {
console.log(e)
}
}
async checkAuth() {
this.setLoading(true);
try {
const response = await axios.get<AuthResponse>(`${API_URL}/auth/refresh`, {withCredentials: true});
localStorage.setItem('token', response.data.accessToken);
this.setAuth(true);
this.setUser(response.data.user)
} catch (e) {
console.log(e);
} finally {
this.setLoading(false);
}
}
storeLoad() {
this.setLoading(false);
}
export const store = () => {
return configureStore({
reducer: rootReducer
})
}
export type RootState = ReturnType<typeof rootReducer>
export type AppStore = ReturnType<typeof store>
export type AppDispatch = AppStore['dispatch']
Loading…
Cancel
Save