added axios type script

added api calls from a mock server
added redux saga
This commit is contained in:
Nikhil Nandgopal 2019-03-26 20:58:24 +05:30
parent 4e2b003a5d
commit d83f3d9308
17 changed files with 183 additions and 33 deletions

View File

@ -7,6 +7,7 @@
"@blueprintjs/datetime": "^3.6.0",
"@blueprintjs/icons": "^3.5.0",
"@blueprintjs/table": "^3.4.0",
"@types/axios": "^0.14.0",
"@types/jest": "^23.3.13",
"@types/lodash": "^4.14.120",
"@types/moment-timezone": "^0.5.10",

View File

@ -1,18 +0,0 @@
import { IContainerWidgetProps } from "../widgets/ContainerWidget"
import CanvasWidgetsNormalizer, { widgetSchema } from "../normalizers/CanvasWidgetsNormalizer"
import { LoadCanvasPayload, ActionTypes, ReduxAction } from "../constants/ActionConstants"
export const loadCanvas = (canvasResponse: PageResponse): ReduxAction<LoadCanvasPayload> => {
const normalizedResponse = CanvasWidgetsNormalizer.normalize(canvasResponse)
return {
type: ActionTypes.LOAD_CANVAS,
payload: {
pageWidgetId: normalizedResponse.result,
widgets: normalizedResponse.entities.canvasWidgets
}
}
}
export interface PageResponse {
pageWidget: IContainerWidgetProps<any>
}

View File

@ -0,0 +1,62 @@
import _ from "lodash"
import {
BASE_URL,
REQUEST_TIMEOUT_MS,
REQUEST_HEADERS
} from "../constants/ApiConstants"
const axios = require("axios")
const axiosInstance = axios.create({
baseURL: BASE_URL,
timeout: REQUEST_TIMEOUT_MS,
headers: REQUEST_HEADERS
})
axiosInstance.interceptors.response.use(
function(response: any) {
// Do something with response data
return response.data
},
function(error: any) {
if (error.response) {
// The request was made and the server responded with a status code
// that falls out of the range of 2xx
console.log(error.response.data)
console.log(error.response.status)
console.log(error.response.headers)
} else if (error.request) {
// The request was made but no response was received
// `error.request` is an instance of XMLHttpRequest in the browser and an instance of
// http.ClientRequest in node.js
console.log(error.request)
} else {
// Something happened in setting up the request that triggered an Error
console.log("Error", error.message)
}
console.log(error.config)
return Promise.reject(error)
}
)
class Api {
static get(url: string, queryParams: any) {
return axiosInstance.get(url + this.convertObjectToQueryParams(queryParams))
}
static post(url: string, queryParams?: any, body?: any) {
return axiosInstance.post(
url + this.convertObjectToQueryParams(queryParams),
body
)
}
static convertObjectToQueryParams(object: any): string {
const paramArray: string[] = _.map(_.keys(object), key => {
return encodeURIComponent(key) + "=" + encodeURIComponent(object[key])
})
return "?" + _.join(paramArray, "&")
}
}
export default Api

View File

@ -0,0 +1,12 @@
import { ContentType, DataType, EncodingType } from "../constants/ApiConstants";
export interface ApiHeaders {
Accept: ContentType
"Content-Type": ContentType
dataType: DataType
"Accept-Encoding": EncodingType
}
export interface ApiRequest {
}

View File

@ -0,0 +1,9 @@
export type ApiErrorCodes = "INVALID_REQUEST" | "UNKNOWN"
export interface ResponseMeta {
errorCode?: ApiErrorCodes
}
export interface ApiResponse {
responseMeta: ResponseMeta
}

View File

@ -0,0 +1,21 @@
import Api from "./Api"
import { IContainerWidgetProps } from "../widgets/ContainerWidget"
import { ApiResponse } from "./ApiResponses"
export interface PageRequest {
pageId: string
}
export interface PageResponse extends ApiResponse {
pageWidget: IContainerWidgetProps<any>
}
class PageApi extends Api {
static url: string = "/page/"
static fetchPage(pageRequest: PageRequest): Promise<PageResponse> {
return Api.get(PageApi.url + pageRequest.pageId, pageRequest)
}
}
export default PageApi

