Skip to content
This repository was archived by the owner on Dec 9, 2021. It is now read-only.

Commit e20087a

Browse files
committed
add UserService
1 parent c4def46 commit e20087a

18 files changed

+173
-135
lines changed

package.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
"buildServer": "tsc -project tsconfig.server.json",
1212
"watchServer": "tsc -watch -project tsconfig.server.json",
1313
"removeAndBuildServer": "npm run clean && npm run buildServer",
14-
"prestart": "npm run prod:build",
14+
"build": "npm run prod:build",
1515
"start": "cross-env NODE_ENV=production node ./dist/server.js",
1616
"---------- DEVELOPMENT -------------------------------------------------------------------------": "",
1717
"predev": "npm run removeAndBuildServer",
@@ -61,6 +61,7 @@
6161
"@babel/preset-env": "7.1.6",
6262
"@babel/preset-react": "7.0.0",
6363
"@babel/preset-typescript": "7.1.0",
64+
"@types/axios": "0.14.0",
6465
"@types/classnames": "2.2.6",
6566
"@types/hapi": "17.6.3",
6667
"@types/inert": "5.1.2",
@@ -107,6 +108,7 @@
107108
"write-file-webpack-plugin": "4.4.1"
108109
},
109110
"dependencies": {
111+
"axios": "0.18.0",
110112
"babel-polyfill": "6.26.0",
111113
"bootstrap": "4.1.3",
112114
"classnames": "2.2.6",

src/constants/RequestMethodEnum.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
enum RequestMethodEnum {
2-
GET = 'GET',
3-
POST = 'POST',
4-
PUT = 'PUT',
5-
PATCH = 'PATCH',
6-
DELETE = 'DELETE',
2+
Get = 'GET',
3+
Post = 'POST',
4+
Put = 'PUT',
5+
Patch = 'PATCH',
6+
Delete = 'DELETE',
77
}
88

99
export default RequestMethodEnum;

src/server/controllers/AssetsController.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ export default class AssetsController implements IController {
77

88
public mapRoutes(server: Hapi.Server): void {
99
server.route({
10-
method: RequestMethodEnum.GET,
10+
method: RequestMethodEnum.Get,
1111
path: '/assets/{file*}',
1212
handler: (request: Hapi.Request, h: Hapi.ResponseToolkit): Hapi.ResponseObject => {
1313
return h.file(path.resolve(__dirname, `../../public${request.path}`));

src/server/controllers/ReactController.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ export default class ReactController implements IController {
2121

2222
public mapRoutes(server: Hapi.Server): void {
2323
server.route({
24-
method: RequestMethodEnum.GET,
24+
method: RequestMethodEnum.Get,
2525
path: '/{route*}',
2626
handler: async (request: Hapi.Request, h: Hapi.ResponseToolkit): Promise<Hapi.ResponseObject> => {
2727
let initialState: Partial<IStore> = {renderReducer: this._getRenderReducer(request)};

src/stores/IStore.ts

-2
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
11
import {RouterState} from 'connected-react-router';
22
import {Store} from 'redux';
33
import {FormReducer} from 'redux-form';
4-
import ILoadingReducerState from './loading/ILoadingReducerState';
54
import IMetaReducerState from './meta/IMetaReducerState';
65
import IUserReducerState from './user/IUserReducerState';
76
import IRenderReducerState from './render/IRenderReducerState';
87
import IModalReducerState from './modal/IModalReducerState';
98

109
export default interface IStore extends Store<IStore> {
1110
readonly form: FormReducer;
12-
readonly loadingReducer: ILoadingReducerState;
1311
readonly metaReducer: IMetaReducerState;
1412
readonly modalReducer: IModalReducerState;
1513
readonly renderReducer: IRenderReducerState;

src/stores/loading/ILoadingReducerState.ts

-3
This file was deleted.

src/stores/loading/LoadingAction.ts

-14
This file was deleted.

src/stores/loading/LoadingReducer.ts

-27
This file was deleted.

src/stores/rootReducer.ts

-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import {combineReducers, Reducer, ReducersMapObject} from 'redux';
22
import {connectRouter} from 'connected-react-router';
33
import UserReducer from './user/UserReducer';
4-
import LoadingReducer from './loading/LoadingReducer';
54
import MetaReducer from './meta/MetaReducer';
65
import {reducer as formReducer} from 'redux-form';
76
import RenderReducer from './render/RenderReducer';
@@ -12,7 +11,6 @@ import {History} from 'history';
1211
export default (history: History): Reducer<IStore> => {
1312
const reducerMap: ReducersMapObject = {
1413
form: formReducer,
15-
loadingReducer: LoadingReducer.reducer,
1614
metaReducer: MetaReducer.reducer,
1715
modalReducer: ModalReducer.reducer,
1816
renderReducer: RenderReducer.reducer,

src/stores/user/IUserReducerState.ts

+4-17
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,6 @@
1+
import IUser from './models/IUser';
2+
13
export default interface IUserReducerState {
2-
readonly name: {
3-
title: string;
4-
first: string;
5-
last: string;
6-
};
7-
readonly email: string;
8-
readonly dob: string;
9-
readonly phone: string;
10-
readonly id: {
11-
name: string;
12-
value: string;
13-
};
14-
readonly picture: {
15-
large: string;
16-
medium: string;
17-
thumbnail: string;
18-
};
4+
readonly currentUser: IUser;
5+
readonly isLoadingUser: boolean;
196
}

src/stores/user/UserAction.ts

+8-1
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,22 @@
11
import IAction from '../IAction';
2+
import IUser from './models/IUser';
23

34
export default class UserAction {
45

56
public static readonly LOAD_USER: string = 'UserAction.LOAD_USER';
67
public static readonly LOAD_USER_SUCCESS: string = 'UserAction.LOAD_USER_SUCCESS';
7-
public static readonly LOAD_USER_FAIL: string = 'UserAction.LOAD_USER_FAIL';
88

99
public static loadUser(): IAction<void> {
1010
return {
1111
type: UserAction.LOAD_USER,
1212
};
1313
}
1414

15+
public static loadUserSuccess(model: IUser): IAction<IUser> {
16+
return {
17+
payload: model,
18+
type: UserAction.LOAD_USER_SUCCESS,
19+
};
20+
}
21+
1522
}

src/stores/user/UserReducer.ts

+16-20
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,38 @@
11
import UserAction from './UserAction';
22
import IUserReducerState from './IUserReducerState';
33
import IAction from '../IAction';
4+
import IUser from './models/IUser';
45

56
export default class UserReducer {
67

78
private static readonly _initialState: IUserReducerState = {
8-
name: {
9-
title: '',
10-
first: '',
11-
last: '',
12-
},
13-
email: '',
14-
dob: '',
15-
phone: '',
16-
id: {
17-
name: '',
18-
value: '',
19-
},
20-
picture: {
21-
large: '',
22-
medium: '',
23-
thumbnail: '',
24-
},
9+
currentUser: null,
10+
isLoadingUser: false,
2511
};
2612

2713
public static reducer(state: IUserReducerState = UserReducer._initialState, action: IAction<any>): IUserReducerState {
2814
switch (action.type) {
29-
case UserAction.LOAD_USER_SUCCESS:
15+
case UserAction.LOAD_USER:
3016
return UserReducer._loadUser(state, action);
17+
case UserAction.LOAD_USER_SUCCESS:
18+
return UserReducer._loadUserSuccess(state, action);
3119
default:
3220
return state;
3321
}
3422
}
3523

36-
private static _loadUser(state: IUserReducerState, action: IAction<IUserReducerState>): IUserReducerState {
24+
private static _loadUser(state: IUserReducerState, action: IAction<IUser>): IUserReducerState {
25+
return {
26+
...state,
27+
isLoadingUser: true,
28+
};
29+
}
30+
31+
private static _loadUserSuccess(state: IUserReducerState, action: IAction<IUser>): IUserReducerState {
3732
return {
3833
...state,
39-
...action.payload,
34+
currentUser: action.payload,
35+
isLoadingUser: false,
4036
};
4137
}
4238

src/stores/user/UserSaga.ts

+6-30
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,15 @@
1-
import {put} from 'redux-saga/effects';
2-
import UserAction from './UserAction';
3-
import LoadingAction from '../loading/LoadingAction';
41
import IAction from '../IAction';
5-
import IUserReducerState from './IUserReducerState';
2+
import UserService from './UserService';
3+
import UserAction from './UserAction';
4+
import {put} from 'redux-saga/effects';
5+
import IUser from './models/IUser';
66

77
export default class UserSaga {
88

99
public static* loadUser(action: IAction<void> = null) {
10-
yield put({
11-
type: LoadingAction.SET_LOADING,
12-
payload: true,
13-
});
14-
15-
const response: Response = yield fetch('https://randomuser.me/api/?inc=picture,name,email,phone,id,dob');
16-
const type: string = (response.status === 200) ? UserAction.LOAD_USER_SUCCESS : UserAction.LOAD_USER_FAIL;
17-
18-
let data: IUserReducerState = null;
19-
20-
if (response.status === 200) {
21-
const json = yield response.json();
22-
23-
data = json.results[0];
24-
}
25-
26-
yield put({
27-
type,
28-
payload: data,
29-
meta: response,
30-
error: response.statusText,
31-
});
10+
const responseModel: IUser = yield UserService.loadUser();
3211

33-
yield put({
34-
type: LoadingAction.SET_LOADING,
35-
payload: false,
36-
});
12+
yield put(UserAction.loadUserSuccess(responseModel));
3713
}
3814

3915
}

src/stores/user/UserService.ts

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import HttpUtility from '../../utilities/HttpUtility';
2+
import {AxiosResponse} from 'axios';
3+
import IUser from './models/IUser';
4+
5+
export default class UserService {
6+
7+
private static _http: HttpUtility = new HttpUtility();
8+
9+
public static async loadUser(): Promise<IUser> {
10+
const endpoint: string = 'https://randomuser.me/api/?inc=picture,name,email,phone,id,dob';
11+
const response: AxiosResponse = await UserService._http.get(endpoint);
12+
13+
return response.data.results[0];
14+
}
15+
16+
}

src/stores/user/models/IUser.ts

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
export default interface IUser {
2+
readonly name: {
3+
title: string;
4+
first: string;
5+
last: string;
6+
};
7+
readonly email: string;
8+
readonly dob: string;
9+
readonly phone: string;
10+
readonly id: {
11+
name: string;
12+
value: string;
13+
};
14+
readonly picture: {
15+
large: string;
16+
medium: string;
17+
thumbnail: string;
18+
};
19+
}

src/utilities/HttpUtility.ts

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import axios, {AxiosResponse } from 'axios';
2+
import RequestMethodEnum from '../constants/RequestMethodEnum';
3+
4+
// http://httpstat.us
5+
export default class HttpUtility {
6+
7+
public async get(endpoint: string): Promise<AxiosResponse<any>> {
8+
const request = new Request(endpoint, {
9+
method: RequestMethodEnum.Get,
10+
});
11+
12+
return this._fetch(request);
13+
}
14+
15+
// TODO: finish setting up
16+
public async post(endpoint: string): Promise<AxiosResponse<any>> {
17+
const request = new Request(endpoint, {
18+
method: RequestMethodEnum.Post,
19+
});
20+
21+
return this._fetch(request);
22+
}
23+
24+
// TODO: finish setting up
25+
public async put(endpoint: string): Promise<AxiosResponse<any>> {
26+
const request = new Request(endpoint, {
27+
method: RequestMethodEnum.Put,
28+
});
29+
30+
return this._fetch(request);
31+
}
32+
33+
// TODO: finish setting up
34+
public async delete(endpoint: string): Promise<AxiosResponse<any>> {
35+
const request = new Request(endpoint, {
36+
method: RequestMethodEnum.Delete,
37+
});
38+
39+
return this._fetch(request);
40+
}
41+
42+
private async _fetch(request: Request, init?: any): Promise<AxiosResponse<any>> {
43+
try {
44+
return await axios({
45+
data: init,
46+
method: request.method,
47+
url: request.url,
48+
});
49+
} catch (error) {
50+
console.error(`error`, error);
51+
52+
return error;
53+
}
54+
}
55+
56+
}

0 commit comments

Comments
 (0)