Skip to content

Commit

Permalink
Added auth form. Added login and logout actions
Browse files Browse the repository at this point in the history
  • Loading branch information
pawelmalak committed Nov 10, 2021
1 parent f5ed854 commit e4690d5
Show file tree
Hide file tree
Showing 11 changed files with 199 additions and 31 deletions.
2 changes: 1 addition & 1 deletion client/src/components/Apps/AppForm/AppForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ export const AppForm = ({ app, modalHandler }: Props): JSX.Element => {
onChange={(e) => inputChangeHandler(e)}
/>
<span>
Use icon name from MDI.
Use icon name from MDI or pass a valid URL.
<a href="https://materialdesignicons.com/" target="blank">
{' '}
Click here for reference
Expand Down
2 changes: 1 addition & 1 deletion client/src/components/Bookmarks/Form/BookmarksForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ export const BookmarksForm = ({
onChange={(e) => inputChangeHandler(e)}
/>
<span>
Use icon name from MDI.
Use icon name from MDI or pass a valid URL.
<a href="https://materialdesignicons.com/" target="blank">
{' '}
Click here for reference
Expand Down
12 changes: 9 additions & 3 deletions client/src/components/Settings/AppDetails/AppDetails.module.css
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
.AppVersion {
.text {
color: var(--color-primary);
margin-bottom: 15px;
}

.AppVersion a {
.text a,
.text span {
color: var(--color-accent);
}
}

.separator {
margin: 30px 0;
border: 1px solid var(--color-primary);
}
113 changes: 90 additions & 23 deletions client/src/components/Settings/AppDetails/AppDetails.tsx
Original file line number Diff line number Diff line change
@@ -1,33 +1,100 @@
import { Fragment } from 'react';
import { FormEvent, Fragment, useState } from 'react';

// Redux
import { useDispatch, useSelector } from 'react-redux';
import { bindActionCreators } from 'redux';
import { actionCreators } from '../../../store';
import { State } from '../../../store/reducers';

// UI
import { Button, InputGroup, SettingsHeadline } from '../../UI';

// CSS
import classes from './AppDetails.module.css';
import { Button } from '../../UI';

// Utils
import { checkVersion } from '../../../utility';

export const AppDetails = (): JSX.Element => {
const { isAuthenticated } = useSelector((state: State) => state.auth);

const dispatch = useDispatch();
const { login, logout } = bindActionCreators(actionCreators, dispatch);

const [password, setPassword] = useState('');

const formHandler = (e: FormEvent) => {
e.preventDefault();
login(password);
setPassword('');
};

return (
<Fragment>
<p className={classes.AppVersion}>
<a
href="https://github.com/pawelmalak/flame"
target="_blank"
rel="noreferrer"
>
Flame
</a>{' '}
version {process.env.REACT_APP_VERSION}
</p>
<p className={classes.AppVersion}>
See changelog{' '}
<a
href="https://github.com/pawelmalak/flame/blob/master/CHANGELOG.md"
target="_blank"
rel="noreferrer"
>
here
</a>
</p>
<Button click={() => checkVersion(true)}>Check for updates</Button>
<SettingsHeadline text="Authentication" />
{!isAuthenticated ? (
<form onSubmit={formHandler}>
<InputGroup>
<label htmlFor="password">Password</label>
<input
type="password"
id="password"
name="password"
placeholder="••••••"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
<span>
See
<a
href="https://github.com/pawelmalak/flame/wiki/Authentication"
target="blank"
>
{` project wiki `}
</a>
to read more about authentication
</span>
</InputGroup>

<Button>Login</Button>
</form>
) : (
<div>
<p className={classes.text}>
You are logged in. Your session will expire <span>@@@@</span>
</p>
<Button click={logout}>Logout</Button>
</div>
)}

<hr className={classes.separator} />

<div>
<SettingsHeadline text="App version" />
<p className={classes.text}>
<a
href="https://github.com/pawelmalak/flame"
target="_blank"
rel="noreferrer"
>
Flame
</a>{' '}
version {process.env.REACT_APP_VERSION}
</p>

<p className={classes.text}>
See changelog{' '}
<a
href="https://github.com/pawelmalak/flame/blob/master/CHANGELOG.md"
target="_blank"
rel="noreferrer"
>
here
</a>
</p>

<Button click={() => checkVersion(true)}>Check for updates</Button>
</div>
</Fragment>
);
};
40 changes: 40 additions & 0 deletions client/src/store/action-creators/auth.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { Dispatch } from 'redux';
import { ApiResponse } from '../../interfaces';
import { ActionType } from '../action-types';
import { LoginAction, LogoutAction } from '../actions/auth';
import axios, { AxiosError } from 'axios';

export const login =
(password: string) => async (dispatch: Dispatch<LoginAction>) => {
try {
const res = await axios.post<ApiResponse<{ token: string }>>(
'/api/auth',
{ password }
);

localStorage.setItem('token', res.data.data.token);

dispatch({
type: ActionType.login,
payload: res.data.data.token,
});
} catch (err) {
const apiError = err as AxiosError;

dispatch<any>({
type: ActionType.createNotification,
payload: {
title: 'Error',
message: apiError.response?.data.error,
},
});
}
};

export const logout = () => (dispatch: Dispatch<LogoutAction>) => {
localStorage.removeItem('token');

dispatch({
type: ActionType.logout,
});
};
1 change: 1 addition & 0 deletions client/src/store/action-creators/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ export * from './config';
export * from './notification';
export * from './app';
export * from './bookmark';
export * from './auth';
3 changes: 3 additions & 0 deletions client/src/store/action-types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,7 @@ export enum ActionType {
addBookmark = 'ADD_BOOKMARK',
deleteBookmark = 'DELETE_BOOKMARK',
updateBookmark = 'UPDATE_BOOKMARK',
// AUTH
login = 'LOGIN',
logout = 'LOGOUT',
}
10 changes: 10 additions & 0 deletions client/src/store/actions/auth.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { ActionType } from '../action-types';

export interface LoginAction {
type: ActionType.login;
payload: string;
}

export interface LogoutAction {
type: ActionType.logout;
}
11 changes: 8 additions & 3 deletions client/src/store/actions/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { App } from '../../interfaces';

import { SetThemeAction } from './theme';

import {
Expand All @@ -24,8 +26,6 @@ import {
SortAppsAction,
} from './app';

import { App } from '../../interfaces';

import {
GetCategoriesAction,
AddCategoryAction,
Expand All @@ -39,6 +39,8 @@ import {
UpdateBookmarkAction,
} from './bookmark';

import { LoginAction, LogoutAction } from './auth';

export type Action =
// Theme
| SetThemeAction
Expand Down Expand Up @@ -71,4 +73,7 @@ export type Action =
// Bookmarks
| AddBookmarkAction
| DeleteBookmarkAction
| UpdateBookmarkAction;
| UpdateBookmarkAction
// Auth
| LoginAction
| LogoutAction;
34 changes: 34 additions & 0 deletions client/src/store/reducers/auth.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { Action } from '../actions';
import { ActionType } from '../action-types';

interface AuthState {
isAuthenticated: boolean;
token: string | null;
}

const initialState: AuthState = {
isAuthenticated: false,
token: null,
};

export const authReducer = (
state: AuthState = initialState,
action: Action
): AuthState => {
switch (action.type) {
case ActionType.login:
return {
...state,
token: action.payload,
isAuthenticated: true,
};
case ActionType.logout:
return {
...state,
token: null,
isAuthenticated: false,
};
default:
return state;
}
};
2 changes: 2 additions & 0 deletions client/src/store/reducers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ import { configReducer } from './config';
import { notificationReducer } from './notification';
import { appsReducer } from './app';
import { bookmarksReducer } from './bookmark';
import { authReducer } from './auth';

export const reducers = combineReducers({
theme: themeReducer,
config: configReducer,
notification: notificationReducer,
apps: appsReducer,
bookmarks: bookmarksReducer,
auth: authReducer,
});

export type State = ReturnType<typeof reducers>;

0 comments on commit e4690d5

Please sign in to comment.