View File

@ -2,13 +2,15 @@ import ContainerWidget from "../widgets/ContainerWidget"
import { IWidgetProps } from "../widgets/BaseWidget"
export type ActionType =
| "LOAD_CANVAS"
| "UPDATE_CANVAS"
| "FETCH_CANVAS"
| "CLEAR_CANVAS"
| "DROP_WIDGET_CANVAS"
| "REMOVE_WIDGET_CANVAS"
| "LOAD_WIDGET_PANE"
export const ActionTypes: { [id: string]: ActionType } = {
LOAD_CANVAS: "LOAD_CANVAS",
UPDATE_CANVAS: "UPDATE_CANVAS",
FETCH_CANVAS: "FETCH_CANVAS",
CLEAR_CANVAS: "CLEAR_CANVAS",
DROP_WIDGET_CANVAS: "DROP_WIDGET_CANVAS",
REMOVE_WIDGET_CANVAS: "REMOVE_WIDGET_CANVAS",

View File

@ -0,0 +1,16 @@
import { ApiHeaders } from "../api/ApiRequests";
export type DataType = "json" | "xml"
export type ContentType = "application/json" | "application/x-www-form-urlencoded"
export type EncodingType = "gzip"
export const PROD_BASE_URL = "https://mobtools.com/api/"
export const STAGE_BASE_URL = "https://14157cb0-190f-4082-a791-886a8df05930.mock.pstmn.io"
export const BASE_URL = STAGE_BASE_URL
export const REQUEST_TIMEOUT_MS = 2000
export const REQUEST_HEADERS: ApiHeaders = {
Accept: "application/json",
"Content-Type": "application/json",
dataType: "json",
"Accept-Encoding": "gzip"
}

View File

@ -7,13 +7,20 @@ import Editor from "./pages/Editor";
import PageNotFound from "./pages/PageNotFound";
import * as serviceWorker from "./serviceWorker";
import { BrowserRouter, Route, Switch } from "react-router-dom";
import { createStore } from "redux";
import { createStore, applyMiddleware } from "redux";
import appReducer from "./reducers";
import WidgetBuilderRegistry from "./utils/WidgetRegistry";
import { ThemeProvider, theme } from "./constants/DefaultTheme";
import createSagaMiddleware from 'redux-saga'
import { rootSaga } from "./sagas"
import { ActionType } from "./constants/ActionConstants";
WidgetBuilderRegistry.registerWidgetBuilders();
const store = createStore(appReducer);
const sagaMiddleware = createSagaMiddleware()
const store = createStore(appReducer, applyMiddleware(sagaMiddleware));
sagaMiddleware.run(rootSaga)
export const action = (type: ActionType) => store.dispatch({type})
ReactDOM.render(
<Provider store={store}>
<ThemeProvider theme={theme}>

View File

@ -8,6 +8,7 @@ const WidgetPaneResponse: WidgetPaneReduxState = {
text: "Lorem Ipsum",
renderMode: RenderModes.COMPONENT_PANE,
bottomRow: 50,
widgetId: "1",
rightColumn: 200
},
{
@ -15,6 +16,7 @@ const WidgetPaneResponse: WidgetPaneReduxState = {
text: "Lorem Ipsum",
renderMode: RenderModes.COMPONENT_PANE,
bottomRow: 50,
widgetId: "2",
rightColumn: 200
},
{
@ -22,6 +24,7 @@ const WidgetPaneResponse: WidgetPaneReduxState = {
renderMode: RenderModes.COMPONENT_PANE,
backgroundColor: "#434343",
bottomRow: 50,
widgetId: "3",
rightColumn: 200
}
]

View File

@ -1,5 +1,5 @@
import { normalize, schema, denormalize } from 'normalizr';
import { PageResponse } from '../actions/CanvasActions';
import { PageResponse } from '../api/PageApi';
import { IContainerWidgetProps } from '../widgets/ContainerWidget';
export const widgetSchema = new schema.Entity('canvasWidgets', { }, { idAttribute: "widgetId" }, );

View File

@ -2,16 +2,15 @@ import React, { Component } from "react"
import { connect } from "react-redux"
import { AppState } from "../../reducers"
import WidgetFactory from "../../utils/WidgetFactory"
import { loadCanvas } from "../../actions/CanvasActions";
import CanvasResponse from "../../mockResponses/CanvasResponse";
import { denormalize } from "normalizr";
import CanvasWidgetsNormalizer, { widgetSchema } from "../../normalizers/CanvasWidgetsNormalizer";
import { IContainerWidgetProps } from "../../widgets/ContainerWidget";
import { action } from "../../index"
import { ActionTypes } from "../../constants/ActionConstants";
class Canvas extends Component<{ pageWidget: IContainerWidgetProps<any>, loadCanvas: Function }> {
componentDidMount() {
this.props.loadCanvas()
action(ActionTypes.FETCH_CANVAS)
}
render() {
@ -35,9 +34,6 @@ const mapStateToProps = (state: AppState, props: any) => {
const mapDispatchToProps = (dispatch: any) => {
return {
loadCanvas: () => {
dispatch(loadCanvas({ pageWidget: CanvasResponse }))
}
}
}

View File

@ -22,7 +22,7 @@ const initialState: CanvasWidgetsReduxState = {
}
const canvasWidgetsReducer = createReducer(initialState, {
[ActionTypes.LOAD_CANVAS]: (
[ActionTypes.UPDATE_CANVAS]: (
state: CanvasWidgetsReduxState,
action: ReduxAction<LoadCanvasPayload>
) => {

View File

@ -10,7 +10,7 @@ const initialState: CanvasReduxState = {
}
const canvasReducer = createReducer(initialState, {
[ActionTypes.LOAD_CANVAS]: (
[ActionTypes.UPDATE_CANVAS]: (
state: CanvasReduxState,
action: ReduxAction<LoadCanvasPayload>
) => {

View File

@ -0,0 +1,27 @@
import CanvasWidgetsNormalizer, {
} from "../normalizers/CanvasWidgetsNormalizer"
import {
ActionTypes,
} from "../constants/ActionConstants"
import PageApi, { PageResponse } from "../api/PageApi"
import { call, put, takeLeading, all, takeEvery } from "redux-saga/effects"
export function* fetchCanvas() {
const pageResponse: PageResponse = yield call(PageApi.fetchPage, {
pageId: "123"
})
const normalizedResponse = CanvasWidgetsNormalizer.normalize(pageResponse)
const payload = {
pageWidgetId: normalizedResponse.result,
widgets: normalizedResponse.entities.canvasWidgets
}
yield put({ type: ActionTypes.UPDATE_CANVAS, payload })
}
export function* watchFetchCanvas() {
yield takeEvery(ActionTypes.FETCH_CANVAS, fetchCanvas)
}
export function* canvasSagas() {
yield all([fetchCanvas(), watchFetchCanvas()])
}

View File

@ -0,0 +1,6 @@
import { all } from "redux-saga/effects"
import { canvasSagas } from "../sagas/CanvasSagas"
export function* rootSaga() {
yield all([canvasSagas()])
}

View File

@ -914,6 +914,12 @@
"@svgr/core" "^2.4.1"
loader-utils "^1.1.0"
"@types/axios@^0.14.0":
version "0.14.0"
resolved "https://registry.yarnpkg.com/@types/axios/-/axios-0.14.0.tgz#ec2300fbe7d7dddd7eb9d3abf87999964cafce46"
dependencies:
axios "*"
"@types/dom4@^2.0.1":
version "2.0.1"
resolved "https://registry.yarnpkg.com/@types/dom4/-/dom4-2.0.1.tgz#506d5781b9bcab81bd9a878b198aec7dee2a6033"
@ -1458,7 +1464,7 @@ aws4@^1.8.0:
version "1.8.0"
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f"
axios@^0.18.0:
axios@*, axios@^0.18.0:
version "0.18.0"
resolved "https://registry.yarnpkg.com/axios/-/axios-0.18.0.tgz#32d53e4851efdc0a11993b6cd000789d70c05102"
dependencies: