added axios type script
added api calls from a mock server added redux saga
This commit is contained in:
parent
4e2b003a5d
commit
d83f3d9308
|
|
@ -7,6 +7,7 @@
|
||||||
"@blueprintjs/datetime": "^3.6.0",
|
"@blueprintjs/datetime": "^3.6.0",
|
||||||
"@blueprintjs/icons": "^3.5.0",
|
"@blueprintjs/icons": "^3.5.0",
|
||||||
"@blueprintjs/table": "^3.4.0",
|
"@blueprintjs/table": "^3.4.0",
|
||||||
|
"@types/axios": "^0.14.0",
|
||||||
"@types/jest": "^23.3.13",
|
"@types/jest": "^23.3.13",
|
||||||
"@types/lodash": "^4.14.120",
|
"@types/lodash": "^4.14.120",
|
||||||
"@types/moment-timezone": "^0.5.10",
|
"@types/moment-timezone": "^0.5.10",
|
||||||
|
|
|
||||||
|
|
@ -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>
|
|
||||||
}
|
|
||||||
62
app/client/src/api/Api.tsx
Normal file
62
app/client/src/api/Api.tsx
Normal 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
|
||||||
12
app/client/src/api/ApiRequests.tsx
Normal file
12
app/client/src/api/ApiRequests.tsx
Normal 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 {
|
||||||
|
|
||||||
|
}
|
||||||
9
app/client/src/api/ApiResponses.tsx
Normal file
9
app/client/src/api/ApiResponses.tsx
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
export type ApiErrorCodes = "INVALID_REQUEST" | "UNKNOWN"
|
||||||
|
|
||||||
|
export interface ResponseMeta {
|
||||||
|
errorCode?: ApiErrorCodes
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ApiResponse {
|
||||||
|
responseMeta: ResponseMeta
|
||||||
|
}
|
||||||
21
app/client/src/api/PageApi.tsx
Normal file
21
app/client/src/api/PageApi.tsx
Normal 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
|
||||||
|
|
@ -2,13 +2,15 @@ import ContainerWidget from "../widgets/ContainerWidget"
|
||||||
import { IWidgetProps } from "../widgets/BaseWidget"
|
import { IWidgetProps } from "../widgets/BaseWidget"
|
||||||
|
|
||||||
export type ActionType =
|
export type ActionType =
|
||||||
| "LOAD_CANVAS"
|
| "UPDATE_CANVAS"
|
||||||
|
| "FETCH_CANVAS"
|
||||||
| "CLEAR_CANVAS"
|
| "CLEAR_CANVAS"
|
||||||
| "DROP_WIDGET_CANVAS"
|
| "DROP_WIDGET_CANVAS"
|
||||||
| "REMOVE_WIDGET_CANVAS"
|
| "REMOVE_WIDGET_CANVAS"
|
||||||
| "LOAD_WIDGET_PANE"
|
| "LOAD_WIDGET_PANE"
|
||||||
export const ActionTypes: { [id: string]: ActionType } = {
|
export const ActionTypes: { [id: string]: ActionType } = {
|
||||||
LOAD_CANVAS: "LOAD_CANVAS",
|
UPDATE_CANVAS: "UPDATE_CANVAS",
|
||||||
|
FETCH_CANVAS: "FETCH_CANVAS",
|
||||||
CLEAR_CANVAS: "CLEAR_CANVAS",
|
CLEAR_CANVAS: "CLEAR_CANVAS",
|
||||||
DROP_WIDGET_CANVAS: "DROP_WIDGET_CANVAS",
|
DROP_WIDGET_CANVAS: "DROP_WIDGET_CANVAS",
|
||||||
REMOVE_WIDGET_CANVAS: "REMOVE_WIDGET_CANVAS",
|
REMOVE_WIDGET_CANVAS: "REMOVE_WIDGET_CANVAS",
|
||||||
|
|
|
||||||
16
app/client/src/constants/ApiConstants.tsx
Normal file
16
app/client/src/constants/ApiConstants.tsx
Normal 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"
|
||||||
|
}
|
||||||
|
|
@ -7,13 +7,20 @@ import Editor from "./pages/Editor";
|
||||||
import PageNotFound from "./pages/PageNotFound";
|
import PageNotFound from "./pages/PageNotFound";
|
||||||
import * as serviceWorker from "./serviceWorker";
|
import * as serviceWorker from "./serviceWorker";
|
||||||
import { BrowserRouter, Route, Switch } from "react-router-dom";
|
import { BrowserRouter, Route, Switch } from "react-router-dom";
|
||||||
import { createStore } from "redux";
|
import { createStore, applyMiddleware } from "redux";
|
||||||
import appReducer from "./reducers";
|
import appReducer from "./reducers";
|
||||||
import WidgetBuilderRegistry from "./utils/WidgetRegistry";
|
import WidgetBuilderRegistry from "./utils/WidgetRegistry";
|
||||||
import { ThemeProvider, theme } from "./constants/DefaultTheme";
|
import { ThemeProvider, theme } from "./constants/DefaultTheme";
|
||||||
|
import createSagaMiddleware from 'redux-saga'
|
||||||
|
import { rootSaga } from "./sagas"
|
||||||
|
import { ActionType } from "./constants/ActionConstants";
|
||||||
|
|
||||||
WidgetBuilderRegistry.registerWidgetBuilders();
|
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(
|
ReactDOM.render(
|
||||||
<Provider store={store}>
|
<Provider store={store}>
|
||||||
<ThemeProvider theme={theme}>
|
<ThemeProvider theme={theme}>
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ const WidgetPaneResponse: WidgetPaneReduxState = {
|
||||||
text: "Lorem Ipsum",
|
text: "Lorem Ipsum",
|
||||||
renderMode: RenderModes.COMPONENT_PANE,
|
renderMode: RenderModes.COMPONENT_PANE,
|
||||||
bottomRow: 50,
|
bottomRow: 50,
|
||||||
|
widgetId: "1",
|
||||||
rightColumn: 200
|
rightColumn: 200
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -15,6 +16,7 @@ const WidgetPaneResponse: WidgetPaneReduxState = {
|
||||||
text: "Lorem Ipsum",
|
text: "Lorem Ipsum",
|
||||||
renderMode: RenderModes.COMPONENT_PANE,
|
renderMode: RenderModes.COMPONENT_PANE,
|
||||||
bottomRow: 50,
|
bottomRow: 50,
|
||||||
|
widgetId: "2",
|
||||||
rightColumn: 200
|
rightColumn: 200
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -22,6 +24,7 @@ const WidgetPaneResponse: WidgetPaneReduxState = {
|
||||||
renderMode: RenderModes.COMPONENT_PANE,
|
renderMode: RenderModes.COMPONENT_PANE,
|
||||||
backgroundColor: "#434343",
|
backgroundColor: "#434343",
|
||||||
bottomRow: 50,
|
bottomRow: 50,
|
||||||
|
widgetId: "3",
|
||||||
rightColumn: 200
|
rightColumn: 200
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { normalize, schema, denormalize } from 'normalizr';
|
import { normalize, schema, denormalize } from 'normalizr';
|
||||||
import { PageResponse } from '../actions/CanvasActions';
|
import { PageResponse } from '../api/PageApi';
|
||||||
import { IContainerWidgetProps } from '../widgets/ContainerWidget';
|
import { IContainerWidgetProps } from '../widgets/ContainerWidget';
|
||||||
|
|
||||||
export const widgetSchema = new schema.Entity('canvasWidgets', { }, { idAttribute: "widgetId" }, );
|
export const widgetSchema = new schema.Entity('canvasWidgets', { }, { idAttribute: "widgetId" }, );
|
||||||
|
|
|
||||||
|
|
@ -2,16 +2,15 @@ import React, { Component } from "react"
|
||||||
import { connect } from "react-redux"
|
import { connect } from "react-redux"
|
||||||
import { AppState } from "../../reducers"
|
import { AppState } from "../../reducers"
|
||||||
import WidgetFactory from "../../utils/WidgetFactory"
|
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 CanvasWidgetsNormalizer, { widgetSchema } from "../../normalizers/CanvasWidgetsNormalizer";
|
||||||
import { IContainerWidgetProps } from "../../widgets/ContainerWidget";
|
import { IContainerWidgetProps } from "../../widgets/ContainerWidget";
|
||||||
|
import { action } from "../../index"
|
||||||
|
import { ActionTypes } from "../../constants/ActionConstants";
|
||||||
|
|
||||||
class Canvas extends Component<{ pageWidget: IContainerWidgetProps<any>, loadCanvas: Function }> {
|
class Canvas extends Component<{ pageWidget: IContainerWidgetProps<any>, loadCanvas: Function }> {
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.props.loadCanvas()
|
action(ActionTypes.FETCH_CANVAS)
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|
@ -35,9 +34,6 @@ const mapStateToProps = (state: AppState, props: any) => {
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch: any) => {
|
const mapDispatchToProps = (dispatch: any) => {
|
||||||
return {
|
return {
|
||||||
loadCanvas: () => {
|
|
||||||
dispatch(loadCanvas({ pageWidget: CanvasResponse }))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ const initialState: CanvasWidgetsReduxState = {
|
||||||
}
|
}
|
||||||
|
|
||||||
const canvasWidgetsReducer = createReducer(initialState, {
|
const canvasWidgetsReducer = createReducer(initialState, {
|
||||||
[ActionTypes.LOAD_CANVAS]: (
|
[ActionTypes.UPDATE_CANVAS]: (
|
||||||
state: CanvasWidgetsReduxState,
|
state: CanvasWidgetsReduxState,
|
||||||
action: ReduxAction<LoadCanvasPayload>
|
action: ReduxAction<LoadCanvasPayload>
|
||||||
) => {
|
) => {
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ const initialState: CanvasReduxState = {
|
||||||
}
|
}
|
||||||
|
|
||||||
const canvasReducer = createReducer(initialState, {
|
const canvasReducer = createReducer(initialState, {
|
||||||
[ActionTypes.LOAD_CANVAS]: (
|
[ActionTypes.UPDATE_CANVAS]: (
|
||||||
state: CanvasReduxState,
|
state: CanvasReduxState,
|
||||||
action: ReduxAction<LoadCanvasPayload>
|
action: ReduxAction<LoadCanvasPayload>
|
||||||
) => {
|
) => {
|
||||||
|
|
|
||||||
27
app/client/src/sagas/CanvasSagas.tsx
Normal file
27
app/client/src/sagas/CanvasSagas.tsx
Normal 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()])
|
||||||
|
}
|
||||||
6
app/client/src/sagas/index.tsx
Normal file
6
app/client/src/sagas/index.tsx
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
import { all } from "redux-saga/effects"
|
||||||
|
import { canvasSagas } from "../sagas/CanvasSagas"
|
||||||
|
|
||||||
|
export function* rootSaga() {
|
||||||
|
yield all([canvasSagas()])
|
||||||
|
}
|
||||||
|
|
@ -914,6 +914,12 @@
|
||||||
"@svgr/core" "^2.4.1"
|
"@svgr/core" "^2.4.1"
|
||||||
loader-utils "^1.1.0"
|
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":
|
"@types/dom4@^2.0.1":
|
||||||
version "2.0.1"
|
version "2.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/@types/dom4/-/dom4-2.0.1.tgz#506d5781b9bcab81bd9a878b198aec7dee2a6033"
|
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"
|
version "1.8.0"
|
||||||
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f"
|
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"
|
version "0.18.0"
|
||||||
resolved "https://registry.yarnpkg.com/axios/-/axios-0.18.0.tgz#32d53e4851efdc0a11993b6cd000789d70c05102"
|
resolved "https://registry.yarnpkg.com/axios/-/axios-0.18.0.tgz#32d53e4851efdc0a11993b6cd000789d70c05102"
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user