From 891ebf7bbb55ea4d95e04076d6998548e3baea7c Mon Sep 17 00:00:00 2001 From: qvalentin Date: Fri, 20 Nov 2020 16:33:15 +0100 Subject: [PATCH 01/10] added user state and cookies check --- .../src/background/redux/actions/sytemState.tsx | 4 +++- .../src/background/redux/actions/tokenTypes.tsx | 11 +++++++++-- .../src/background/redux/actions/userTypes.tsx | 17 +++++++++++++++++ .../src/background/redux/reducers/tokens.tsx | 16 +++++++++++++--- .../src/background/redux/reducers/user.tsx | 17 +++++++++++++++++ webapp_frontend/src/components/App.tsx | 3 ++- 6 files changed, 61 insertions(+), 7 deletions(-) create mode 100644 webapp_frontend/src/background/redux/actions/userTypes.tsx create mode 100644 webapp_frontend/src/background/redux/reducers/user.tsx diff --git a/webapp_frontend/src/background/redux/actions/sytemState.tsx b/webapp_frontend/src/background/redux/actions/sytemState.tsx index 91c66188..a5888e73 100644 --- a/webapp_frontend/src/background/redux/actions/sytemState.tsx +++ b/webapp_frontend/src/background/redux/actions/sytemState.tsx @@ -1,5 +1,7 @@ import {TokensState} from "./tokenTypes"; +import {UserState} from "./userTypes"; export interface SystemState { tokens: TokensState -} \ No newline at end of file + user: UserState +} diff --git a/webapp_frontend/src/background/redux/actions/tokenTypes.tsx b/webapp_frontend/src/background/redux/actions/tokenTypes.tsx index a4958dac..6a51e3ad 100644 --- a/webapp_frontend/src/background/redux/actions/tokenTypes.tsx +++ b/webapp_frontend/src/background/redux/actions/tokenTypes.tsx @@ -1,8 +1,9 @@ export const ADD_REFRESH_TOKEN = "ADD_REFRESH_TOKEN"; export const ADD_ACCESS_TOKEN = "ADD_ACCESS_TOKEN"; +export const CHECKED_COOKIES = "CHECKED_COOKIES"; -export interface AccessToken{ +export interface AccessToken { token: string | null; timestamp: number | null; } @@ -11,6 +12,7 @@ export interface AccessToken{ export interface TokensState { refreshToken: string | null; accessToken: AccessToken | null; + checkedCookies: boolean; } @@ -24,5 +26,10 @@ interface AddAccessToken { payload: AccessToken } -export type TokenActionsTypes = AddRefreshToken | AddAccessToken; +interface CheckedCookies{ + type: typeof CHECKED_COOKIES, + payload: boolean +} + +export type TokenActionsTypes = AddRefreshToken | AddAccessToken|CheckedCookies; diff --git a/webapp_frontend/src/background/redux/actions/userTypes.tsx b/webapp_frontend/src/background/redux/actions/userTypes.tsx new file mode 100644 index 00000000..572fad35 --- /dev/null +++ b/webapp_frontend/src/background/redux/actions/userTypes.tsx @@ -0,0 +1,17 @@ +export const ADD_USER = "ADD_USER"; + +export interface UserState{ + groups: number[], + id: number, + username:string, +} + + + +interface AddUser { + type: typeof ADD_USER, + payload: UserState +} + + +export type UserActionTypes=AddUser; diff --git a/webapp_frontend/src/background/redux/reducers/tokens.tsx b/webapp_frontend/src/background/redux/reducers/tokens.tsx index 69097ca4..72d2b3f2 100644 --- a/webapp_frontend/src/background/redux/reducers/tokens.tsx +++ b/webapp_frontend/src/background/redux/reducers/tokens.tsx @@ -1,8 +1,9 @@ -import {ADD_REFRESH_TOKEN, ADD_ACCESS_TOKEN, TokenActionsTypes, TokensState, AccessToken} from "../actions/tokenTypes"; +import {ADD_REFRESH_TOKEN, ADD_ACCESS_TOKEN, TokenActionsTypes, TokensState, AccessToken, CHECKED_COOKIES} from "../actions/tokenTypes"; const initialState: TokensState = { refreshToken: null, accessToken: null, + checkedCookies:false, }; export default function (state = initialState, action: TokenActionsTypes) { @@ -11,14 +12,23 @@ export default function (state = initialState, action: TokenActionsTypes) { const refreshToken: string = action.payload; return { refreshToken: refreshToken, - accessToken: initialState.accessToken + accessToken: initialState.accessToken, + checkedCookies: initialState.checkedCookies }; } case ADD_ACCESS_TOKEN: { const accessToken: AccessToken = action.payload; return { refreshToken: initialState.refreshToken, - accessToken: accessToken + accessToken: accessToken, + checkedCookies: initialState.checkedCookies + }; + } + case CHECKED_COOKIES: { + return { + refreshToken: initialState.refreshToken, + accessToken: initialState.refreshToken, + checkedCookies:action.payload }; } default: diff --git a/webapp_frontend/src/background/redux/reducers/user.tsx b/webapp_frontend/src/background/redux/reducers/user.tsx new file mode 100644 index 00000000..10628166 --- /dev/null +++ b/webapp_frontend/src/background/redux/reducers/user.tsx @@ -0,0 +1,17 @@ +import {ADD_USER, UserActionTypes, UserState} from "../actions/userTypes"; + +const initialState: UserState = { + groups: [], id: -1, username: "" + +}; + + +export default function (state = initialState, action: UserActionTypes) { + switch (action.type) { + case ADD_USER: { + return action.payload; + } + default: + return state; + } +} diff --git a/webapp_frontend/src/components/App.tsx b/webapp_frontend/src/components/App.tsx index f640d2b0..6e7f2067 100644 --- a/webapp_frontend/src/components/App.tsx +++ b/webapp_frontend/src/components/App.tsx @@ -16,7 +16,8 @@ import {Button} from "react-bootstrap"; // this takes the redux store and maps everything that is needed to the function props const mapState = (state: SystemState) => ({ - tokens: {refreshToken: state.tokens.refreshToken, accessToken: state.tokens.accessToken} + tokens: {refreshToken: state.tokens.refreshToken, accessToken: state.tokens.accessToken}, + user: state.user }) // this takes the redux actions and maps them to the props From a89964b69c7210ea26584191854b39d712ba7ec3 Mon Sep 17 00:00:00 2001 From: qvalentin Date: Fri, 20 Nov 2020 16:42:22 +0100 Subject: [PATCH 02/10] added basic flow of components --- .../src/background/redux/actions/tokens.tsx | 10 ++++++++-- .../background/redux/actions/userTypes.tsx | 4 ++-- .../src/background/redux/reducers/user.tsx | 2 +- webapp_frontend/src/components/App.tsx | 20 +++++++++++++++---- 4 files changed, 27 insertions(+), 9 deletions(-) diff --git a/webapp_frontend/src/background/redux/actions/tokens.tsx b/webapp_frontend/src/background/redux/actions/tokens.tsx index 219fa52f..e0592c0f 100644 --- a/webapp_frontend/src/background/redux/actions/tokens.tsx +++ b/webapp_frontend/src/background/redux/actions/tokens.tsx @@ -1,4 +1,4 @@ -import {ADD_REFRESH_TOKEN, ADD_ACCESS_TOKEN, AccessToken} from "./tokenTypes"; +import {ADD_REFRESH_TOKEN, ADD_ACCESS_TOKEN, AccessToken, CHECKED_COOKIES} from "./tokenTypes"; export const addRefreshToken = (content: string) => ({ @@ -9,4 +9,10 @@ export const addRefreshToken = (content: string) => ({ export const addAccessToken = (content: AccessToken) => ({ type: ADD_ACCESS_TOKEN, payload: content -}); \ No newline at end of file +}); + + +export const checkedCookies = (content: boolean) => ({ + type: CHECKED_COOKIES, + payload: content +}); diff --git a/webapp_frontend/src/background/redux/actions/userTypes.tsx b/webapp_frontend/src/background/redux/actions/userTypes.tsx index 572fad35..d3691ca3 100644 --- a/webapp_frontend/src/background/redux/actions/userTypes.tsx +++ b/webapp_frontend/src/background/redux/actions/userTypes.tsx @@ -2,8 +2,8 @@ export const ADD_USER = "ADD_USER"; export interface UserState{ groups: number[], - id: number, - username:string, + id: number | null, + username:string | null, } diff --git a/webapp_frontend/src/background/redux/reducers/user.tsx b/webapp_frontend/src/background/redux/reducers/user.tsx index 10628166..3b3e7b05 100644 --- a/webapp_frontend/src/background/redux/reducers/user.tsx +++ b/webapp_frontend/src/background/redux/reducers/user.tsx @@ -1,7 +1,7 @@ import {ADD_USER, UserActionTypes, UserState} from "../actions/userTypes"; const initialState: UserState = { - groups: [], id: -1, username: "" + groups: [], id: null, username: null }; diff --git a/webapp_frontend/src/components/App.tsx b/webapp_frontend/src/components/App.tsx index 6e7f2067..9feac3c9 100644 --- a/webapp_frontend/src/components/App.tsx +++ b/webapp_frontend/src/components/App.tsx @@ -9,20 +9,21 @@ import PermanentAssets from "./basicElements/PermanentAssets"; import {connect, ConnectedProps} from 'react-redux' -import {addAccessToken, addRefreshToken} from "../background/redux/actions/tokens"; +import {addAccessToken, addRefreshToken,checkedCookies} from "../background/redux/actions/tokens"; import {SystemState} from "../background/redux/actions/sytemState"; import {Button} from "react-bootstrap"; +import Login from "./basicElements/Login"; // this takes the redux store and maps everything that is needed to the function props const mapState = (state: SystemState) => ({ - tokens: {refreshToken: state.tokens.refreshToken, accessToken: state.tokens.accessToken}, + tokens: {refreshToken: state.tokens.refreshToken, accessToken: state.tokens.accessToken,checkedCookies:state.tokens.checkedCookies}, user: state.user }) // this takes the redux actions and maps them to the props const mapDispatch = { - addRefreshToken, addAccessToken + addRefreshToken, addAccessToken,checkedCookies } const connector = connect(mapState, mapDispatch) @@ -38,6 +39,9 @@ function App(props: Props): ReactElement { console.log(props.tokens.refreshToken) console.log(props.tokens) +if (props.tokens.checkedCookies){ + + if (props.tokens.refreshToken){ return (
@@ -50,7 +54,15 @@ function App(props: Props): ReactElement {
- ); + );} + + else return () +} + else { + props.checkedCookies(true) + + return (
Loading
) +} } export default connector(App); From ee85e9f72f2f25288fade182c19acd65e488c7e1 Mon Sep 17 00:00:00 2001 From: qvalentin Date: Fri, 20 Nov 2020 18:22:35 +0100 Subject: [PATCH 03/10] added basic ui for login and hooked up checkbox --- .../src/components/basicElements/Login.tsx | 39 +++++++++++++++++-- webapp_frontend/src/style/custom.scss | 3 +- 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/webapp_frontend/src/components/basicElements/Login.tsx b/webapp_frontend/src/components/basicElements/Login.tsx index 2aa9c86b..9ba63059 100644 --- a/webapp_frontend/src/components/basicElements/Login.tsx +++ b/webapp_frontend/src/components/basicElements/Login.tsx @@ -1,6 +1,39 @@ -import React, {ReactElement} from 'react'; +import React, {ReactElement, useState} from 'react'; +import {Button, Form, Container} from "react-bootstrap"; -export default function Login():ReactElement { - return(
hallo
); + +type Props = {} + +export default function Login(props: Props): ReactElement { + const [userName, SetUsername] = useState(""); + const [password, setPassword] = useState(""); + const [stayLoggedIn,setStayLoggedIn] =useState(false); + + + + + return ( + +
+ + Email address + + + We'll never share your email with anyone else. + + + + + Password + + + + setStayLoggedIn(!stayLoggedIn)}/> + + +
+
); } diff --git a/webapp_frontend/src/style/custom.scss b/webapp_frontend/src/style/custom.scss index 2e592e92..6fdb2183 100644 --- a/webapp_frontend/src/style/custom.scss +++ b/webapp_frontend/src/style/custom.scss @@ -21,4 +21,5 @@ $blue: #1a4965; @import "~bootstrap/scss/grid"; @import "~bootstrap/scss/buttons"; @import "~bootstrap/scss/tables"; -@import "~bootstrap/scss/utilities"; \ No newline at end of file +@import "~bootstrap/scss/utilities"; +@import "~bootstrap/scss/forms"; From 8bc459eb25a7dad58e62de017074093e5df981e2 Mon Sep 17 00:00:00 2001 From: qvalentin Date: Sat, 21 Nov 2020 17:14:21 +0100 Subject: [PATCH 04/10] =?UTF-8?q?can=E2=80=99t=20believe=20that=20I=20wrot?= =?UTF-8?q?e=20this=20on=20paper?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- webapp_frontend/src/background/api/api.ts | 4 +- webapp_frontend/src/background/api/login.ts | 38 +++++++++++++- webapp_frontend/src/background/constants.tsx | 4 +- .../src/background/redux/actions/user.tsx | 7 +++ .../background/redux/actions/userTypes.tsx | 1 + .../src/background/redux/reducers/tokens.tsx | 13 ++--- webapp_frontend/src/components/App.tsx | 5 +- .../src/components/basicElements/Login.tsx | 49 +++++++++++++++---- 8 files changed, 99 insertions(+), 22 deletions(-) create mode 100644 webapp_frontend/src/background/redux/actions/user.tsx diff --git a/webapp_frontend/src/background/api/api.ts b/webapp_frontend/src/background/api/api.ts index 196f0c5c..2d156f5e 100644 --- a/webapp_frontend/src/background/api/api.ts +++ b/webapp_frontend/src/background/api/api.ts @@ -3,6 +3,8 @@ import {constants} from "../constants"; export const hostname:string =constants.url.API_URL+'/api'; +export const userPath:string='/v1/users'; + interface BackendHealthData { uptimeInSeconds: number; @@ -21,4 +23,4 @@ function callBackendHealth():Promise{ }); } -export { callBackendHealth} \ No newline at end of file +export { callBackendHealth} diff --git a/webapp_frontend/src/background/api/login.ts b/webapp_frontend/src/background/api/login.ts index 92bbd6a2..3fd40745 100644 --- a/webapp_frontend/src/background/api/login.ts +++ b/webapp_frontend/src/background/api/login.ts @@ -1,7 +1,41 @@ +import Axios from "axios"; +import {constants} from "../constants"; +import {hostname, userPath} from "./api"; +import {addRefreshToken} from "../redux/actions/tokens"; +import {UserState} from "../redux/actions/userTypes"; -function test(){ + +function test() { return null } -export default test; \ No newline at end of file +export interface BackendLoginData { + refreshToken: string, + user: UserState + +} + +export const loginWithUsernameAndPassword = (userName: string, password: string): Promise => { + + return new Promise((resolve, reject) => { + let config = { + headers: { + Authorization: `Basic ${btoa(userName + ':' + password)}`, + }, + }; + + return Axios.get(hostname + userPath + '/login', config) + .then((data) => { + resolve(data.data) + console.log(data.data) + }) + .catch(((error) => { + reject(error); + })); + }) + + +} + +export default test; diff --git a/webapp_frontend/src/background/constants.tsx b/webapp_frontend/src/background/constants.tsx index 1de2e26d..0d9a78d0 100644 --- a/webapp_frontend/src/background/constants.tsx +++ b/webapp_frontend/src/background/constants.tsx @@ -11,7 +11,7 @@ const prod: constants = { const dev: constants = { url: { - API_URL: 'http://filefighter.ddns.net:3001', + API_URL: 'https://cors-anywhere.herokuapp.com/http://filefighter.ddns.net:3001', } }; -export const constants = process.env.NODE_ENV === 'development' ? dev : prod; \ No newline at end of file +export const constants = process.env.NODE_ENV === 'development' ? dev : prod; diff --git a/webapp_frontend/src/background/redux/actions/user.tsx b/webapp_frontend/src/background/redux/actions/user.tsx new file mode 100644 index 00000000..e7e74bfd --- /dev/null +++ b/webapp_frontend/src/background/redux/actions/user.tsx @@ -0,0 +1,7 @@ + +import {ADD_USER, UserState} from "./userTypes"; + +export const addUser = (content: UserState) => ({ + type: ADD_USER, + payload: content +}); diff --git a/webapp_frontend/src/background/redux/actions/userTypes.tsx b/webapp_frontend/src/background/redux/actions/userTypes.tsx index d3691ca3..be74d9b2 100644 --- a/webapp_frontend/src/background/redux/actions/userTypes.tsx +++ b/webapp_frontend/src/background/redux/actions/userTypes.tsx @@ -14,4 +14,5 @@ interface AddUser { } + export type UserActionTypes=AddUser; diff --git a/webapp_frontend/src/background/redux/reducers/tokens.tsx b/webapp_frontend/src/background/redux/reducers/tokens.tsx index 72d2b3f2..16973f43 100644 --- a/webapp_frontend/src/background/redux/reducers/tokens.tsx +++ b/webapp_frontend/src/background/redux/reducers/tokens.tsx @@ -9,25 +9,26 @@ const initialState: TokensState = { export default function (state = initialState, action: TokenActionsTypes) { switch (action.type) { case ADD_REFRESH_TOKEN: { + console.log('[Redux] adding refreshToken') const refreshToken: string = action.payload; return { refreshToken: refreshToken, - accessToken: initialState.accessToken, - checkedCookies: initialState.checkedCookies + accessToken: state.accessToken, + checkedCookies: state.checkedCookies }; } case ADD_ACCESS_TOKEN: { const accessToken: AccessToken = action.payload; return { - refreshToken: initialState.refreshToken, + refreshToken: state.refreshToken, accessToken: accessToken, - checkedCookies: initialState.checkedCookies + checkedCookies: state.checkedCookies }; } case CHECKED_COOKIES: { return { - refreshToken: initialState.refreshToken, - accessToken: initialState.refreshToken, + refreshToken: state.refreshToken, + accessToken: state.refreshToken, checkedCookies:action.payload }; } diff --git a/webapp_frontend/src/components/App.tsx b/webapp_frontend/src/components/App.tsx index 9feac3c9..75af050f 100644 --- a/webapp_frontend/src/components/App.tsx +++ b/webapp_frontend/src/components/App.tsx @@ -56,7 +56,10 @@ if (props.tokens.checkedCookies){ );} - else return () + else { + console.log("[APP] showing login"); + return () + } } else { props.checkedCookies(true) diff --git a/webapp_frontend/src/components/basicElements/Login.tsx b/webapp_frontend/src/components/basicElements/Login.tsx index 9ba63059..a28a006b 100644 --- a/webapp_frontend/src/components/basicElements/Login.tsx +++ b/webapp_frontend/src/components/basicElements/Login.tsx @@ -1,23 +1,51 @@ -import React, {ReactElement, useState} from 'react'; +import React, {FormEvent, ReactElement, useState} from 'react'; import {Button, Form, Container} from "react-bootstrap"; +import user from "../../background/redux/reducers/user"; +import {loginWithUsernameAndPassword} from "../../background/api/login"; +import {addAccessToken, addRefreshToken, checkedCookies} from "../../background/redux/actions/tokens"; +import {connect, ConnectedProps} from "react-redux"; +import {SystemState} from "../../background/redux/actions/sytemState"; +import {addUser} from "../../background/redux/actions/user"; +//why is this needed? because connect needs this? +const mapState = (state: SystemState) => ({}) -type Props = {} +const mapDispatch = { + addRefreshToken, + addUser +} + +const connector = connect(mapState, mapDispatch) + +type PropsFromRedux = ConnectedProps -export default function Login(props: Props): ReactElement { - const [userName, SetUsername] = useState(""); +// this defines the component props and also adds the redux imported props +type Props = PropsFromRedux & {} + + +function Login(props: Props): ReactElement { + const [userName, setUsername] = useState(""); const [password, setPassword] = useState(""); - const [stayLoggedIn,setStayLoggedIn] =useState(false); + const [stayLoggedIn, setStayLoggedIn] = useState(false); + + const handleSubmit = (event: FormEvent) => { + event.preventDefault(); + loginWithUsernameAndPassword(userName, password) + .then(backendLoginData => { + props.addRefreshToken(backendLoginData.refreshToken); + props.addUser(backendLoginData.user) + }); + }; return ( -
+ - Email address - + Username + setUsername(event.target.value)}/> We'll never share your email with anyone else. @@ -25,10 +53,10 @@ export default function Login(props: Props): ReactElement { Password - + setPassword(event.target.value)}/> - setStayLoggedIn(!stayLoggedIn)}/> + setStayLoggedIn(!stayLoggedIn)}/> - + + +
+ + Username + setUsername(event.target.value)}/> + + + + Password + setPassword(event.target.value)}/> + + Contact your administrator if you have forgotten your password. + + + + setStayLoggedIn(!stayLoggedIn)}/> + + +

