Add error exception

This commit is contained in:
Paulo Gustavo Veiga 2021-02-04 23:05:46 -08:00
parent 6115eeec26
commit 680a679a92
15 changed files with 115 additions and 52 deletions

View File

@ -8,7 +8,7 @@ import ForgotPasswordSuccessPage from './components/forgot-password-success-page
import RegistationPage from './components/registration-page';
import LoginPage from './components/login-page';
import MapsPage from './components/maps-page';
import store from "./store";
import store from "./redux/store";
import { ForgotPasswordPage } from './components/forgot-password-page';
import { Provider } from 'react-redux';
import { QueryClient, QueryClientProvider } from 'react-query';

View File

@ -13,7 +13,6 @@ export type Label = {
iconName: string;
}
export type MapInfo = {
id: number;
starred: boolean;

View File

@ -1,18 +1,23 @@
import axios from 'axios';
import { ErrorInfo, MapInfo, BasicMapInfo, NewUser, Label } from '..';
import MockClient from '../mock-client/';
import { useIntl } from 'react-intl';
import Client, { ErrorInfo, MapInfo, BasicMapInfo, NewUser, Label } from '..';
//@Remove inheritance once is it completed.
export default class RestClient extends MockClient {
export default class RestClient implements Client {
private baseUrl: string;
private authFailed: () => void
private sessionExpired: () => void
constructor(baseUrl: string, authFailed: () => void) {
super();
constructor(baseUrl: string, sessionExpired: () => void) {
this.baseUrl = baseUrl;
this.sessionExpired = sessionExpired;
}
fetchMapInfo(id: number): Promise<BasicMapInfo> {
throw new Error('Method not implemented.');
}
private parseResponseOnError = (response: any): ErrorInfo => {
const intl = useIntl();
let result: ErrorInfo | undefined;
if (response) {
@ -22,7 +27,9 @@ export default class RestClient extends MockClient {
switch (status) {
case 401:
// this.authFailed();
case 302:
this.sessionExpired();
result = { msg: intl.formatMessage({ id: "expired.title", defaultMessage: "Your current session has expired. Please, sign in and try again." })}
break;
default:
if (data) {

View File

@ -8,7 +8,7 @@ import Footer from '../layout/footer'
import FormContainer from '../layout/form-container';
import { useSelector } from 'react-redux'
import { useMutation } from 'react-query'
import { activeInstance } from '../../reducers/serviceSlice'
import { activeInstance } from '../../redux/clientSlice'
import Input from '../form/input'
import GlobalError from '../form/global-error'
import SubmitButton from '../form/submit-button'

View File

@ -6,7 +6,7 @@ import { FormControl } from '@material-ui/core';
import Client, { BasicMapInfo, ErrorInfo } from '../../../../client';
import { activeInstance } from '../../../../reducers/serviceSlice';
import { activeInstance } from '../../../../redux/clientSlice';
import Input from '../../../form/input';
import BaseDialog from '../base-dialog';

View File

@ -4,7 +4,7 @@ import { FormattedMessage, useIntl } from "react-intl";
import { useMutation, useQueryClient } from "react-query";
import { useSelector } from "react-redux";
import Client from "../../../../client";
import { activeInstance } from '../../../../reducers/serviceSlice';
import { activeInstance } from '../../../../redux/clientSlice';
import { DialogProps, fetchMapById, handleOnMutationSuccess } from "..";
import BaseDialog from "../base-dialog";

View File

@ -5,7 +5,7 @@ import { FormControl } from "@material-ui/core";
import { useSelector } from "react-redux";
import Client, { BasicMapInfo, ErrorInfo } from "../../../../client";
import { activeInstance } from '../../../../reducers/serviceSlice';
import { activeInstance } from '../../../../redux/clientSlice';
import Input from "../../../form/input";
import { DialogProps, fetchMapById } from "..";
import BaseDialog from "../base-dialog";

View File

@ -6,7 +6,7 @@ import { ErrorInfo, MapInfo } from '../../../client';
import Client from '../../../client';
import { useSelector } from "react-redux";
import { QueryClient, useQuery } from 'react-query';
import { activeInstance } from '../../../reducers/serviceSlice';
import { activeInstance } from '../../../redux/clientSlice';
import DuplicateDialog from './duplicate-dialog';
import { useHistory } from 'react-router-dom';
import CreateDialog from './create-dialog';
@ -49,8 +49,6 @@ const ActionDispatcher = (props: ActionDialogProps) => {
</span >
);
}
type MapLoadResult = {
isLoading: boolean,
error: ErrorInfo | null,

View File

@ -3,7 +3,7 @@ import { useIntl } from "react-intl";
import { useMutation, useQueryClient } from "react-query";
import { useSelector } from "react-redux";
import Client, { BasicMapInfo, ErrorInfo } from "../../../../client";
import { activeInstance } from '../../../../reducers/serviceSlice';
import { activeInstance } from '../../../../redux/clientSlice';
import { DialogProps, fetchMapById, handleOnMutationSuccess } from "..";
import Input from "../../../form/input";
import { FormControl } from "@material-ui/core";

View File

@ -9,15 +9,16 @@ import ListItem from '@material-ui/core/ListItem';
import ListItemIcon from '@material-ui/core/ListItemIcon';
import { useStyles } from './style';
import { AccountCircle, AcUnitTwoTone, AddCircleTwoTone, CloudUploadTwoTone, DeleteOutlineTwoTone, EmailOutlined, EmojiPeopleOutlined, ExitToAppOutlined, FeedbackOutlined, Help, LabelTwoTone, PeopleAltTwoTone, PersonAddTwoTone, PersonOutlineTwoTone, PersonTwoTone, PolicyOutlined, PublicTwoTone, SettingsApplicationsOutlined, ShareTwoTone, StarTwoTone } from '@material-ui/icons';
import { Button, Link, ListItemSecondaryAction, ListItemText, Menu, MenuItem, Tooltip } from '@material-ui/core';
import { Button, Dialog, DialogActions, DialogContent, DialogTitle, Link, ListItemSecondaryAction, ListItemText, Menu, MenuItem, Tooltip } from '@material-ui/core';
import { MapsList } from './maps-list';
import { FormattedMessage } from 'react-intl';
import { useQuery, useMutation, useQueryClient } from 'react-query';
import { activeInstance } from '../../reducers/serviceSlice';
import { activeInstance, activeInstanceStatus, ClientStatus } from '../../redux/clientSlice';
import { useSelector } from 'react-redux';
import Client, { Label } from '../../client';
import ActionDispatcher from './action-dispatcher';
import { ActionType } from './action-chooser';
import { Alert, AlertTitle } from '@material-ui/lab';
const logoIcon = require('../../images/logo-small.svg');
const poweredByIcon = require('../../images/pwrdby-white.svg');
@ -46,12 +47,10 @@ const MapsPage = () => {
const queryClient = useQueryClient();
const [activeDialog, setActiveDialog] = React.useState<ActionType | undefined>(undefined);
useEffect(() => {
document.title = 'Maps | WiseMapping';
}, []);
const mutation = useMutation(
(id: number) => client.deleteLabel(id),
{
@ -106,6 +105,7 @@ const MapsPage = () => {
return (
<div className={classes.root}>
<HandleClientStatus/>
<AppBar
position="fixed"
className={clsx(classes.appBar, {
@ -238,6 +238,46 @@ const StyleListItem = (props: ListItemProps) => {
);
}
const HandleClientStatus = () => {
const status: ClientStatus = useSelector(activeInstanceStatus);
const handleOnClose = () => {
window.location.href = '/c/login';
}
return (
<div>
<Dialog
open={status.state != 'healthy'}
onClose={handleOnClose}
maxWidth="sm"
fullWidth={true}>
<DialogTitle>
<FormattedMessage id="expired.title" defaultMessage="Your session has expired" />
</DialogTitle>
<DialogContent>
<Alert severity="error">
<AlertTitle><FormattedMessage id="expired.title" defaultMessage="Your current session has expired. Please, sign in and try again." /></AlertTitle>
</Alert>
</DialogContent>
<DialogActions>
<Button
type="button"
color="primary"
size="medium"
onClick={handleOnClose} >
<FormattedMessage id="action.close-button" defaultMessage="Close" />
</Button>
</DialogActions>
</Dialog>
</div>
)
}
const ProfileToobarButton = () => {
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
const open = Boolean(anchorEl);

View File

@ -18,7 +18,7 @@ import StarRateRoundedIcon from '@material-ui/icons/StarRateRounded';
import MoreHorizIcon from '@material-ui/icons/MoreHoriz';
import { CSSProperties } from 'react';
import { useSelector } from 'react-redux';
import { activeInstance } from '../../../reducers/serviceSlice';
import { activeInstance } from '../../../redux/clientSlice';
import { useMutation, useQuery, useQueryClient } from 'react-query';
import { ErrorInfo, MapInfo } from '../../../client';
import Client from '../../../client';
@ -30,6 +30,7 @@ import moment from 'moment'
import { Filter, LabelFilter } from '..';
import { FormattedMessage } from 'react-intl';
import { DeleteOutlined, LabelTwoTone } from '@material-ui/icons';
import Alert from '@material-ui/lab/Alert';
function descendingComparator<T>(a: T, b: T, orderBy: keyof T) {
@ -162,7 +163,7 @@ const mapsFilter = (filter: Filter, search: string): ((mapInfo: MapInfo) => bool
result = mapInfo.starred;
break;
case 'owned':
//@todo: complete ...
//@todo: complete ...
result = mapInfo.starred;
break;
@ -398,7 +399,7 @@ export const MapsList = (props: MapsListProps) => {
{isLoading ? (
<TableRow><TableCell colSpan={6}>Loading ...</TableCell></TableRow>) :
(mapsInfo.length == 0 ?
(<TableRow><TableCell colSpan={6} style={{ textAlign: 'center' }}><FormattedMessage id="maps.emptyresult" defaultMessage="No matching record found with the current filter criteria." /></TableCell></TableRow>) :
(<TableRow><TableCell colSpan={6} style={{ textAlign: 'center' }}><FormattedMessage id="maps.empty-result" defaultMessage="No matching record found with the current filter criteria." /></TableCell></TableRow>) :
stableSort(mapsInfo, getComparator(order, orderBy))
.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
.map((row: MapInfo) => {
@ -479,3 +480,9 @@ export const MapsList = (props: MapsListProps) => {
</div >
);
}
const ErrorDialog = (props) => {
return (<Alert severity="error">This is an error alert check it out!</Alert>);
}

View File

@ -11,7 +11,7 @@ import Footer from '../layout/footer';
import { FormControl, Typography } from '@material-ui/core';
import { useSelector } from 'react-redux';
import { useMutation } from 'react-query';
import { activeInstance } from '../../reducers/serviceSlice';
import { activeInstance } from '../../redux/clientSlice';
import Input from '../form/input';
import GlobalError from '../form/global-error';
import SubmitButton from '../form/submit-button';

View File

@ -1,5 +1,4 @@
import { createSlice, PayloadAction } from '@reduxjs/toolkit'
import axios from 'axios';
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
import Client from '../client';
import MockClient from '../client/mock-client';
import RestClient from '../client/rest-client';
@ -25,7 +24,7 @@ class RutimeConfig {
buildClient(): Client {
let result: Client;
if (this.config) {
result = new RestClient(this.config.apiBaseUrl, () => { console.log("401 error") });
result = new RestClient(this.config.apiBaseUrl, () => { sessionExpired() });
console.log("Service using rest client. " + JSON.stringify(this.config))
} else {
@ -36,27 +35,40 @@ class RutimeConfig {
}
}
interface ServiceState {
instance: Client;
export interface ClientStatus {
state: 'healthy' | 'session-expired';
msg?: string
}
const initialState: ServiceState = {
instance: new RutimeConfig().load().buildClient()
export interface ClientState {
instance: Client;
status: ClientStatus;
}
const initialState: ClientState = {
instance: new RutimeConfig().load().buildClient(),
status: { state: 'healthy' }
};
export const serviceSlice = createSlice({
name: "service",
export const clientSlice = createSlice({
name: "client",
initialState: initialState,
reducers: {
initialize(state, action: PayloadAction<void[]>) {
// state.instance = new RutimeConfig().load().buildClient()
sessionExpired(state, action: PayloadAction<void>) {
state.status = { state: 'session-expired', msg: 'Sessions has expired. You need to login again.' }
}
},
});
export const activeInstance = (state: any): Client => {
return state.service.instance;
return state.client.instance;
}
export default serviceSlice.reducer
export const activeInstanceStatus = (state: any): ClientStatus => {
return state.client.status;
}
export const { sessionExpired } = clientSlice.actions;
export default clientSlice.reducer;

View File

@ -0,0 +1,12 @@
import { configureStore } from '@reduxjs/toolkit';
import clientReducer from './clientSlice';
// Create Service object...
const store = configureStore({
reducer: {
client: clientReducer
}
});
export default store;

View File

@ -1,12 +0,0 @@
import { configureStore, getDefaultMiddleware } from '@reduxjs/toolkit';
import serviceReducer from './reducers/serviceSlice';
// Create Service object...
const store = configureStore({
reducer: {
service: serviceReducer
}
});
export default store;