Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,559 changes: 732 additions & 827 deletions package-lock.json

Large diffs are not rendered by default.

12 changes: 9 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,24 @@
"@types/node": "^12.19.1",
"@types/react-dom": "^16.9.8",
"@types/react-helmet": "^6.0.0",
"@types/react-redux": "^7.1.11",
"@types/react-router-dom": "^5.1.5",
"@types/uuid": "^8.3.0",
"@types/styled-components": "^5.1.4",
"antd": "^4.6.6",
"axios": "^0.19.2",
"craco-antd": "^1.19.0",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"react-helmet": "^6.1.0",
"react-redux": "^7.2.0",
"react-redux": "^7.2.2",
"react-router-dom": "^5.2.0",
"react-scripts": "^3.4.3",
"styled-components": "^5.2.1",
"typescript": "^3.7.5"
"redux": "^4.0.5",
"redux-thunk": "^2.3.0",
"typescript": "^3.7.5",
"uuid": "^8.3.1",
"styled-components": "^5.2.1"
},
"scripts": {
"start": "nodemon -w craco.config.js -w ./antd.customize.less --exec \"craco start\"",
Expand Down Expand Up @@ -64,6 +69,7 @@
"eslint-config-prettier": "^6.11.0",
"eslint-config-react": "^1.1.7",
"eslint-plugin-prettier": "^3.1.4",
"nock": "^13.0.4",
"prettier": "^2.1.2",
"redux-devtools": "^3.5.0",
"tslint": "^6.1.3",
Expand Down
83 changes: 0 additions & 83 deletions src/auth/authAPI.tsx

This file was deleted.

70 changes: 70 additions & 0 deletions src/auth/authClient.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import {
TokenPayload,
LoginRequest,
SignupRequest,
RefreshTokenResponse,
} from './ducks/types';
import axios, { AxiosInstance } from 'axios';

export interface AuthClient {
login: (user: LoginRequest) => Promise<TokenPayload>;
signup: (user: SignupRequest) => Promise<TokenPayload>;
logout: (refreshToken: string) => Promise<void>;
refresh: (refreshToken: string) => Promise<RefreshTokenResponse>;
}

export enum API_ROUTE {
LOGIN = '/api/v1/user/login/',
SIGNUP = '/api/v1/user/signup/',
REFRESH = '/api/v1/user/login/refresh/',
}

const AuthAxiosInstance: AxiosInstance = axios.create({
baseURL: process.env.REACT_APP_API_DOMAIN,
timeout: 10000,
headers: {
'Content-Type': 'application/json',
},
});

const login: (user: LoginRequest) => Promise<TokenPayload> = (
user: LoginRequest,
) =>
AuthAxiosInstance.post(API_ROUTE.LOGIN, user).then(
(response) => response.data,
);

const signup: (user: SignupRequest) => Promise<TokenPayload> = (
user: SignupRequest,
) =>
AuthAxiosInstance.post(API_ROUTE.SIGNUP, user).then(
(response) => response.data,
);

const logout: (refreshToken: string) => Promise<void> = (
refreshToken: string,
) =>
AuthAxiosInstance.delete(API_ROUTE.LOGIN, {
headers: {
'X-Refresh-Token': refreshToken,
},
// eslint-disable-next-line
}).then(() => {});

const refresh: (refreshToken: string) => Promise<RefreshTokenResponse> = (
refreshToken: string,
) =>
AuthAxiosInstance.post(API_ROUTE.REFRESH, null, {
headers: {
'X-Refresh-Token': refreshToken,
},
}).then((response) => response.data);

const Client: AuthClient = Object.freeze({
login,
signup,
logout,
refresh,
});

export default Client;
16 changes: 0 additions & 16 deletions src/auth/axios.test.tsx

This file was deleted.

47 changes: 47 additions & 0 deletions src/auth/axios.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import axios, { AxiosInstance } from 'axios';
import store, { C4CState } from '../store';
import { AsyncRequestKinds } from '../utils/asyncRequest';

const AppAxiosInstance: AxiosInstance = axios.create({
baseURL: process.env.REACT_APP_API_DOMAIN,
timeout: 10000,
headers: {
'Content-Type': 'application/json',
},
});

const listener = () => {
const state: C4CState = store.getState();
if (state.authenticationState.tokens.kind === AsyncRequestKinds.Completed) {
AppAxiosInstance.defaults.headers['X-Access-Token'] =
state.authenticationState.tokens.result.accessToken;
}
};

store.subscribe(listener);

// const responseErrorInterceptor: (error: AxiosError) => void = (error) => {
// // const originalRequest = error.config;
// if (
// error.code === '401' &&
// error.message === INVALID_ACCESS_TOKEN &&
// tokenService.isRefreshTokenValid()
// ) {
// // return refresh().then(() => {
// // Instance.defaults.headers[
// // 'X-Access-Token'
// // ] = tokenService.getAccessToken();
// // return Instance(originalRequest);
// // });
// }
// if (
// error.code === '401' &&
// error.message === INVALID_ACCESS_TOKEN &&
// !tokenService.isRefreshTokenValid()
// ) {
// // logout();
// }
// return Promise.reject(error);
// };

export default AppAxiosInstance;
54 changes: 0 additions & 54 deletions src/auth/axios.tsx

This file was deleted.

14 changes: 14 additions & 0 deletions src/auth/ducks/actions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { genericAsyncActions } from '../../utils/asyncRequest';
import { TokenPayload } from './types';

export const authenticateUser = genericAsyncActions<TokenPayload, any>();

export const logoutUser = genericAsyncActions<void, void>();

export type UserAuthenticationActions =
| ReturnType<typeof authenticateUser.loading>
| ReturnType<typeof authenticateUser.loaded>
| ReturnType<typeof authenticateUser.failed>
| ReturnType<typeof logoutUser.loading>
| ReturnType<typeof logoutUser.loaded>
| ReturnType<typeof logoutUser.failed>;
39 changes: 39 additions & 0 deletions src/auth/ducks/reducers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { TokenPayload, UserAuthenticationReducerState } from './types';
import { authenticateUser } from './actions';
import { C4CAction } from '../../store';
import {
ASYNC_REQUEST_FAILED_ACTION,
ASYNC_REQUEST_LOADED_ACTION,
ASYNC_REQUEST_LOADING_ACTION,
AsyncRequestNotStarted,
generateAsyncRequestReducer,
} from '../../utils/asyncRequest';

export const initialUserState: UserAuthenticationReducerState = {
tokens: AsyncRequestNotStarted<TokenPayload, any>(),
};

const userAuthenticationRequestReducer = generateAsyncRequestReducer<
UserAuthenticationReducerState,
TokenPayload,
void
>(authenticateUser.key);

const reducers = (
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this the top level reducer? If so, would all API calls that get data have to be included in this down the line?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Everything in this auth/ducks/ folder will be solely for authentication-related data and actions. Each container typically will have its own ducks. The reducers, along with the action types, are combined in store.ts.

state: UserAuthenticationReducerState = initialUserState,
action: C4CAction,
): UserAuthenticationReducerState => {
switch (action.type) {
case ASYNC_REQUEST_LOADING_ACTION:
case ASYNC_REQUEST_LOADED_ACTION:
case ASYNC_REQUEST_FAILED_ACTION:
return {
...state,
tokens: userAuthenticationRequestReducer(state.tokens, action),
};
default:
return state;
}
};

export default reducers;
12 changes: 12 additions & 0 deletions src/auth/ducks/selectors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { PrivilegeLevel, TokenPayload } from './types';
import { AsyncRequest, AsyncRequestKinds } from '../../utils/asyncRequest';

export const getPrivilegeLevel = (
tokens: AsyncRequest<TokenPayload, any>,
): PrivilegeLevel => {
if (tokens.kind === AsyncRequestKinds.Completed) {
const payload = JSON.parse(atob(tokens.result.accessToken.split('.')[1]));
return payload.privilegeLevel;
}
return PrivilegeLevel.NONE;
};
Loading