{errorMessage}

+
+ +
); } From f3ba20645669f505d614e32b5fdecaf4d881ccd1 Mon Sep 17 00:00:00 2001 From: qvalentin Date: Sun, 22 Nov 2020 12:43:23 +0100 Subject: [PATCH 10/10] fixed ts errors --- webapp_frontend/src/background/api/auth.ts | 25 +++++++------------ .../background/redux/actions/tokenTypes.tsx | 6 ++--- .../background/redux/actions/userTypes.tsx | 2 +- 3 files changed, 13 insertions(+), 20 deletions(-) diff --git a/webapp_frontend/src/background/api/auth.ts b/webapp_frontend/src/background/api/auth.ts index 321ebdd9..6bb3fbdb 100644 --- a/webapp_frontend/src/background/api/auth.ts +++ b/webapp_frontend/src/background/api/auth.ts @@ -3,10 +3,11 @@ import Axios from "axios"; import {hostname, userPath} from "./api"; -import {UserState} from "../redux/actions/userTypes"; +import {AddUser, UserState} from "../redux/actions/userTypes"; import store from "../redux/store"; import {addAccessToken, addRefreshToken} from "../redux/actions/tokens"; import {addUser} from "../redux/actions/user"; +import {AccessToken, AddAccessToken, AddRefreshToken, TokensState} from "../redux/actions/tokenTypes"; // reference: https://daveceddia.com/access-redux-store-outside-react/ @@ -28,11 +29,9 @@ export const loginWithUsernameAndPassword = (userName: string, password: string) return Axios.get(hostname + userPath + '/login', config) .then((data) => { - // @ts-ignore - store.dispatch(addRefreshToken(data.data.refreshToken)) - // @ts-ignore - store.dispatch(addUser(data.data.user)) - // resolve(data.data) + store.dispatch(addRefreshToken(data.data.refreshToken) as AddRefreshToken) + store.dispatch(addUser(data.data.user as UserState) as AddUser) + getAccessTokenWithRefreshToken() }) .catch(((error) => { @@ -44,17 +43,11 @@ export const loginWithUsernameAndPassword = (userName: string, password: string) }) } -/*export interface BackendAuthData { - token: string, - userId: number, - validUntil: number -}*/ - export const getAccessTokenWithRefreshToken = () => { console.log("getAccessTokenWithRefreshToken") - // @ts-ignore - let refreshToken: string = store.getState().tokens.refreshToken; + + let refreshToken: string|null = (store.getState().tokens as TokensState).refreshToken; let config = { headers: { @@ -65,8 +58,8 @@ export const getAccessTokenWithRefreshToken = () => { Axios.get(hostname + userPath + '/auth', config) .then((data) => { setAuthHeaderToAxios(data.data.token) - // @ts-ignore - store.dispatch(addAccessToken({token: data.data.token, timestamp: data.data.validUntil})) + + store.dispatch(addAccessToken({token: data.data.token, timestamp: data.data.validUntil}as AccessToken) as AddAccessToken); }) .catch(((error) => { diff --git a/webapp_frontend/src/background/redux/actions/tokenTypes.tsx b/webapp_frontend/src/background/redux/actions/tokenTypes.tsx index 6a51e3ad..dc4bbe08 100644 --- a/webapp_frontend/src/background/redux/actions/tokenTypes.tsx +++ b/webapp_frontend/src/background/redux/actions/tokenTypes.tsx @@ -16,17 +16,17 @@ export interface TokensState { } -interface AddRefreshToken { +export interface AddRefreshToken { type: typeof ADD_REFRESH_TOKEN payload: string } -interface AddAccessToken { +export interface AddAccessToken { type: typeof ADD_ACCESS_TOKEN payload: AccessToken } -interface CheckedCookies{ +export interface CheckedCookies{ type: typeof CHECKED_COOKIES, payload: boolean } diff --git a/webapp_frontend/src/background/redux/actions/userTypes.tsx b/webapp_frontend/src/background/redux/actions/userTypes.tsx index 14532a47..43b2ade9 100644 --- a/webapp_frontend/src/background/redux/actions/userTypes.tsx +++ b/webapp_frontend/src/background/redux/actions/userTypes.tsx @@ -9,7 +9,7 @@ export interface UserState { } -interface AddUser { +export interface AddUser { type: typeof ADD_USER, payload: UserState }