From 680a679a92169bd85ca3d71f4c96cca3477ac55a Mon Sep 17 00:00:00 2001 From: Paulo Gustavo Veiga Date: Thu, 4 Feb 2021 23:05:46 -0800 Subject: [PATCH] Add error exception --- packages/webapp/src/app.tsx | 2 +- packages/webapp/src/client/index.ts | 1 - .../webapp/src/client/rest-client/index.ts | 25 ++++++---- .../components/forgot-password-page/index.tsx | 2 +- .../action-dispatcher/create-dialog/index.tsx | 2 +- .../action-dispatcher/delete-dialog/index.tsx | 2 +- .../duplicate-dialog/index.tsx | 2 +- .../maps-page/action-dispatcher/index.tsx | 4 +- .../action-dispatcher/rename/index.tsx | 2 +- .../webapp/src/components/maps-page/index.tsx | 48 +++++++++++++++++-- .../components/maps-page/maps-list/index.tsx | 13 +++-- .../components/registration-page/index.tsx | 2 +- .../serviceSlice.ts => redux/clientSlice.ts} | 38 ++++++++++----- packages/webapp/src/redux/store.ts | 12 +++++ packages/webapp/src/store.ts | 12 ----- 15 files changed, 115 insertions(+), 52 deletions(-) rename packages/webapp/src/{reducers/serviceSlice.ts => redux/clientSlice.ts} (50%) create mode 100644 packages/webapp/src/redux/store.ts delete mode 100644 packages/webapp/src/store.ts diff --git a/packages/webapp/src/app.tsx b/packages/webapp/src/app.tsx index d09fa273..e382b1d6 100644 --- a/packages/webapp/src/app.tsx +++ b/packages/webapp/src/app.tsx @@ -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'; diff --git a/packages/webapp/src/client/index.ts b/packages/webapp/src/client/index.ts index f8ac4dbe..df8e0cb2 100644 --- a/packages/webapp/src/client/index.ts +++ b/packages/webapp/src/client/index.ts @@ -13,7 +13,6 @@ export type Label = { iconName: string; } - export type MapInfo = { id: number; starred: boolean; diff --git a/packages/webapp/src/client/rest-client/index.ts b/packages/webapp/src/client/rest-client/index.ts index a3f7f6ad..be8a760a 100644 --- a/packages/webapp/src/client/rest-client/index.ts +++ b/packages/webapp/src/client/rest-client/index.ts @@ -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 { + 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) { diff --git a/packages/webapp/src/components/forgot-password-page/index.tsx b/packages/webapp/src/components/forgot-password-page/index.tsx index e9849cd1..6469cb9f 100644 --- a/packages/webapp/src/components/forgot-password-page/index.tsx +++ b/packages/webapp/src/components/forgot-password-page/index.tsx @@ -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' diff --git a/packages/webapp/src/components/maps-page/action-dispatcher/create-dialog/index.tsx b/packages/webapp/src/components/maps-page/action-dispatcher/create-dialog/index.tsx index 25cabca9..a51bcbb1 100644 --- a/packages/webapp/src/components/maps-page/action-dispatcher/create-dialog/index.tsx +++ b/packages/webapp/src/components/maps-page/action-dispatcher/create-dialog/index.tsx @@ -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'; diff --git a/packages/webapp/src/components/maps-page/action-dispatcher/delete-dialog/index.tsx b/packages/webapp/src/components/maps-page/action-dispatcher/delete-dialog/index.tsx index 73c01a52..4b898678 100644 --- a/packages/webapp/src/components/maps-page/action-dispatcher/delete-dialog/index.tsx +++ b/packages/webapp/src/components/maps-page/action-dispatcher/delete-dialog/index.tsx @@ -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"; diff --git a/packages/webapp/src/components/maps-page/action-dispatcher/duplicate-dialog/index.tsx b/packages/webapp/src/components/maps-page/action-dispatcher/duplicate-dialog/index.tsx index cc6c7fdf..ed9b20dd 100644 --- a/packages/webapp/src/components/maps-page/action-dispatcher/duplicate-dialog/index.tsx +++ b/packages/webapp/src/components/maps-page/action-dispatcher/duplicate-dialog/index.tsx @@ -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"; diff --git a/packages/webapp/src/components/maps-page/action-dispatcher/index.tsx b/packages/webapp/src/components/maps-page/action-dispatcher/index.tsx index 4ed88f21..162750db 100644 --- a/packages/webapp/src/components/maps-page/action-dispatcher/index.tsx +++ b/packages/webapp/src/components/maps-page/action-dispatcher/index.tsx @@ -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) => { ); } - - type MapLoadResult = { isLoading: boolean, error: ErrorInfo | null, diff --git a/packages/webapp/src/components/maps-page/action-dispatcher/rename/index.tsx b/packages/webapp/src/components/maps-page/action-dispatcher/rename/index.tsx index af818c07..0cc36808 100644 --- a/packages/webapp/src/components/maps-page/action-dispatcher/rename/index.tsx +++ b/packages/webapp/src/components/maps-page/action-dispatcher/rename/index.tsx @@ -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"; diff --git a/packages/webapp/src/components/maps-page/index.tsx b/packages/webapp/src/components/maps-page/index.tsx index 8c92749a..bd1b1c12 100644 --- a/packages/webapp/src/components/maps-page/index.tsx +++ b/packages/webapp/src/components/maps-page/index.tsx @@ -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(undefined); - useEffect(() => { document.title = 'Maps | WiseMapping'; }, []); - const mutation = useMutation( (id: number) => client.deleteLabel(id), { @@ -106,6 +105,7 @@ const MapsPage = () => { return (
+ { ); } +const HandleClientStatus = () => { + const status: ClientStatus = useSelector(activeInstanceStatus); + + const handleOnClose = () => { + window.location.href = '/c/login'; + } + + return ( +
+ + + + + + + + + + + + + + + + + +
+ ) +} + const ProfileToobarButton = () => { const [anchorEl, setAnchorEl] = React.useState(null); const open = Boolean(anchorEl); diff --git a/packages/webapp/src/components/maps-page/maps-list/index.tsx b/packages/webapp/src/components/maps-page/maps-list/index.tsx index 0befc98e..1ba32f8c 100644 --- a/packages/webapp/src/components/maps-page/maps-list/index.tsx +++ b/packages/webapp/src/components/maps-page/maps-list/index.tsx @@ -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(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 ? ( Loading ...) : (mapsInfo.length == 0 ? - () : + () : stableSort(mapsInfo, getComparator(order, orderBy)) .slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage) .map((row: MapInfo) => { @@ -478,4 +479,10 @@ export const MapsList = (props: MapsListProps) => { setActiveDialog(undefined)} mapId={activeDialog ? activeDialog.mapId : -1} />
); +} + +const ErrorDialog = (props) => { + + return (This is an error alert — check it out!); + } \ No newline at end of file diff --git a/packages/webapp/src/components/registration-page/index.tsx b/packages/webapp/src/components/registration-page/index.tsx index a8dee267..54d2e047 100644 --- a/packages/webapp/src/components/registration-page/index.tsx +++ b/packages/webapp/src/components/registration-page/index.tsx @@ -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'; diff --git a/packages/webapp/src/reducers/serviceSlice.ts b/packages/webapp/src/redux/clientSlice.ts similarity index 50% rename from packages/webapp/src/reducers/serviceSlice.ts rename to packages/webapp/src/redux/clientSlice.ts index 082a58cd..4bfb3329 100644 --- a/packages/webapp/src/reducers/serviceSlice.ts +++ b/packages/webapp/src/redux/clientSlice.ts @@ -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) { - // state.instance = new RutimeConfig().load().buildClient() + sessionExpired(state, action: PayloadAction) { + 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; diff --git a/packages/webapp/src/redux/store.ts b/packages/webapp/src/redux/store.ts new file mode 100644 index 00000000..f28c1642 --- /dev/null +++ b/packages/webapp/src/redux/store.ts @@ -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; \ No newline at end of file diff --git a/packages/webapp/src/store.ts b/packages/webapp/src/store.ts deleted file mode 100644 index a9afbf8d..00000000 --- a/packages/webapp/src/store.ts +++ /dev/null @@ -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; \ No newline at end of file