Skip to content

Commit

Permalink
add react promise middleware, fix api calling problems
Browse files Browse the repository at this point in the history
  • Loading branch information
haitrr committed Nov 3, 2018
1 parent f2f5464 commit a6106ee
Show file tree
Hide file tree
Showing 12 changed files with 186 additions and 27 deletions.
15 changes: 15 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "chrome",
"request": "launch",
"name": "Launch Chrome against localhost",
"url": "http://localhost:3000",
"webRoot": "${workspaceFolder}"
}
]
}
51 changes: 51 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@
"react": "^16.5.2",
"react-dom": "^16.5.2",
"react-redux": "latest",
"redux-devtools-extension": "^2.13.5",
"react-router": "latest",
"react-router-dom": "^4.3.1",
"react-scripts-ts": "3.1.0",
"redux": "latest",
"redux-actions": "latest"
"redux-actions": "latest",
"redux-promise": "0.6.0"
},
"scripts": {
"start": "react-scripts-ts start",
Expand All @@ -29,6 +31,7 @@
"@types/react-router": "^4.0.31",
"@types/react-router-dom": "^4.3.1",
"@types/redux-actions": "^2.3.0",
"@types/redux-promise": "^0.5.28",
"prettier": "^1.14.3",
"tslint": "5.11.0",
"tslint-consistent-codestyle": "^1.13.3",
Expand Down
16 changes: 5 additions & 11 deletions src/Actions/UserAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,12 @@ export const USER_REGISTERED: string = "USER_REGISTERED";
/**
* user login action.
*/
export const loginAction: ActionFunction1<
IUserLoginModel,
Action<Promise<boolean>>
> = createAction(USER_LOGGED_IN, async (credentials: IUserLoginModel) => {
try {
await loginAsync(credentials);

return true;
} catch (e) {
return false;
export const loginAction: any = createAction(
USER_LOGGED_IN,
async (credentials: IUserLoginModel) => {
return loginAsync(credentials);
}
});
);

export const registerAction: ActionFunction1<
IUserRegisterModel,
Expand Down
21 changes: 21 additions & 0 deletions src/Apis/TextApi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { TEXT_API } from "src/Constants";
import { getAsync } from "src/Utilities/HttpRequest";

interface ITextListItem {
title: string;
}
interface ITextList {
total: number;
items: ITextListItem[];
}

/**
* Get the list of text
*/
export async function getListAsync(): Promise<ITextList | null> {
try {
return await getAsync<ITextList>(TEXT_API, {});
} catch {
return null;
}
}
10 changes: 6 additions & 4 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,22 @@ import * as React from "react";
import { Provider } from "react-redux";
import { Route } from "react-router";
import { BrowserRouter } from "react-router-dom";
import { createStore, Store } from "redux";
import { applyMiddleware, createStore, Store } from "redux";
import { composeWithDevTools } from "redux-devtools-extension";
import * as promiseMiddleware from "redux-promise";
import "src/App.css";
import { rootReducer } from "src/RootReducer";
import { Footer } from "./Components/Footer";
import { Header } from "./Components/Header/Header";
import { HomePage } from "./Components/Pages/HomePage";
import { LoginPage } from "./Components/Pages/LoginPage";
import { RegisterPage } from "./Components/Pages/RegisterPage/RegisterPage";
import { TextPage } from './Components/Pages/TextPage';
import { TextPage } from "./Components/Pages/TextPage";

const store: Store = createStore(
rootReducer,
// @ts-ignore
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
// tslint:disable-next-line
composeWithDevTools(applyMiddleware((promiseMiddleware as any).default))
);

/**
Expand Down
4 changes: 3 additions & 1 deletion src/Components/Forms/LoginForm/LoginForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@ class LoginForm extends React.Component<ILoginFormProps & FormComponentProps> {
const { form, onSubmit } = this.props;
form.validateFields((err: string[], values: object) => {
if (err != null && err.length > 0) {
onSubmit(values);
// todo: error
}

onSubmit(values);
});
}

Expand Down
1 change: 1 addition & 0 deletions src/Constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@

export const API_ROOT: string = "http://localhost:63488/api";
export const LOGIN_API: string = `${API_ROOT}/user/login`;
export const TEXT_API: string = `${API_ROOT}/text`;
22 changes: 22 additions & 0 deletions src/Reducers/TextReducer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { handleActions, Reducer } from "redux-actions";

/**
* text reducer
*/

interface ITextState {
texts: object[];
page: number;
itemPerPage: number;
}

const defaultState: ITextState = {
texts: [],
page: 1,
itemPerPage: 10
};

export const textReducer: Reducer<ITextState, ITextState> = handleActions(
{},
defaultState
);
12 changes: 10 additions & 2 deletions src/Reducers/UserReducer.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { handleActions, Reducer } from "redux-actions";
import { USER_LOGGED_IN } from "src/Actions/UserAction";

/**
* default state
Expand All @@ -11,7 +12,14 @@ const defaultState: object = {
/**
* user reducer
*/
export const userReducer: Reducer<object, object> = handleActions(
{},
export const userReducer: Reducer<any, any> = handleActions(
{
[USER_LOGGED_IN]: (state: any, action: any): any => {
return {
...state,
isLoggedIn: action.payload
};
}
},
defaultState
);
53 changes: 46 additions & 7 deletions src/Utilities/HttpRequest.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,25 @@
function defaultResponseErrorHandler(response: Response): never {
throw new Error(
`Error connecting with server ${response.status}:${response.statusText}`
);
}
function defaultResponseHandler(response: Response): any {
if (response.status === 200) {
return response.json();
} else {
throw response;
}
}
/**
* perform a post request
* @param url the request url
* @param body body of the request
*/
export async function postAsync<T>(url: string, body: object): Promise<T> {
export async function postAsync<T>(
url: string,
body: object,
handleResponse: (response: Response) => any = defaultResponseHandler
): Promise<T> {
return fetch(url, {
body: JSON.stringify(body), // body data type must match "Content-Type" header
cache: "no-cache", // *default, no-cache, reload, force-cache, only-if-cached
Expand All @@ -16,12 +32,35 @@ export async function postAsync<T>(url: string, body: object): Promise<T> {
mode: "cors", // no-cors, cors, *same-origin
redirect: "follow", // manual, *follow, error
referrer: "no-referrer" // no-referrer, *client
}).then(
async (response: Response): Promise<T> =>
response.json().then((json: any): T => <T>json)
); // parses response to JSON
})
.then(handleResponse)
.then((json: any): T => <T>json)
.catch(defaultResponseErrorHandler);
}

export function getAsync(): object {
return {};
export async function getAsync<T>(
url: string,
params: object,
handleResponse: (response: Response) => any = defaultResponseHandler
): Promise<T> {
let fullUrl: string = `${url}?`;
Object.keys(params).forEach((key: string) => {
fullUrl += `${key}=${params[key]}`;
});

return fetch(fullUrl, {
cache: "no-cache", // *default, no-cache, reload, force-cache, only-if-cached
credentials: "same-origin", // include, same-origin, *omit
headers: {
"Content-Type": "application/json; charset=utf-8"
// "Content-Type": "application/x-www-form-urlencoded",
},
method: "GET", // *GET, POST, PUT, DELETE, etc.
mode: "cors", // no-cors, cors, *same-origin
redirect: "follow", // manual, *follow, error
referrer: "no-referrer" // no-referrer, *client
})
.then(handleResponse)
.then((json: any): T => <T>json)
.catch(defaultResponseErrorHandler);
}
3 changes: 2 additions & 1 deletion tslint.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"prettier": true,
"no-default-export": true,
"no-unsafe-any": false,
"no-any": false
"no-any": false,
"no-suspicious-comment": false
}
}

0 comments on commit a6106ee

Please sign in to comment.