Split Client into two classes.

This commit is contained in:
Paulo Gustavo Veiga 2021-02-03 14:27:32 -08:00
parent a45d18aebc
commit 8df40788ba
5 changed files with 138 additions and 110 deletions

View File

@ -32,6 +32,51 @@ export type ErrorInfo = {
fields?: Map<String, String>; fields?: Map<String, String>;
} }
export const parseResponseOnError = (response: any): ErrorInfo => {
let result: ErrorInfo | undefined;
if (response) {
const status: number = response.status;
const data = response.data;
console.log(data);
switch (status) {
case 401:
// this.authFailed();
break;
default:
if (data) {
// Set global errors ...
if (data.globalErrors) {
let msg;
let errors = data.globalErrors;
if (errors.length > 0) {
msg = errors[0];
}
result = { msg: errors };
}
// Set field errors ...
if (data.fieldErrors) {
// @Todo: Fix this ...
result = { msg: data.fieldErrors };
result.fields = new Map<string, string>();
}
} else {
result = { msg: response.statusText };
}
}
}
// Network related problem ...
if (!result) {
result = { msg: 'Unexpected error. Please, try latter' };
}
return result;
}
interface Client { interface Client {
createMap(rest: { name: string; description?: string | undefined }) createMap(rest: { name: string; description?: string | undefined })
deleteLabel(label: string): Promise<unknown>; deleteLabel(label: string): Promise<unknown>;
@ -44,6 +89,7 @@ interface Client {
duplicateMap(id: number, basicInfo: BasicMapInfo): Promise<void>; duplicateMap(id: number, basicInfo: BasicMapInfo): Promise<void>;
loadMapInfo(id: number): Promise<BasicMapInfo>; loadMapInfo(id: number): Promise<BasicMapInfo>;
changeStarred(id: number): Promise<void>; changeStarred(id: number): Promise<void>;
} }

View File

@ -1,15 +1,11 @@
import { BasicMapInfo, ErrorInfo, MapInfo, NewUser } from ".."; import Client, { BasicMapInfo, ErrorInfo, MapInfo, NewUser, parseResponseOnError } from '..';
import Client from "..";
import axios from "axios"; import axios from "axios";
class MockClient implements Client { class MockClient implements Client {
private baseUrl: string;
private authFailed: () => void
private maps: MapInfo[] = []; private maps: MapInfo[] = [];
private labels: string[] = []; private labels: string[] = [];
constructor(baseUrl: string, authFailed: () => void) { constructor() {
this.baseUrl = baseUrl;
// Remove, just for develop .... // Remove, just for develop ....
function createMapInfo( function createMapInfo(
@ -46,7 +42,7 @@ class MockClient implements Client {
createMap(rest: { name: string; description?: string | undefined; }) { createMap(rest: { name: string; description?: string | undefined; }) {
throw new Error("Method not implemented."); throw new Error("Method not implemented.");
} }
s s
fetchLabels(): Promise<string[]> { fetchLabels(): Promise<string[]> {
console.log("Fetching labels from server") console.log("Fetching labels from server")
return Promise.resolve(this.labels); return Promise.resolve(this.labels);
@ -138,20 +134,7 @@ s
} }
registerNewUser(user: NewUser): Promise<void> { registerNewUser(user: NewUser): Promise<void> {
const handler = (success: () => void, reject: (error: ErrorInfo) => void) => { return Promise.resolve();
axios.post(this.baseUrl + '/service/users',
JSON.stringify(user),
{ headers: { 'Content-Type': 'application/json' } }
).then(response => {
// All was ok, let's sent to success page ...;
success();
}).catch(error => {
const response = error.response;
const errorInfo = this.parseResponseOnError(response);
reject(errorInfo);
});
}
return new Promise(handler);
} }
fetchAllMaps(): Promise<MapInfo[]> { fetchAllMaps(): Promise<MapInfo[]> {
@ -160,66 +143,7 @@ s
} }
resetPassword(email: string): Promise<void> { resetPassword(email: string): Promise<void> {
return Promise.resolve();
const handler = (success: () => void, reject: (error: ErrorInfo) => void) => {
axios.post(`${this.baseUrl}/service/users/resetPassword?email=${email}`,
null,
{ headers: { 'Content-Type': 'application/json' } }
).then(response => {
// All was ok, let's sent to success page ...;
success();
}).catch(error => {
const response = error.response;
const errorInfo = this.parseResponseOnError(response);
reject(errorInfo);
});
}
return new Promise(handler);
}
private parseResponseOnError = (response: any): ErrorInfo => {
let result: ErrorInfo | undefined;
if (response) {
const status: number = response.status;
const data = response.data;
console.log(data);
switch (status) {
case 401:
this.authFailed();
break;
default:
if (data) {
// Set global errors ...
if (data.globalErrors) {
let msg;
let errors = data.globalErrors;
if (errors.length > 0) {
msg = errors[0];
}
result = { msg: errors };
}
// Set field errors ...
if (data.fieldErrors) {
// @Todo: Fix this ...
result = { msg: data.fieldErrors };
result.fields = new Map<string, string>();
}
} else {
result = { msg: response.statusText };
}
}
}
// Network related problem ...
if (!result) {
result = { msg: 'Unexpected error. Please, try latter' };
}
return result;
} }
} }

View File

@ -0,0 +1,54 @@
import axios from 'axios';
import { ErrorInfo, MapInfo, NewUser, parseResponseOnError } from '..';
import MockClient from '../mock-client/';
//@Remove inheritance once is it completed.
export default class RestClient extends MockClient {
private baseUrl: string;
private authFailed: () => void
constructor(baseUrl: string, authFailed: () => void) {
super();
this.baseUrl = baseUrl;
}
fetchAllMaps(): Promise<MapInfo[]> {
console.log("Fetching maps from server")
return Promise.resolve([]);
}
registerNewUser(user: NewUser): Promise<void> {
const handler = (success: () => void, reject: (error: ErrorInfo) => void) => {
axios.post(this.baseUrl + '/service/users',
JSON.stringify(user),
{ headers: { 'Content-Type': 'application/json' } }
).then(response => {
// All was ok, let's sent to success page ...;
success();
}).catch(error => {
const response = error.response;
const errorInfo = parseResponseOnError(response);
reject(errorInfo);
});
}
return new Promise(handler);
}
resetPassword(email: string): Promise<void> {
const handler = (success: () => void, reject: (error: ErrorInfo) => void) => {
axios.put(`${this.baseUrl}/service/users/resetPassword?email=${email}`,
null,
{ headers: { 'Content-Type': 'application/json' } }
).then(response => {
// All was ok, let's sent to success page ...;
success();
}).catch(error => {
const response = error.response;
const errorInfo = parseResponseOnError(response);
reject(errorInfo);
});
}
return new Promise(handler);
}
}

View File

@ -393,9 +393,9 @@ export const MapsList = (props: MapsListProps) => {
<TableBody> <TableBody>
{isLoading ? ( {isLoading ? (
<TableRow><TableCell rowSpan={6}>Loading ...</TableCell></TableRow>) : <TableRow><TableCell colSpan={6}>Loading ...</TableCell></TableRow>) :
(mapsInfo.length == 0 ? (mapsInfo.length == 0 ?
(<TableRow><TableCell rowSpan={6}>No matching records found</TableCell></TableRow>) : (<TableRow><TableCell colSpan={6} style={{textAlign:'center'}}><FormattedMessage id="maps.emptyresult" defaultMessage="No matching record found with the current filter criteria." /></TableCell></TableRow>) :
stableSort(mapsInfo, getComparator(order, orderBy)) stableSort(mapsInfo, getComparator(order, orderBy))
.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage) .slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
.map((row: MapInfo) => { .map((row: MapInfo) => {

View File

@ -1,44 +1,47 @@
import { createSlice, PayloadAction } from '@reduxjs/toolkit' import { createSlice, PayloadAction } from '@reduxjs/toolkit'
import axios from 'axios'; import axios from 'axios';
import Client from '../client'; import Client from '../client';
import MockClient from '../client/mock-client'; import MockClient from '../client/mock-client';
import RestClient from '../client/rest-client';
type RutimeConfig = { interface ConfigInfo {
apiBaseUrl: string; apiBaseUrl: string
} }
async function loadRuntimeConfig() { class RutimeConfig {
let result: RutimeConfig | undefined; private config: ConfigInfo;
await axios.get("runtime-config.json" constructor() {
).then(response => {
// All was ok, let's sent to success page ...
result = response.data as RutimeConfig;
console.log("Dynamic configuration->" + response.data);
}).catch(e => {
console.log(e)
});
if (!result) {
// Ok, try to create a default configuration relative to the current path ...
console.log("Configuration could not be loaded, falback to default config.")
const location = window.location;
const basePath = location.protocol + "//" + location.host + "/" + location.pathname.split('/')[1]
result = {
apiBaseUrl: basePath
}
} }
return result;
}
load() {
// Config can be inserted in the html page to define the global properties ...
this.config = (window as any).serverconfig;
return this;
}
buildClient(): Client {
let result: Client;
if (this.config) {
result = new RestClient(this.config.apiBaseUrl, () => { console.log("401 error") });
console.log("Service using rest client. " + JSON.stringify(this.config))
} else {
console.log("Warning:Service using mockservice client")
result = new MockClient();
}
return result;
}
}
interface ServiceState { interface ServiceState {
instance: Client; instance: Client;
} }
const initialState: ServiceState = { const initialState: ServiceState = {
instance: new MockClient("", () => { console.log("401 error") }) instance: new RutimeConfig().load().buildClient()
}; };
export const serviceSlice = createSlice({ export const serviceSlice = createSlice({
@ -46,7 +49,7 @@ export const serviceSlice = createSlice({
initialState: initialState, initialState: initialState,
reducers: { reducers: {
initialize(state, action: PayloadAction<void[]>) { initialize(state, action: PayloadAction<void[]>) {
state.instance = new MockClient("", () => { console.log("401 error") }); // state.instance = new RutimeConfig().load().buildClient()
} }
}, },
}); });
@ -54,5 +57,6 @@ export const serviceSlice = createSlice({
export const activeInstance = (state: any): Client => { export const activeInstance = (state: any): Client => {
return state.service.instance; return state.service.instance;
} }
export default serviceSlice.reducer export default serviceSlice.reducer