mirror of
https://bitbucket.org/wisemapping/wisemapping-frontend.git
synced 2024-11-11 01:43:23 +01:00
Redux initial refactor
This commit is contained in:
parent
fed51ad5a9
commit
60fd57b094
@ -1,4 +1,55 @@
|
||||
{
|
||||
"action.cancel-button": {
|
||||
"defaultMessage": "Cancel"
|
||||
},
|
||||
"action.delete": {
|
||||
"defaultMessage": "Delete"
|
||||
},
|
||||
"action.delete-button": {
|
||||
"defaultMessage": "Delete"
|
||||
},
|
||||
"action.delete-description": {
|
||||
"defaultMessage": "Deleted mindmap can not be recovered. Do you want to continue ?."
|
||||
},
|
||||
"action.delete-title": {
|
||||
"defaultMessage": "Delete"
|
||||
},
|
||||
"action.duplicate": {
|
||||
"defaultMessage": "Duplicate"
|
||||
},
|
||||
"action.export": {
|
||||
"defaultMessage": "Export"
|
||||
},
|
||||
"action.open": {
|
||||
"defaultMessage": "Open"
|
||||
},
|
||||
"action.print": {
|
||||
"defaultMessage": "Print"
|
||||
},
|
||||
"action.publish": {
|
||||
"defaultMessage": "Publish"
|
||||
},
|
||||
"action.rename": {
|
||||
"defaultMessage": "Rename"
|
||||
},
|
||||
"action.rename-button": {
|
||||
"defaultMessage": "Rename"
|
||||
},
|
||||
"action.rename-description": {
|
||||
"defaultMessage": "Please, update the name and description for your mindmap."
|
||||
},
|
||||
"action.rename-description-placeholder": {
|
||||
"defaultMessage": "Description"
|
||||
},
|
||||
"action.rename-name-placeholder": {
|
||||
"defaultMessage": "Name"
|
||||
},
|
||||
"action.rename-title": {
|
||||
"defaultMessage": "Rename"
|
||||
},
|
||||
"action.share": {
|
||||
"defaultMessage": "Info"
|
||||
},
|
||||
"common.wait": {
|
||||
"defaultMessage": "Please wait ..."
|
||||
},
|
||||
@ -57,7 +108,7 @@
|
||||
"defaultMessage": "Email"
|
||||
},
|
||||
"login.error": {
|
||||
"defaultMessage": "The login.email address or login.password you entered is not valid."
|
||||
"defaultMessage": "The email address or password you entered is not valid."
|
||||
},
|
||||
"login.forgotpwd": {
|
||||
"defaultMessage": "Forgot Password ?"
|
||||
@ -82,7 +133,7 @@
|
||||
"defaultMessage": "Welcome"
|
||||
},
|
||||
"login.userinactive": {
|
||||
"defaultMessage": "Sorry, your account has not been activated yet. You'll receive a notification login.email when it becomes active. Stay tuned!."
|
||||
"defaultMessage": "Sorry, your account has not been activated yet. You'll receive a notification email when it becomes active. Stay tuned!."
|
||||
},
|
||||
"registration.desc": {
|
||||
"defaultMessage": "Signing up is free and just take a moment"
|
||||
|
@ -48,13 +48,15 @@
|
||||
"@material-ui/core": "^4.11.2",
|
||||
"@material-ui/icons": "^4.11.2",
|
||||
"@material-ui/lab": "^4.0.0-alpha.57",
|
||||
"@reduxjs/toolkit": "^1.5.0",
|
||||
"@types/axios": "^0.14.0",
|
||||
"@types/react-google-recaptcha": "^2.1.0",
|
||||
"axios": "^0.21.0",
|
||||
"react": "^17.0.1",
|
||||
"react-dom": "^17.0.1",
|
||||
"react-google-recaptcha": "^2.1.0",
|
||||
"react-intl": "^5.10.6",
|
||||
"react-redux": "^7.2.2",
|
||||
"react-router-dom": "^5.2.0",
|
||||
"styled-components": "^5.2.1"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,4 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Service, RestService } from './services/Service';
|
||||
import { IntlProvider } from 'react-intl'
|
||||
|
||||
import { GlobalStyle } from './theme/global-style';
|
||||
@ -7,7 +6,8 @@ import RegistrationSuccessPage from './components/registration-success-page';
|
||||
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 MapsPage from './components/maps-page';
|
||||
import store from "./store"
|
||||
|
||||
import {
|
||||
Route,
|
||||
@ -17,6 +17,7 @@ import {
|
||||
} from 'react-router-dom';
|
||||
|
||||
import { ForgotPasswordPage } from './components/forgot-password-page';
|
||||
import { Provider } from 'react-redux';
|
||||
|
||||
function loadLocaleData(language: string) {
|
||||
switch (language) {
|
||||
@ -25,13 +26,13 @@ function loadLocaleData(language: string) {
|
||||
default:
|
||||
return require('./compiled-lang/en.json')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type AppProps = {
|
||||
baseRestUrl: string;
|
||||
}
|
||||
|
||||
const App = (props: AppProps) => {
|
||||
const App = () => {
|
||||
const [messages, setMessages] = useState(undefined);
|
||||
|
||||
// Boostrap i18n ...
|
||||
@ -50,33 +51,32 @@ const App = (props: AppProps) => {
|
||||
fetchData();
|
||||
}, []);
|
||||
|
||||
// Create Service object...
|
||||
|
||||
const service: Service = new RestService(props.baseRestUrl, () => { console.log("401 error") });
|
||||
|
||||
return messages ? (
|
||||
<IntlProvider locale={locale} defaultLocale='en' messages={messages}>
|
||||
<GlobalStyle />
|
||||
<Router>
|
||||
<Switch>
|
||||
<Route exact path="/">
|
||||
<Redirect to="/c/login" />
|
||||
</Route>
|
||||
<Route path="/c/login" component={LoginPage} />
|
||||
<Route path="/c/registration">
|
||||
<RegistationPage service={service} />
|
||||
</Route>
|
||||
<Route path="/c/registration-success" component={RegistrationSuccessPage} />
|
||||
<Route path="/c/forgot-password">
|
||||
<ForgotPasswordPage service={service} />
|
||||
</Route>
|
||||
<Route path="/c/forgot-password-success" component={ForgotPasswordSuccessPage} />
|
||||
<Route path="/c/maps/">
|
||||
<MapsPage service={service} />
|
||||
</Route>
|
||||
</Switch>
|
||||
</Router>
|
||||
</IntlProvider>
|
||||
<Provider store={store}>
|
||||
<IntlProvider locale={locale} defaultLocale='en' messages={messages}>
|
||||
<GlobalStyle />
|
||||
<Router>
|
||||
<Switch>
|
||||
<Route exact path="/">
|
||||
<Redirect to="/c/login" />
|
||||
</Route>
|
||||
<Route path="/c/login" component={LoginPage} />
|
||||
<Route path="/c/registration">
|
||||
<RegistationPage />
|
||||
</Route>
|
||||
<Route path="/c/registration-success" component={RegistrationSuccessPage} />
|
||||
<Route path="/c/forgot-password">
|
||||
<ForgotPasswordPage />
|
||||
</Route>
|
||||
<Route path="/c/forgot-password-success" component={ForgotPasswordSuccessPage} />
|
||||
<Route path="/c/maps/">
|
||||
<MapsPage />
|
||||
</Route>
|
||||
</Switch>
|
||||
</Router>
|
||||
</IntlProvider>
|
||||
</Provider>
|
||||
|
||||
) : <div>Loading ... </div>
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,106 @@
|
||||
{
|
||||
"action.cancel-button": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Cancel"
|
||||
}
|
||||
],
|
||||
"action.delete": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Delete"
|
||||
}
|
||||
],
|
||||
"action.delete-button": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Delete"
|
||||
}
|
||||
],
|
||||
"action.delete-description": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Deleted mindmap can not be recovered. Do you want to continue ?."
|
||||
}
|
||||
],
|
||||
"action.delete-title": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Delete"
|
||||
}
|
||||
],
|
||||
"action.duplicate": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Duplicate"
|
||||
}
|
||||
],
|
||||
"action.export": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Export"
|
||||
}
|
||||
],
|
||||
"action.open": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Open"
|
||||
}
|
||||
],
|
||||
"action.print": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Print"
|
||||
}
|
||||
],
|
||||
"action.publish": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Publish"
|
||||
}
|
||||
],
|
||||
"action.rename": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Rename"
|
||||
}
|
||||
],
|
||||
"action.rename-button": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Rename"
|
||||
}
|
||||
],
|
||||
"action.rename-description": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Please, update the name and description for your mindmap."
|
||||
}
|
||||
],
|
||||
"action.rename-description-placeholder": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Description"
|
||||
}
|
||||
],
|
||||
"action.rename-name-placeholder": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Name"
|
||||
}
|
||||
],
|
||||
"action.rename-title": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Rename"
|
||||
}
|
||||
],
|
||||
"action.share": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Info"
|
||||
}
|
||||
],
|
||||
"common.wait": [
|
||||
{
|
||||
"type": 0,
|
||||
@ -116,7 +218,7 @@
|
||||
"login.error": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "The login.email address or login.password you entered is not valid."
|
||||
"value": "The email address or password you entered is not valid."
|
||||
}
|
||||
],
|
||||
"login.forgotpwd": [
|
||||
@ -164,7 +266,7 @@
|
||||
"login.userinactive": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Sorry, your account has not been activated yet. You'll receive a notification login.email when it becomes active. Stay tuned!."
|
||||
"value": "Sorry, your account has not been activated yet. You'll receive a notification email when it becomes active. Stay tuned!."
|
||||
}
|
||||
],
|
||||
"registration.desc": [
|
||||
|
@ -13,7 +13,7 @@ type ForgotPasswordProps = {
|
||||
email: string;
|
||||
}
|
||||
|
||||
const ForgotPassword = (props: ServiceProps) => {
|
||||
const ForgotPassword = () => {
|
||||
const [email, setEmail] = useState('');
|
||||
const [errorMsg, setErrorMsg] = useState('');
|
||||
const [disableButton, setDisableButton] = useState(false);
|
||||
@ -26,20 +26,20 @@ const ForgotPassword = (props: ServiceProps) => {
|
||||
setDisableButton(true);
|
||||
|
||||
// Call Service ...
|
||||
const service = props.service;
|
||||
service.resetPassword(email)
|
||||
.then(() => {
|
||||
history.push("/c/forgot-password-success");
|
||||
}).catch((error: ErrorInfo) => {
|
||||
setErrorMsg(error.msg ? error.msg : '');
|
||||
setDisableButton(false);
|
||||
});
|
||||
// const service = props.service;
|
||||
// service.resetPassword(email)
|
||||
// .then(() => {
|
||||
// history.push("/c/forgot-password-success");
|
||||
// }).catch((error: ErrorInfo) => {
|
||||
// setErrorMsg(error.msg ? error.msg : '');
|
||||
// setDisableButton(false);
|
||||
// });
|
||||
}
|
||||
|
||||
return (
|
||||
<PageContent>
|
||||
<h1><FormattedMessage id="forgot.title" defaultMessage="Reset your password"/></h1>
|
||||
<p><FormattedMessage id="forgot.desc" defaultMessage="We will send you an email to reset your password"/></p>
|
||||
<h1><FormattedMessage id="forgot.title" defaultMessage="Reset your password" /></h1>
|
||||
<p><FormattedMessage id="forgot.desc" defaultMessage="We will send you an email to reset your password" /></p>
|
||||
|
||||
<form onSubmit={handleOnSubmit}>
|
||||
<input type="email" name="email" onChange={e => setEmail(e.target.value)} placeholder={intl.formatMessage({ id: "forgot.email", defaultMessage: "Email" })} required={true} autoComplete="email" />
|
||||
@ -55,7 +55,7 @@ const ForgotPassword = (props: ServiceProps) => {
|
||||
type ServiceProps = {
|
||||
service: Service
|
||||
}
|
||||
const ForgotPasswordPage = (props: ServiceProps) => {
|
||||
const ForgotPasswordPage = () => {
|
||||
|
||||
useEffect(() => {
|
||||
document.title = 'Reset Password | WiseMapping';
|
||||
@ -64,7 +64,7 @@ const ForgotPasswordPage = (props: ServiceProps) => {
|
||||
return (
|
||||
<div>
|
||||
<Header type='only-signin' />
|
||||
<ForgotPassword service={props.service} />
|
||||
<ForgotPassword />
|
||||
<Footer />
|
||||
</div>
|
||||
);
|
||||
|
@ -6,26 +6,41 @@ import DialogContent from '@material-ui/core/DialogContent';
|
||||
import DialogContentText from '@material-ui/core/DialogContentText';
|
||||
import DialogTitle from '@material-ui/core/DialogTitle';
|
||||
import { FormattedMessage, useIntl } from 'react-intl';
|
||||
import { BasicMapInfo, ErrorInfo, Service } from '../../services/Service';
|
||||
import { ErrorInfo, MapInfo, Service } from '../../services/Service';
|
||||
import { FormControl, TextField } from '@material-ui/core';
|
||||
import { Alert, AlertTitle } from '@material-ui/lab';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import {
|
||||
allMaps,
|
||||
remove,
|
||||
rename
|
||||
} from '../../reducers/mapsListSlice'
|
||||
import { Description } from '@material-ui/icons';
|
||||
|
||||
|
||||
type DialogProps = {
|
||||
open: boolean,
|
||||
mapId: number,
|
||||
onClose: (reload: boolean) => void,
|
||||
service: Service
|
||||
onClose: () => void
|
||||
}
|
||||
|
||||
function DeleteConfirmDialog(props: DialogProps) {
|
||||
export type BasicMapInfo = {
|
||||
name: string;
|
||||
description: string | undefined;
|
||||
}
|
||||
|
||||
function DeleteDialog(props: DialogProps) {
|
||||
const dispatch = useDispatch()
|
||||
const mapId = props.mapId;
|
||||
|
||||
const mapInfo: MapInfo | undefined = useSelector(allMaps).
|
||||
find(m => m.id == mapId);
|
||||
|
||||
const handleOnClose = (action: 'accept' | undefined): void => {
|
||||
let result = false;
|
||||
if (action == 'accept') {
|
||||
props.service.deleteMap(props.mapId);
|
||||
result = true;
|
||||
if (action == 'accept' && mapInfo) {
|
||||
dispatch(remove({ id: mapId }))
|
||||
}
|
||||
props.onClose(result);
|
||||
props.onClose();
|
||||
};
|
||||
|
||||
return (
|
||||
@ -35,12 +50,10 @@ function DeleteConfirmDialog(props: DialogProps) {
|
||||
onClose={() => handleOnClose(undefined)} >
|
||||
<DialogTitle><FormattedMessage id="action.delete-title" defaultMessage="Delete" /></DialogTitle>
|
||||
<DialogContent>
|
||||
<DialogContentText>
|
||||
<Alert severity="warning">
|
||||
<AlertTitle>Map to be deleted</AlertTitle>
|
||||
<FormattedMessage id="action.delete-description" defaultMessage="Deleted mindmap can not be recovered. Do you want to continue ?." />
|
||||
</Alert>
|
||||
</DialogContentText>
|
||||
<Alert severity="warning">
|
||||
<AlertTitle>Delete '{mapInfo?.name}'</AlertTitle>
|
||||
<FormattedMessage id="action.delete-description" defaultMessage="Deleted mindmap can not be recovered. Do you want to continue ?." />
|
||||
</Alert>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={() => handleOnClose('accept')} variant="outlined" color="primary">
|
||||
@ -54,19 +67,32 @@ function DeleteConfirmDialog(props: DialogProps) {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
export type RenameModel = {
|
||||
id: number;
|
||||
name: string;
|
||||
description?: string;
|
||||
}
|
||||
|
||||
function RenameDialog(props: DialogProps) {
|
||||
const defaultModel: BasicMapInfo = { name: '', description: '' };
|
||||
const [model, setModel] = React.useState<BasicMapInfo>(defaultModel);
|
||||
const [errorInfo, setErroInfo] = React.useState<ErrorInfo>();
|
||||
|
||||
const defaultModel: RenameModel = { name: '', description: '', id: -1 };
|
||||
const [model, setModel] = React.useState<RenameModel>(defaultModel);
|
||||
const [errorInfo, setErroInfo] = React.useState<ErrorInfo>();
|
||||
const dispatch = useDispatch()
|
||||
const intl = useIntl();
|
||||
|
||||
useEffect(() => {
|
||||
props.service.loadMapInfo(props.mapId)
|
||||
.then((info: BasicMapInfo) => {
|
||||
setModel(info);
|
||||
})
|
||||
const mapId: number = props.mapId;
|
||||
if (mapId != -1) {
|
||||
const mapInfo: MapInfo | undefined = useSelector(allMaps)
|
||||
.find(m => m.id == props.mapId);
|
||||
|
||||
if (!mapInfo) {
|
||||
throw "Please, reflesh the page.";
|
||||
}
|
||||
|
||||
setModel({ ...mapInfo });
|
||||
}
|
||||
}, []);
|
||||
|
||||
const handleOnClose = (): void => {
|
||||
@ -74,21 +100,22 @@ function RenameDialog(props: DialogProps) {
|
||||
setModel(defaultModel);
|
||||
setErroInfo(undefined);
|
||||
|
||||
props.onClose(false);
|
||||
props.onClose();
|
||||
};
|
||||
|
||||
const handleOnSubmit = (event: React.FormEvent<HTMLFormElement>): void => {
|
||||
// Stop form submit ...
|
||||
event.preventDefault();
|
||||
|
||||
// Fire rest call ...
|
||||
const mapId = props.mapId;
|
||||
props.service.renameMap(mapId, model).
|
||||
then(() => {
|
||||
props.onClose(true);
|
||||
}).catch((errorInfo: ErrorInfo) => {
|
||||
setErroInfo(errorInfo)
|
||||
});
|
||||
// Fire rename ...
|
||||
const mapId: number = props.mapId;
|
||||
try {
|
||||
dispatch(rename({ id: mapId, name: model.name, description: model.description }))
|
||||
handleOnClose();
|
||||
|
||||
} catch (errorInfo) {
|
||||
setErroInfo(errorInfo)
|
||||
}
|
||||
};
|
||||
|
||||
const handleOnChange = (event: React.ChangeEvent<HTMLInputElement>): void => {
|
||||
@ -118,9 +145,9 @@ function RenameDialog(props: DialogProps) {
|
||||
{Boolean(errorInfo?.msg) ? <Alert severity="error" variant="filled" hidden={!Boolean(errorInfo?.msg)}>{errorInfo?.msg}</Alert> : null}
|
||||
<FormControl margin="normal" required fullWidth>
|
||||
<TextField name="name" label={intl.formatMessage({ id: "action.rename-name-placeholder", defaultMessage: "Name" })}
|
||||
value={model.name} onChange={handleOnChange}
|
||||
error={Boolean(errorInfo?.fields?.get('name'))} helperText={errorInfo?.fields?.get('name')}
|
||||
variant="filled" required={true}/>
|
||||
value={model.name} onChange={handleOnChange}
|
||||
error={Boolean(errorInfo?.fields?.get('name'))} helperText={errorInfo?.fields?.get('name')}
|
||||
variant="filled" required={true} />
|
||||
</FormControl>
|
||||
<FormControl margin="normal" required fullWidth>
|
||||
<TextField name="description" label={intl.formatMessage({ id: "action.rename-description-placeholder", defaultMessage: "Description" })} value={model.description} onChange={handleOnChange} variant="filled" />
|
||||
@ -129,7 +156,7 @@ function RenameDialog(props: DialogProps) {
|
||||
|
||||
<DialogActions>
|
||||
<Button color="primary" variant="outlined" type="submit">
|
||||
<FormattedMessage id="action.rename-button" defaultMessage="Rename"/>
|
||||
<FormattedMessage id="action.rename-button" defaultMessage="Rename" />
|
||||
</Button>
|
||||
|
||||
<Button color="secondary" variant="outlined" autoFocus onClick={handleOnClose}>
|
||||
@ -145,23 +172,23 @@ function RenameDialog(props: DialogProps) {
|
||||
export type DialogType = 'share' | 'delete' | 'info' | 'duplicate' | 'export' | 'rename' | 'publish';
|
||||
|
||||
type ActionDialogProps = {
|
||||
action: DialogType | undefined,
|
||||
action?: DialogType,
|
||||
mapId: number,
|
||||
service: Service,
|
||||
onClose: (reload: boolean) => void
|
||||
onClose: () => void
|
||||
}
|
||||
|
||||
const ActionDialog = (props: ActionDialogProps) => {
|
||||
|
||||
const handleOnClose = (reload: boolean): void => {
|
||||
props.onClose(reload);
|
||||
const handleOnClose = (): void => {
|
||||
props.onClose();
|
||||
}
|
||||
|
||||
const mapId = props.mapId;
|
||||
const action = props.action;
|
||||
|
||||
return (
|
||||
<span>
|
||||
<DeleteConfirmDialog open={props.action === 'delete'} service={props.service} onClose={handleOnClose} mapId={props.mapId} />
|
||||
<RenameDialog open={props.action === 'rename'} service={props.service} onClose={handleOnClose} mapId={props.mapId} />
|
||||
|
||||
<DeleteDialog open={action === 'delete'} onClose={handleOnClose} mapId={mapId} />
|
||||
<RenameDialog open={action === 'rename'} onClose={handleOnClose} mapId={mapId} />
|
||||
</span >
|
||||
);
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
import React, { useEffect } from 'react'
|
||||
import { MapInfo, Service } from '../../services/Service'
|
||||
import { PageContainer, MapsListArea, NavArea, HeaderArea, StyledTableCell } from './styled';
|
||||
|
||||
import { createStyles, makeStyles, Theme } from '@material-ui/core/styles';
|
||||
@ -24,6 +23,8 @@ import MoreHorizIcon from '@material-ui/icons/MoreHoriz';
|
||||
import { CSSProperties } from 'react';
|
||||
import MapActionMenu, { ActionType } from './MapActionMenu';
|
||||
import ActionDialog, { DialogType } from './ActionDialog';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { allMaps, MapInfo } from '../../reducers/mapsListSlice';
|
||||
|
||||
function descendingComparator<T>(a: T, b: T, orderBy: keyof T) {
|
||||
if (b[orderBy] < a[orderBy]) {
|
||||
@ -84,6 +85,7 @@ interface EnhancedTableProps {
|
||||
|
||||
function EnhancedTableHead(props: EnhancedTableProps) {
|
||||
const { classes, onSelectAllClick, order, orderBy, numSelected, rowCount, onRequestSort } = props;
|
||||
|
||||
const createSortHandler = (property: keyof MapInfo) => (event: React.MouseEvent<unknown>) => {
|
||||
onRequestSort(event, property);
|
||||
};
|
||||
@ -209,19 +211,16 @@ type ActionPanelState = {
|
||||
mapId: number
|
||||
}
|
||||
|
||||
function EnhancedTable(props: ServiceProps) {
|
||||
function EnhancedTable() {
|
||||
const classes = useStyles();
|
||||
|
||||
const [order, setOrder] = React.useState<Order>('asc');
|
||||
const [orderBy, setOrderBy] = React.useState<keyof MapInfo>('modified');
|
||||
const [selected, setSelected] = React.useState<number[]>([]);
|
||||
const [page, setPage] = React.useState(0);
|
||||
const [rowsPerPage, setRowsPerPage] = React.useState(5);
|
||||
const [rows, setRows] = React.useState<MapInfo[]>([]);
|
||||
|
||||
const mapsInfo: MapInfo[] = useSelector(allMaps);
|
||||
|
||||
const [activeRowAction, setActiveRowAction] = React.useState<ActionPanelState | undefined>(undefined);
|
||||
|
||||
type ActiveDialog = {
|
||||
actionType: DialogType;
|
||||
mapId: number
|
||||
@ -229,13 +228,6 @@ function EnhancedTable(props: ServiceProps) {
|
||||
};
|
||||
const [activeDialog, setActiveDialog] = React.useState<ActiveDialog | undefined>(undefined);
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
const mapsInfo = await props.service.fetchAllMaps();
|
||||
setRows(mapsInfo);
|
||||
})();
|
||||
}, []);
|
||||
|
||||
const handleRequestSort = (event: React.MouseEvent<unknown>, property: keyof MapInfo) => {
|
||||
const isAsc = orderBy === property && order === 'asc';
|
||||
setOrder(isAsc ? 'desc' : 'asc');
|
||||
@ -244,7 +236,7 @@ function EnhancedTable(props: ServiceProps) {
|
||||
|
||||
const handleSelectAllClick = (event: React.ChangeEvent<HTMLInputElement>): void => {
|
||||
if (event.target.checked) {
|
||||
const newSelecteds = rows.map((n) => n.id);
|
||||
const newSelecteds = mapsInfo.map((n) => n.id);
|
||||
setSelected(newSelecteds);
|
||||
return;
|
||||
}
|
||||
@ -306,7 +298,7 @@ function EnhancedTable(props: ServiceProps) {
|
||||
|
||||
const isSelected = (id: number) => selected.indexOf(id) !== -1;
|
||||
|
||||
const emptyRows = rowsPerPage - Math.min(rowsPerPage, rows.length - page * rowsPerPage);
|
||||
const emptyRows = rowsPerPage - Math.min(rowsPerPage, mapsInfo.length - page * rowsPerPage);
|
||||
|
||||
return (
|
||||
<div className={classes.root}>
|
||||
@ -327,10 +319,10 @@ function EnhancedTable(props: ServiceProps) {
|
||||
orderBy={orderBy}
|
||||
onSelectAllClick={handleSelectAllClick}
|
||||
onRequestSort={handleRequestSort}
|
||||
rowCount={rows.length}
|
||||
rowCount={mapsInfo.length}
|
||||
/>
|
||||
<TableBody>
|
||||
{stableSort(rows, getComparator(order, orderBy))
|
||||
{stableSort(mapsInfo, getComparator(order, orderBy))
|
||||
.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
|
||||
.map((row: MapInfo) => {
|
||||
const isItemSelected = isSelected(row.id);
|
||||
@ -390,7 +382,7 @@ function EnhancedTable(props: ServiceProps) {
|
||||
<TablePagination
|
||||
rowsPerPageOptions={[5, 10, 25]}
|
||||
component="div"
|
||||
count={rows.length}
|
||||
count={mapsInfo.length}
|
||||
rowsPerPage={rowsPerPage}
|
||||
page={page}
|
||||
onChangePage={handleChangePage}
|
||||
@ -399,16 +391,12 @@ function EnhancedTable(props: ServiceProps) {
|
||||
</Paper>
|
||||
|
||||
{/* Action Dialog */}
|
||||
<ActionDialog action={activeDialog?.actionType} onClose={(refresh: boolean) => setActiveDialog(undefined)} mapId={activeDialog ? activeDialog.mapId : -1} service={props.service}/>
|
||||
<ActionDialog action={activeDialog?.actionType} onClose={() => setActiveDialog(undefined)} mapId={activeDialog ? activeDialog.mapId : -1}/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
type ServiceProps = {
|
||||
service: Service
|
||||
}
|
||||
|
||||
const MapsPage = (props: ServiceProps) => {
|
||||
const MapsPage = () => {
|
||||
|
||||
useEffect(() => {
|
||||
document.title = 'Maps | WiseMapping';
|
||||
@ -423,7 +411,7 @@ const MapsPage = (props: ServiceProps) => {
|
||||
<h1> Nav </h1>
|
||||
</NavArea>
|
||||
<MapsListArea>
|
||||
<EnhancedTable service={props.service} />
|
||||
<EnhancedTable/>
|
||||
</MapsListArea>
|
||||
</PageContainer>
|
||||
);
|
||||
|
@ -12,7 +12,7 @@ import SubmitButton from '../submit-button'
|
||||
import { StyledReCAPTCHA } from './styled';
|
||||
import { PageContent } from '../../theme/global-style';
|
||||
|
||||
const RegistrationForm = (props: ServiceProps) => {
|
||||
const RegistrationForm = () => {
|
||||
const [email, setEmail] = useState('');
|
||||
const [lastname, setLastname] = useState('')
|
||||
const [firstname, setFirstname] = useState('');
|
||||
@ -40,15 +40,15 @@ const RegistrationForm = (props: ServiceProps) => {
|
||||
};
|
||||
|
||||
// Call Service ...
|
||||
const service = props.service;
|
||||
service.registerNewUser(user)
|
||||
.then(() => {
|
||||
history.push("/c/registration-success")
|
||||
}).catch((error: ErrorInfo) => {
|
||||
const errorMsg = error.msg ? error.msg : undefined;
|
||||
setErrorMsg(errorMsg);
|
||||
setDisableButton(false);
|
||||
});
|
||||
// const service = props.service;
|
||||
// service.registerNewUser(user)
|
||||
// .then(() => {
|
||||
// history.push("/c/registration-success")
|
||||
// }).catch((error: ErrorInfo) => {
|
||||
// const errorMsg = error.msg ? error.msg : undefined;
|
||||
// setErrorMsg(errorMsg);
|
||||
// setDisableButton(false);
|
||||
// });
|
||||
}
|
||||
|
||||
|
||||
@ -82,10 +82,7 @@ const RegistrationForm = (props: ServiceProps) => {
|
||||
);
|
||||
}
|
||||
|
||||
type ServiceProps = {
|
||||
service: Service
|
||||
}
|
||||
const RegistationPage = (props: ServiceProps) => {
|
||||
const RegistationPage = () => {
|
||||
|
||||
useEffect(() => {
|
||||
document.title = 'Registration | WiseMapping';
|
||||
@ -94,7 +91,7 @@ const RegistationPage = (props: ServiceProps) => {
|
||||
return (
|
||||
<div>
|
||||
<Header type='only-signin' />
|
||||
<RegistrationForm service={props.service} />
|
||||
<RegistrationForm/>
|
||||
<Footer />
|
||||
</div>
|
||||
);
|
||||
|
@ -2,43 +2,13 @@ import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import App from './app';
|
||||
import { BrowserRouter as Router } from 'react-router-dom';
|
||||
import axios from 'axios'
|
||||
import axios from 'axios';
|
||||
|
||||
type RutimeConfig = {
|
||||
apiBaseUrl: string;
|
||||
}
|
||||
|
||||
async function loadRuntimeConfig() {
|
||||
let result: RutimeConfig | undefined;
|
||||
|
||||
await axios.get("runtime-config.json"
|
||||
).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;
|
||||
}
|
||||
|
||||
async function bootstrapApplication() {
|
||||
|
||||
const config: RutimeConfig = await loadRuntimeConfig();
|
||||
ReactDOM.render(
|
||||
<Router>
|
||||
<App baseRestUrl={config.apiBaseUrl} />
|
||||
<App/>
|
||||
</Router>,
|
||||
document.getElementById('root') as HTMLElement
|
||||
)
|
||||
|
113
packages/webapp/src/reducers/mapsListSlice.ts
Normal file
113
packages/webapp/src/reducers/mapsListSlice.ts
Normal file
@ -0,0 +1,113 @@
|
||||
import { createSlice, PayloadAction } from '@reduxjs/toolkit'
|
||||
import axios from 'axios';
|
||||
import { RestService, Service } from '../services/Service';
|
||||
|
||||
function createMapInfo(
|
||||
id: number,
|
||||
starred: boolean,
|
||||
name: string,
|
||||
labels: [string],
|
||||
creator: string,
|
||||
modified: number,
|
||||
description: string
|
||||
): MapInfo {
|
||||
return { id, name, labels, creator, modified, starred, description };
|
||||
}
|
||||
|
||||
const maps = [
|
||||
createMapInfo(1, true, "El Mapa", [""], "Paulo", 67, ""),
|
||||
createMapInfo(2, false, "El Mapa2", [""], "Paulo2", 67, ""),
|
||||
createMapInfo(3, false, "El Mapa3", [""], "Paulo3", 67, "")
|
||||
];
|
||||
|
||||
export type MapInfo = {
|
||||
id: number;
|
||||
starred: boolean;
|
||||
name: string;
|
||||
labels: [string];
|
||||
creator: string;
|
||||
modified: number;
|
||||
description: string
|
||||
}
|
||||
|
||||
interface MapsListState {
|
||||
maps: MapInfo[]
|
||||
}
|
||||
|
||||
type RutimeConfig = {
|
||||
apiBaseUrl: string;
|
||||
}
|
||||
|
||||
async function loadRuntimeConfig() {
|
||||
let result: RutimeConfig | undefined;
|
||||
|
||||
await axios.get("runtime-config.json"
|
||||
).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;
|
||||
}
|
||||
|
||||
const initialState: MapsListState = { maps: maps };
|
||||
|
||||
const service: Service = new RestService("", () => { console.log("401 error") });
|
||||
|
||||
type RemovePayload = {
|
||||
id: number;
|
||||
}
|
||||
|
||||
type RenamePayload = {
|
||||
id: number;
|
||||
name: string;
|
||||
description: string | undefined;
|
||||
|
||||
}
|
||||
|
||||
export const mapsListSlice = createSlice({
|
||||
name: 'maps',
|
||||
initialState: initialState,
|
||||
reducers: {
|
||||
remove(state, action: PayloadAction<RemovePayload>) {
|
||||
const maps: MapInfo[] = state.maps as MapInfo[];
|
||||
const payload = action.payload;
|
||||
state.maps = maps.filter(map => map.id != payload.id);
|
||||
},
|
||||
rename(state, action: PayloadAction<RenamePayload>) {
|
||||
let maps: MapInfo[] = state.maps as MapInfo[];
|
||||
const payload = action.payload;
|
||||
|
||||
const mapInfo = maps.find(m => m.id == payload.id);
|
||||
if (mapInfo) {
|
||||
mapInfo.name = payload.name;
|
||||
mapInfo.description = payload.description ? payload.description: "";
|
||||
|
||||
// Remove and add the new map.
|
||||
maps = maps.filter(map => map.id != payload.id);
|
||||
maps.push(mapInfo);
|
||||
|
||||
state.maps = maps;
|
||||
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
export const allMaps = (state: any): MapInfo[] => state.mapsList.maps;
|
||||
|
||||
export const { remove, rename } = mapsListSlice.actions
|
||||
export default mapsListSlice.reducer
|
@ -1,3 +1,4 @@
|
||||
import { Description } from '@material-ui/icons'
|
||||
import axios from 'axios'
|
||||
|
||||
export type NewUser = {
|
||||
@ -15,11 +16,12 @@ export type MapInfo = {
|
||||
labels: [string];
|
||||
creator: string;
|
||||
modified: number;
|
||||
description: string;
|
||||
}
|
||||
|
||||
export type BasicMapInfo = {
|
||||
name: string;
|
||||
description: string;
|
||||
description?: string;
|
||||
}
|
||||
|
||||
export type FieldError = {
|
||||
@ -86,6 +88,7 @@ class RestService implements Service {
|
||||
}
|
||||
|
||||
async fetchAllMaps(): Promise<MapInfo[]> {
|
||||
|
||||
function createMapInfo(
|
||||
id: number,
|
||||
starred: boolean,
|
||||
@ -93,14 +96,15 @@ class RestService implements Service {
|
||||
labels: [string],
|
||||
creator: string,
|
||||
modified: number,
|
||||
description: string
|
||||
): MapInfo {
|
||||
return { id, name, labels, creator, modified, starred };
|
||||
return { id, name, labels, creator, modified, starred, description};
|
||||
}
|
||||
|
||||
const maps = [
|
||||
createMapInfo(1, true, "El Mapa", [""], "Paulo", 67,),
|
||||
createMapInfo(2, false, "El Mapa2", [""], "Paulo2", 67),
|
||||
createMapInfo(3, false, "El Mapa3", [""], "Paulo3", 67)
|
||||
createMapInfo(1, true, "El Mapa", [""], "Paulo", 67,""),
|
||||
createMapInfo(2, false, "El Mapa2", [""], "Paulo2", 67,""),
|
||||
createMapInfo(3, false, "El Mapa3", [""], "Paulo3", 67,"")
|
||||
];
|
||||
|
||||
return Promise.resolve(maps);
|
||||
|
12
packages/webapp/src/store.ts
Normal file
12
packages/webapp/src/store.ts
Normal file
@ -0,0 +1,12 @@
|
||||
|
||||
import { configureStore } from '@reduxjs/toolkit';
|
||||
import mapsListReducer from './reducers/mapsListSlice';
|
||||
|
||||
// Create Service object...
|
||||
const store = configureStore({
|
||||
reducer: {
|
||||
mapsList: mapsListReducer
|
||||
}
|
||||
});
|
||||
|
||||
export default store;
|
Loading…
Reference in New Issue
Block a user