mirror of
https://bitbucket.org/wisemapping/wisemapping-frontend.git
synced 2024-11-11 01:43:23 +01:00
Add error exception
This commit is contained in:
parent
6115eeec26
commit
680a679a92
@ -8,7 +8,7 @@ import ForgotPasswordSuccessPage from './components/forgot-password-success-page
|
|||||||
import RegistationPage from './components/registration-page';
|
import RegistationPage from './components/registration-page';
|
||||||
import LoginPage from './components/login-page';
|
import LoginPage from './components/login-page';
|
||||||
import MapsPage from './components/maps-page';
|
import MapsPage from './components/maps-page';
|
||||||
import store from "./store";
|
import store from "./redux/store";
|
||||||
import { ForgotPasswordPage } from './components/forgot-password-page';
|
import { ForgotPasswordPage } from './components/forgot-password-page';
|
||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
import { QueryClient, QueryClientProvider } from 'react-query';
|
import { QueryClient, QueryClientProvider } from 'react-query';
|
||||||
|
@ -13,7 +13,6 @@ export type Label = {
|
|||||||
iconName: string;
|
iconName: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export type MapInfo = {
|
export type MapInfo = {
|
||||||
id: number;
|
id: number;
|
||||||
starred: boolean;
|
starred: boolean;
|
||||||
|
@ -1,18 +1,23 @@
|
|||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { ErrorInfo, MapInfo, BasicMapInfo, NewUser, Label } from '..';
|
import { useIntl } from 'react-intl';
|
||||||
import MockClient from '../mock-client/';
|
import Client, { ErrorInfo, MapInfo, BasicMapInfo, NewUser, Label } from '..';
|
||||||
|
|
||||||
//@Remove inheritance once is it completed.
|
export default class RestClient implements Client {
|
||||||
export default class RestClient extends MockClient {
|
|
||||||
private baseUrl: string;
|
private baseUrl: string;
|
||||||
private authFailed: () => void
|
private sessionExpired: () => void
|
||||||
|
|
||||||
constructor(baseUrl: string, authFailed: () => void) {
|
|
||||||
super();
|
constructor(baseUrl: string, sessionExpired: () => void) {
|
||||||
this.baseUrl = baseUrl;
|
this.baseUrl = baseUrl;
|
||||||
|
this.sessionExpired = sessionExpired;
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchMapInfo(id: number): Promise<BasicMapInfo> {
|
||||||
|
throw new Error('Method not implemented.');
|
||||||
}
|
}
|
||||||
|
|
||||||
private parseResponseOnError = (response: any): ErrorInfo => {
|
private parseResponseOnError = (response: any): ErrorInfo => {
|
||||||
|
const intl = useIntl();
|
||||||
|
|
||||||
let result: ErrorInfo | undefined;
|
let result: ErrorInfo | undefined;
|
||||||
if (response) {
|
if (response) {
|
||||||
@ -22,7 +27,9 @@ export default class RestClient extends MockClient {
|
|||||||
|
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case 401:
|
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;
|
break;
|
||||||
default:
|
default:
|
||||||
if (data) {
|
if (data) {
|
||||||
|
@ -8,7 +8,7 @@ import Footer from '../layout/footer'
|
|||||||
import FormContainer from '../layout/form-container';
|
import FormContainer from '../layout/form-container';
|
||||||
import { useSelector } from 'react-redux'
|
import { useSelector } from 'react-redux'
|
||||||
import { useMutation } from 'react-query'
|
import { useMutation } from 'react-query'
|
||||||
import { activeInstance } from '../../reducers/serviceSlice'
|
import { activeInstance } from '../../redux/clientSlice'
|
||||||
import Input from '../form/input'
|
import Input from '../form/input'
|
||||||
import GlobalError from '../form/global-error'
|
import GlobalError from '../form/global-error'
|
||||||
import SubmitButton from '../form/submit-button'
|
import SubmitButton from '../form/submit-button'
|
||||||
|
@ -6,7 +6,7 @@ import { FormControl } from '@material-ui/core';
|
|||||||
|
|
||||||
|
|
||||||
import Client, { BasicMapInfo, ErrorInfo } from '../../../../client';
|
import Client, { BasicMapInfo, ErrorInfo } from '../../../../client';
|
||||||
import { activeInstance } from '../../../../reducers/serviceSlice';
|
import { activeInstance } from '../../../../redux/clientSlice';
|
||||||
import Input from '../../../form/input';
|
import Input from '../../../form/input';
|
||||||
import BaseDialog from '../base-dialog';
|
import BaseDialog from '../base-dialog';
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ import { FormattedMessage, useIntl } from "react-intl";
|
|||||||
import { useMutation, useQueryClient } from "react-query";
|
import { useMutation, useQueryClient } from "react-query";
|
||||||
import { useSelector } from "react-redux";
|
import { useSelector } from "react-redux";
|
||||||
import Client from "../../../../client";
|
import Client from "../../../../client";
|
||||||
import { activeInstance } from '../../../../reducers/serviceSlice';
|
import { activeInstance } from '../../../../redux/clientSlice';
|
||||||
import { DialogProps, fetchMapById, handleOnMutationSuccess } from "..";
|
import { DialogProps, fetchMapById, handleOnMutationSuccess } from "..";
|
||||||
import BaseDialog from "../base-dialog";
|
import BaseDialog from "../base-dialog";
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ import { FormControl } from "@material-ui/core";
|
|||||||
import { useSelector } from "react-redux";
|
import { useSelector } from "react-redux";
|
||||||
|
|
||||||
import Client, { BasicMapInfo, ErrorInfo } from "../../../../client";
|
import Client, { BasicMapInfo, ErrorInfo } from "../../../../client";
|
||||||
import { activeInstance } from '../../../../reducers/serviceSlice';
|
import { activeInstance } from '../../../../redux/clientSlice';
|
||||||
import Input from "../../../form/input";
|
import Input from "../../../form/input";
|
||||||
import { DialogProps, fetchMapById } from "..";
|
import { DialogProps, fetchMapById } from "..";
|
||||||
import BaseDialog from "../base-dialog";
|
import BaseDialog from "../base-dialog";
|
||||||
|
@ -6,7 +6,7 @@ import { ErrorInfo, MapInfo } from '../../../client';
|
|||||||
import Client from '../../../client';
|
import Client from '../../../client';
|
||||||
import { useSelector } from "react-redux";
|
import { useSelector } from "react-redux";
|
||||||
import { QueryClient, useQuery } from 'react-query';
|
import { QueryClient, useQuery } from 'react-query';
|
||||||
import { activeInstance } from '../../../reducers/serviceSlice';
|
import { activeInstance } from '../../../redux/clientSlice';
|
||||||
import DuplicateDialog from './duplicate-dialog';
|
import DuplicateDialog from './duplicate-dialog';
|
||||||
import { useHistory } from 'react-router-dom';
|
import { useHistory } from 'react-router-dom';
|
||||||
import CreateDialog from './create-dialog';
|
import CreateDialog from './create-dialog';
|
||||||
@ -49,8 +49,6 @@ const ActionDispatcher = (props: ActionDialogProps) => {
|
|||||||
</span >
|
</span >
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
type MapLoadResult = {
|
type MapLoadResult = {
|
||||||
isLoading: boolean,
|
isLoading: boolean,
|
||||||
error: ErrorInfo | null,
|
error: ErrorInfo | null,
|
||||||
|
@ -3,7 +3,7 @@ import { useIntl } from "react-intl";
|
|||||||
import { useMutation, useQueryClient } from "react-query";
|
import { useMutation, useQueryClient } from "react-query";
|
||||||
import { useSelector } from "react-redux";
|
import { useSelector } from "react-redux";
|
||||||
import Client, { BasicMapInfo, ErrorInfo } from "../../../../client";
|
import Client, { BasicMapInfo, ErrorInfo } from "../../../../client";
|
||||||
import { activeInstance } from '../../../../reducers/serviceSlice';
|
import { activeInstance } from '../../../../redux/clientSlice';
|
||||||
import { DialogProps, fetchMapById, handleOnMutationSuccess } from "..";
|
import { DialogProps, fetchMapById, handleOnMutationSuccess } from "..";
|
||||||
import Input from "../../../form/input";
|
import Input from "../../../form/input";
|
||||||
import { FormControl } from "@material-ui/core";
|
import { FormControl } from "@material-ui/core";
|
||||||
|
@ -9,15 +9,16 @@ import ListItem from '@material-ui/core/ListItem';
|
|||||||
import ListItemIcon from '@material-ui/core/ListItemIcon';
|
import ListItemIcon from '@material-ui/core/ListItemIcon';
|
||||||
import { useStyles } from './style';
|
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 { 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 { MapsList } from './maps-list';
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
import { useQuery, useMutation, useQueryClient } from 'react-query';
|
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 { useSelector } from 'react-redux';
|
||||||
import Client, { Label } from '../../client';
|
import Client, { Label } from '../../client';
|
||||||
import ActionDispatcher from './action-dispatcher';
|
import ActionDispatcher from './action-dispatcher';
|
||||||
import { ActionType } from './action-chooser';
|
import { ActionType } from './action-chooser';
|
||||||
|
import { Alert, AlertTitle } from '@material-ui/lab';
|
||||||
|
|
||||||
const logoIcon = require('../../images/logo-small.svg');
|
const logoIcon = require('../../images/logo-small.svg');
|
||||||
const poweredByIcon = require('../../images/pwrdby-white.svg');
|
const poweredByIcon = require('../../images/pwrdby-white.svg');
|
||||||
@ -46,12 +47,10 @@ const MapsPage = () => {
|
|||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
const [activeDialog, setActiveDialog] = React.useState<ActionType | undefined>(undefined);
|
const [activeDialog, setActiveDialog] = React.useState<ActionType | undefined>(undefined);
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
document.title = 'Maps | WiseMapping';
|
document.title = 'Maps | WiseMapping';
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
|
||||||
const mutation = useMutation(
|
const mutation = useMutation(
|
||||||
(id: number) => client.deleteLabel(id),
|
(id: number) => client.deleteLabel(id),
|
||||||
{
|
{
|
||||||
@ -106,6 +105,7 @@ const MapsPage = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classes.root}>
|
<div className={classes.root}>
|
||||||
|
<HandleClientStatus/>
|
||||||
<AppBar
|
<AppBar
|
||||||
position="fixed"
|
position="fixed"
|
||||||
className={clsx(classes.appBar, {
|
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 ProfileToobarButton = () => {
|
||||||
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
|
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
|
||||||
const open = Boolean(anchorEl);
|
const open = Boolean(anchorEl);
|
||||||
|
@ -18,7 +18,7 @@ import StarRateRoundedIcon from '@material-ui/icons/StarRateRounded';
|
|||||||
import MoreHorizIcon from '@material-ui/icons/MoreHoriz';
|
import MoreHorizIcon from '@material-ui/icons/MoreHoriz';
|
||||||
import { CSSProperties } from 'react';
|
import { CSSProperties } from 'react';
|
||||||
import { useSelector } from 'react-redux';
|
import { useSelector } from 'react-redux';
|
||||||
import { activeInstance } from '../../../reducers/serviceSlice';
|
import { activeInstance } from '../../../redux/clientSlice';
|
||||||
import { useMutation, useQuery, useQueryClient } from 'react-query';
|
import { useMutation, useQuery, useQueryClient } from 'react-query';
|
||||||
import { ErrorInfo, MapInfo } from '../../../client';
|
import { ErrorInfo, MapInfo } from '../../../client';
|
||||||
import Client from '../../../client';
|
import Client from '../../../client';
|
||||||
@ -30,6 +30,7 @@ import moment from 'moment'
|
|||||||
import { Filter, LabelFilter } from '..';
|
import { Filter, LabelFilter } from '..';
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
import { DeleteOutlined, LabelTwoTone } from '@material-ui/icons';
|
import { DeleteOutlined, LabelTwoTone } from '@material-ui/icons';
|
||||||
|
import Alert from '@material-ui/lab/Alert';
|
||||||
|
|
||||||
|
|
||||||
function descendingComparator<T>(a: T, b: T, orderBy: keyof T) {
|
function descendingComparator<T>(a: T, b: T, orderBy: keyof T) {
|
||||||
@ -398,7 +399,7 @@ export const MapsList = (props: MapsListProps) => {
|
|||||||
{isLoading ? (
|
{isLoading ? (
|
||||||
<TableRow><TableCell colSpan={6}>Loading ...</TableCell></TableRow>) :
|
<TableRow><TableCell colSpan={6}>Loading ...</TableCell></TableRow>) :
|
||||||
(mapsInfo.length == 0 ?
|
(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))
|
stableSort(mapsInfo, getComparator(order, orderBy))
|
||||||
.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
|
.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
|
||||||
.map((row: MapInfo) => {
|
.map((row: MapInfo) => {
|
||||||
@ -479,3 +480,9 @@ export const MapsList = (props: MapsListProps) => {
|
|||||||
</div >
|
</div >
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ErrorDialog = (props) => {
|
||||||
|
|
||||||
|
return (<Alert severity="error">This is an error alert — check it out!</Alert>);
|
||||||
|
|
||||||
|
}
|
@ -11,7 +11,7 @@ import Footer from '../layout/footer';
|
|||||||
import { FormControl, Typography } from '@material-ui/core';
|
import { FormControl, Typography } from '@material-ui/core';
|
||||||
import { useSelector } from 'react-redux';
|
import { useSelector } from 'react-redux';
|
||||||
import { useMutation } from 'react-query';
|
import { useMutation } from 'react-query';
|
||||||
import { activeInstance } from '../../reducers/serviceSlice';
|
import { activeInstance } from '../../redux/clientSlice';
|
||||||
import Input from '../form/input';
|
import Input from '../form/input';
|
||||||
import GlobalError from '../form/global-error';
|
import GlobalError from '../form/global-error';
|
||||||
import SubmitButton from '../form/submit-button';
|
import SubmitButton from '../form/submit-button';
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { createSlice, PayloadAction } from '@reduxjs/toolkit'
|
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
|
||||||
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';
|
import RestClient from '../client/rest-client';
|
||||||
@ -25,7 +24,7 @@ class RutimeConfig {
|
|||||||
buildClient(): Client {
|
buildClient(): Client {
|
||||||
let result: Client;
|
let result: Client;
|
||||||
if (this.config) {
|
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))
|
console.log("Service using rest client. " + JSON.stringify(this.config))
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@ -36,27 +35,40 @@ class RutimeConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ServiceState {
|
export interface ClientStatus {
|
||||||
instance: Client;
|
state: 'healthy' | 'session-expired';
|
||||||
|
msg?: string
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const initialState: ServiceState = {
|
export interface ClientState {
|
||||||
instance: new RutimeConfig().load().buildClient()
|
instance: Client;
|
||||||
|
status: ClientStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
const initialState: ClientState = {
|
||||||
|
instance: new RutimeConfig().load().buildClient(),
|
||||||
|
status: { state: 'healthy' }
|
||||||
};
|
};
|
||||||
|
|
||||||
export const serviceSlice = createSlice({
|
export const clientSlice = createSlice({
|
||||||
name: "service",
|
name: "client",
|
||||||
initialState: initialState,
|
initialState: initialState,
|
||||||
reducers: {
|
reducers: {
|
||||||
initialize(state, action: PayloadAction<void[]>) {
|
sessionExpired(state, action: PayloadAction<void>) {
|
||||||
// state.instance = new RutimeConfig().load().buildClient()
|
state.status = { state: 'session-expired', msg: 'Sessions has expired. You need to login again.' }
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export const activeInstance = (state: any): Client => {
|
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;
|
||||||
|
|
12
packages/webapp/src/redux/store.ts
Normal file
12
packages/webapp/src/redux/store.ts
Normal 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;
|
@ -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;
|
|
Loading…
Reference in New Issue
Block a user