mirror of
https://bitbucket.org/wisemapping/wisemapping-frontend.git
synced 2024-11-22 14:47:56 +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": {
|
"common.wait": {
|
||||||
"defaultMessage": "Please wait ..."
|
"defaultMessage": "Please wait ..."
|
||||||
},
|
},
|
||||||
@ -57,7 +108,7 @@
|
|||||||
"defaultMessage": "Email"
|
"defaultMessage": "Email"
|
||||||
},
|
},
|
||||||
"login.error": {
|
"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": {
|
"login.forgotpwd": {
|
||||||
"defaultMessage": "Forgot Password ?"
|
"defaultMessage": "Forgot Password ?"
|
||||||
@ -82,7 +133,7 @@
|
|||||||
"defaultMessage": "Welcome"
|
"defaultMessage": "Welcome"
|
||||||
},
|
},
|
||||||
"login.userinactive": {
|
"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": {
|
"registration.desc": {
|
||||||
"defaultMessage": "Signing up is free and just take a moment"
|
"defaultMessage": "Signing up is free and just take a moment"
|
||||||
|
@ -48,12 +48,14 @@
|
|||||||
"@material-ui/core": "^4.11.2",
|
"@material-ui/core": "^4.11.2",
|
||||||
"@material-ui/icons": "^4.11.2",
|
"@material-ui/icons": "^4.11.2",
|
||||||
"@material-ui/lab": "^4.0.0-alpha.57",
|
"@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",
|
"@types/react-google-recaptcha": "^2.1.0",
|
||||||
"axios": "^0.21.0",
|
|
||||||
"react": "^17.0.1",
|
"react": "^17.0.1",
|
||||||
"react-dom": "^17.0.1",
|
"react-dom": "^17.0.1",
|
||||||
"react-google-recaptcha": "^2.1.0",
|
"react-google-recaptcha": "^2.1.0",
|
||||||
"react-intl": "^5.10.6",
|
"react-intl": "^5.10.6",
|
||||||
|
"react-redux": "^7.2.2",
|
||||||
"react-router-dom": "^5.2.0",
|
"react-router-dom": "^5.2.0",
|
||||||
"styled-components": "^5.2.1"
|
"styled-components": "^5.2.1"
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { Service, RestService } from './services/Service';
|
|
||||||
import { IntlProvider } from 'react-intl'
|
import { IntlProvider } from 'react-intl'
|
||||||
|
|
||||||
import { GlobalStyle } from './theme/global-style';
|
import { GlobalStyle } from './theme/global-style';
|
||||||
@ -8,6 +7,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 {
|
import {
|
||||||
Route,
|
Route,
|
||||||
@ -17,6 +17,7 @@ import {
|
|||||||
} from 'react-router-dom';
|
} from 'react-router-dom';
|
||||||
|
|
||||||
import { ForgotPasswordPage } from './components/forgot-password-page';
|
import { ForgotPasswordPage } from './components/forgot-password-page';
|
||||||
|
import { Provider } from 'react-redux';
|
||||||
|
|
||||||
function loadLocaleData(language: string) {
|
function loadLocaleData(language: string) {
|
||||||
switch (language) {
|
switch (language) {
|
||||||
@ -31,7 +32,7 @@ type AppProps = {
|
|||||||
baseRestUrl: string;
|
baseRestUrl: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const App = (props: AppProps) => {
|
const App = () => {
|
||||||
const [messages, setMessages] = useState(undefined);
|
const [messages, setMessages] = useState(undefined);
|
||||||
|
|
||||||
// Boostrap i18n ...
|
// Boostrap i18n ...
|
||||||
@ -50,11 +51,8 @@ const App = (props: AppProps) => {
|
|||||||
fetchData();
|
fetchData();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
// Create Service object...
|
|
||||||
|
|
||||||
const service: Service = new RestService(props.baseRestUrl, () => { console.log("401 error") });
|
|
||||||
|
|
||||||
return messages ? (
|
return messages ? (
|
||||||
|
<Provider store={store}>
|
||||||
<IntlProvider locale={locale} defaultLocale='en' messages={messages}>
|
<IntlProvider locale={locale} defaultLocale='en' messages={messages}>
|
||||||
<GlobalStyle />
|
<GlobalStyle />
|
||||||
<Router>
|
<Router>
|
||||||
@ -64,19 +62,21 @@ const App = (props: AppProps) => {
|
|||||||
</Route>
|
</Route>
|
||||||
<Route path="/c/login" component={LoginPage} />
|
<Route path="/c/login" component={LoginPage} />
|
||||||
<Route path="/c/registration">
|
<Route path="/c/registration">
|
||||||
<RegistationPage service={service} />
|
<RegistationPage />
|
||||||
</Route>
|
</Route>
|
||||||
<Route path="/c/registration-success" component={RegistrationSuccessPage} />
|
<Route path="/c/registration-success" component={RegistrationSuccessPage} />
|
||||||
<Route path="/c/forgot-password">
|
<Route path="/c/forgot-password">
|
||||||
<ForgotPasswordPage service={service} />
|
<ForgotPasswordPage />
|
||||||
</Route>
|
</Route>
|
||||||
<Route path="/c/forgot-password-success" component={ForgotPasswordSuccessPage} />
|
<Route path="/c/forgot-password-success" component={ForgotPasswordSuccessPage} />
|
||||||
<Route path="/c/maps/">
|
<Route path="/c/maps/">
|
||||||
<MapsPage service={service} />
|
<MapsPage />
|
||||||
</Route>
|
</Route>
|
||||||
</Switch>
|
</Switch>
|
||||||
</Router>
|
</Router>
|
||||||
</IntlProvider>
|
</IntlProvider>
|
||||||
|
</Provider>
|
||||||
|
|
||||||
) : <div>Loading ... </div>
|
) : <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": [
|
"common.wait": [
|
||||||
{
|
{
|
||||||
"type": 0,
|
"type": 0,
|
||||||
@ -116,7 +218,7 @@
|
|||||||
"login.error": [
|
"login.error": [
|
||||||
{
|
{
|
||||||
"type": 0,
|
"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": [
|
"login.forgotpwd": [
|
||||||
@ -164,7 +266,7 @@
|
|||||||
"login.userinactive": [
|
"login.userinactive": [
|
||||||
{
|
{
|
||||||
"type": 0,
|
"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": [
|
"registration.desc": [
|
||||||
|
@ -13,7 +13,7 @@ type ForgotPasswordProps = {
|
|||||||
email: string;
|
email: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ForgotPassword = (props: ServiceProps) => {
|
const ForgotPassword = () => {
|
||||||
const [email, setEmail] = useState('');
|
const [email, setEmail] = useState('');
|
||||||
const [errorMsg, setErrorMsg] = useState('');
|
const [errorMsg, setErrorMsg] = useState('');
|
||||||
const [disableButton, setDisableButton] = useState(false);
|
const [disableButton, setDisableButton] = useState(false);
|
||||||
@ -26,14 +26,14 @@ const ForgotPassword = (props: ServiceProps) => {
|
|||||||
setDisableButton(true);
|
setDisableButton(true);
|
||||||
|
|
||||||
// Call Service ...
|
// Call Service ...
|
||||||
const service = props.service;
|
// const service = props.service;
|
||||||
service.resetPassword(email)
|
// service.resetPassword(email)
|
||||||
.then(() => {
|
// .then(() => {
|
||||||
history.push("/c/forgot-password-success");
|
// history.push("/c/forgot-password-success");
|
||||||
}).catch((error: ErrorInfo) => {
|
// }).catch((error: ErrorInfo) => {
|
||||||
setErrorMsg(error.msg ? error.msg : '');
|
// setErrorMsg(error.msg ? error.msg : '');
|
||||||
setDisableButton(false);
|
// setDisableButton(false);
|
||||||
});
|
// });
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -55,7 +55,7 @@ const ForgotPassword = (props: ServiceProps) => {
|
|||||||
type ServiceProps = {
|
type ServiceProps = {
|
||||||
service: Service
|
service: Service
|
||||||
}
|
}
|
||||||
const ForgotPasswordPage = (props: ServiceProps) => {
|
const ForgotPasswordPage = () => {
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
document.title = 'Reset Password | WiseMapping';
|
document.title = 'Reset Password | WiseMapping';
|
||||||
@ -64,7 +64,7 @@ const ForgotPasswordPage = (props: ServiceProps) => {
|
|||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Header type='only-signin' />
|
<Header type='only-signin' />
|
||||||
<ForgotPassword service={props.service} />
|
<ForgotPassword />
|
||||||
<Footer />
|
<Footer />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -6,26 +6,41 @@ import DialogContent from '@material-ui/core/DialogContent';
|
|||||||
import DialogContentText from '@material-ui/core/DialogContentText';
|
import DialogContentText from '@material-ui/core/DialogContentText';
|
||||||
import DialogTitle from '@material-ui/core/DialogTitle';
|
import DialogTitle from '@material-ui/core/DialogTitle';
|
||||||
import { FormattedMessage, useIntl } from 'react-intl';
|
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 { FormControl, TextField } from '@material-ui/core';
|
||||||
import { Alert, AlertTitle } from '@material-ui/lab';
|
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 = {
|
type DialogProps = {
|
||||||
open: boolean,
|
open: boolean,
|
||||||
mapId: number,
|
mapId: number,
|
||||||
onClose: (reload: boolean) => void,
|
onClose: () => void
|
||||||
service: Service
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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 => {
|
const handleOnClose = (action: 'accept' | undefined): void => {
|
||||||
let result = false;
|
if (action == 'accept' && mapInfo) {
|
||||||
if (action == 'accept') {
|
dispatch(remove({ id: mapId }))
|
||||||
props.service.deleteMap(props.mapId);
|
|
||||||
result = true;
|
|
||||||
}
|
}
|
||||||
props.onClose(result);
|
props.onClose();
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -35,12 +50,10 @@ function DeleteConfirmDialog(props: DialogProps) {
|
|||||||
onClose={() => handleOnClose(undefined)} >
|
onClose={() => handleOnClose(undefined)} >
|
||||||
<DialogTitle><FormattedMessage id="action.delete-title" defaultMessage="Delete" /></DialogTitle>
|
<DialogTitle><FormattedMessage id="action.delete-title" defaultMessage="Delete" /></DialogTitle>
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
<DialogContentText>
|
|
||||||
<Alert severity="warning">
|
<Alert severity="warning">
|
||||||
<AlertTitle>Map to be deleted</AlertTitle>
|
<AlertTitle>Delete '{mapInfo?.name}'</AlertTitle>
|
||||||
<FormattedMessage id="action.delete-description" defaultMessage="Deleted mindmap can not be recovered. Do you want to continue ?." />
|
<FormattedMessage id="action.delete-description" defaultMessage="Deleted mindmap can not be recovered. Do you want to continue ?." />
|
||||||
</Alert>
|
</Alert>
|
||||||
</DialogContentText>
|
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
<Button onClick={() => handleOnClose('accept')} variant="outlined" color="primary">
|
<Button onClick={() => handleOnClose('accept')} variant="outlined" color="primary">
|
||||||
@ -54,19 +67,32 @@ function DeleteConfirmDialog(props: DialogProps) {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
export type RenameModel = {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
description?: string;
|
||||||
|
}
|
||||||
|
|
||||||
function RenameDialog(props: DialogProps) {
|
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();
|
const intl = useIntl();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
props.service.loadMapInfo(props.mapId)
|
const mapId: number = props.mapId;
|
||||||
.then((info: BasicMapInfo) => {
|
if (mapId != -1) {
|
||||||
setModel(info);
|
const mapInfo: MapInfo | undefined = useSelector(allMaps)
|
||||||
})
|
.find(m => m.id == props.mapId);
|
||||||
|
|
||||||
|
if (!mapInfo) {
|
||||||
|
throw "Please, reflesh the page.";
|
||||||
|
}
|
||||||
|
|
||||||
|
setModel({ ...mapInfo });
|
||||||
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const handleOnClose = (): void => {
|
const handleOnClose = (): void => {
|
||||||
@ -74,21 +100,22 @@ function RenameDialog(props: DialogProps) {
|
|||||||
setModel(defaultModel);
|
setModel(defaultModel);
|
||||||
setErroInfo(undefined);
|
setErroInfo(undefined);
|
||||||
|
|
||||||
props.onClose(false);
|
props.onClose();
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleOnSubmit = (event: React.FormEvent<HTMLFormElement>): void => {
|
const handleOnSubmit = (event: React.FormEvent<HTMLFormElement>): void => {
|
||||||
// Stop form submit ...
|
// Stop form submit ...
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
// Fire rest call ...
|
// Fire rename ...
|
||||||
const mapId = props.mapId;
|
const mapId: number = props.mapId;
|
||||||
props.service.renameMap(mapId, model).
|
try {
|
||||||
then(() => {
|
dispatch(rename({ id: mapId, name: model.name, description: model.description }))
|
||||||
props.onClose(true);
|
handleOnClose();
|
||||||
}).catch((errorInfo: ErrorInfo) => {
|
|
||||||
|
} catch (errorInfo) {
|
||||||
setErroInfo(errorInfo)
|
setErroInfo(errorInfo)
|
||||||
});
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleOnChange = (event: React.ChangeEvent<HTMLInputElement>): void => {
|
const handleOnChange = (event: React.ChangeEvent<HTMLInputElement>): void => {
|
||||||
@ -145,23 +172,23 @@ function RenameDialog(props: DialogProps) {
|
|||||||
export type DialogType = 'share' | 'delete' | 'info' | 'duplicate' | 'export' | 'rename' | 'publish';
|
export type DialogType = 'share' | 'delete' | 'info' | 'duplicate' | 'export' | 'rename' | 'publish';
|
||||||
|
|
||||||
type ActionDialogProps = {
|
type ActionDialogProps = {
|
||||||
action: DialogType | undefined,
|
action?: DialogType,
|
||||||
mapId: number,
|
mapId: number,
|
||||||
service: Service,
|
onClose: () => void
|
||||||
onClose: (reload: boolean) => void
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const ActionDialog = (props: ActionDialogProps) => {
|
const ActionDialog = (props: ActionDialogProps) => {
|
||||||
|
const handleOnClose = (): void => {
|
||||||
const handleOnClose = (reload: boolean): void => {
|
props.onClose();
|
||||||
props.onClose(reload);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const mapId = props.mapId;
|
||||||
|
const action = props.action;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<span>
|
<span>
|
||||||
<DeleteConfirmDialog open={props.action === 'delete'} service={props.service} onClose={handleOnClose} mapId={props.mapId} />
|
<DeleteDialog open={action === 'delete'} onClose={handleOnClose} mapId={mapId} />
|
||||||
<RenameDialog open={props.action === 'rename'} service={props.service} onClose={handleOnClose} mapId={props.mapId} />
|
<RenameDialog open={action === 'rename'} onClose={handleOnClose} mapId={mapId} />
|
||||||
|
|
||||||
</span >
|
</span >
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import React, { useEffect } from 'react'
|
import React, { useEffect } from 'react'
|
||||||
import { MapInfo, Service } from '../../services/Service'
|
|
||||||
import { PageContainer, MapsListArea, NavArea, HeaderArea, StyledTableCell } from './styled';
|
import { PageContainer, MapsListArea, NavArea, HeaderArea, StyledTableCell } from './styled';
|
||||||
|
|
||||||
import { createStyles, makeStyles, Theme } from '@material-ui/core/styles';
|
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 { CSSProperties } from 'react';
|
||||||
import MapActionMenu, { ActionType } from './MapActionMenu';
|
import MapActionMenu, { ActionType } from './MapActionMenu';
|
||||||
import ActionDialog, { DialogType } from './ActionDialog';
|
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) {
|
function descendingComparator<T>(a: T, b: T, orderBy: keyof T) {
|
||||||
if (b[orderBy] < a[orderBy]) {
|
if (b[orderBy] < a[orderBy]) {
|
||||||
@ -84,6 +85,7 @@ interface EnhancedTableProps {
|
|||||||
|
|
||||||
function EnhancedTableHead(props: EnhancedTableProps) {
|
function EnhancedTableHead(props: EnhancedTableProps) {
|
||||||
const { classes, onSelectAllClick, order, orderBy, numSelected, rowCount, onRequestSort } = props;
|
const { classes, onSelectAllClick, order, orderBy, numSelected, rowCount, onRequestSort } = props;
|
||||||
|
|
||||||
const createSortHandler = (property: keyof MapInfo) => (event: React.MouseEvent<unknown>) => {
|
const createSortHandler = (property: keyof MapInfo) => (event: React.MouseEvent<unknown>) => {
|
||||||
onRequestSort(event, property);
|
onRequestSort(event, property);
|
||||||
};
|
};
|
||||||
@ -209,19 +211,16 @@ type ActionPanelState = {
|
|||||||
mapId: number
|
mapId: number
|
||||||
}
|
}
|
||||||
|
|
||||||
function EnhancedTable(props: ServiceProps) {
|
function EnhancedTable() {
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
|
|
||||||
const [order, setOrder] = React.useState<Order>('asc');
|
const [order, setOrder] = React.useState<Order>('asc');
|
||||||
const [orderBy, setOrderBy] = React.useState<keyof MapInfo>('modified');
|
const [orderBy, setOrderBy] = React.useState<keyof MapInfo>('modified');
|
||||||
const [selected, setSelected] = React.useState<number[]>([]);
|
const [selected, setSelected] = React.useState<number[]>([]);
|
||||||
const [page, setPage] = React.useState(0);
|
const [page, setPage] = React.useState(0);
|
||||||
const [rowsPerPage, setRowsPerPage] = React.useState(5);
|
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);
|
const [activeRowAction, setActiveRowAction] = React.useState<ActionPanelState | undefined>(undefined);
|
||||||
|
|
||||||
type ActiveDialog = {
|
type ActiveDialog = {
|
||||||
actionType: DialogType;
|
actionType: DialogType;
|
||||||
mapId: number
|
mapId: number
|
||||||
@ -229,13 +228,6 @@ function EnhancedTable(props: ServiceProps) {
|
|||||||
};
|
};
|
||||||
const [activeDialog, setActiveDialog] = React.useState<ActiveDialog | undefined>(undefined);
|
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 handleRequestSort = (event: React.MouseEvent<unknown>, property: keyof MapInfo) => {
|
||||||
const isAsc = orderBy === property && order === 'asc';
|
const isAsc = orderBy === property && order === 'asc';
|
||||||
setOrder(isAsc ? 'desc' : 'asc');
|
setOrder(isAsc ? 'desc' : 'asc');
|
||||||
@ -244,7 +236,7 @@ function EnhancedTable(props: ServiceProps) {
|
|||||||
|
|
||||||
const handleSelectAllClick = (event: React.ChangeEvent<HTMLInputElement>): void => {
|
const handleSelectAllClick = (event: React.ChangeEvent<HTMLInputElement>): void => {
|
||||||
if (event.target.checked) {
|
if (event.target.checked) {
|
||||||
const newSelecteds = rows.map((n) => n.id);
|
const newSelecteds = mapsInfo.map((n) => n.id);
|
||||||
setSelected(newSelecteds);
|
setSelected(newSelecteds);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -306,7 +298,7 @@ function EnhancedTable(props: ServiceProps) {
|
|||||||
|
|
||||||
const isSelected = (id: number) => selected.indexOf(id) !== -1;
|
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 (
|
return (
|
||||||
<div className={classes.root}>
|
<div className={classes.root}>
|
||||||
@ -327,10 +319,10 @@ function EnhancedTable(props: ServiceProps) {
|
|||||||
orderBy={orderBy}
|
orderBy={orderBy}
|
||||||
onSelectAllClick={handleSelectAllClick}
|
onSelectAllClick={handleSelectAllClick}
|
||||||
onRequestSort={handleRequestSort}
|
onRequestSort={handleRequestSort}
|
||||||
rowCount={rows.length}
|
rowCount={mapsInfo.length}
|
||||||
/>
|
/>
|
||||||
<TableBody>
|
<TableBody>
|
||||||
{stableSort(rows, 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) => {
|
||||||
const isItemSelected = isSelected(row.id);
|
const isItemSelected = isSelected(row.id);
|
||||||
@ -390,7 +382,7 @@ function EnhancedTable(props: ServiceProps) {
|
|||||||
<TablePagination
|
<TablePagination
|
||||||
rowsPerPageOptions={[5, 10, 25]}
|
rowsPerPageOptions={[5, 10, 25]}
|
||||||
component="div"
|
component="div"
|
||||||
count={rows.length}
|
count={mapsInfo.length}
|
||||||
rowsPerPage={rowsPerPage}
|
rowsPerPage={rowsPerPage}
|
||||||
page={page}
|
page={page}
|
||||||
onChangePage={handleChangePage}
|
onChangePage={handleChangePage}
|
||||||
@ -399,16 +391,12 @@ function EnhancedTable(props: ServiceProps) {
|
|||||||
</Paper>
|
</Paper>
|
||||||
|
|
||||||
{/* Action Dialog */}
|
{/* 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>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
type ServiceProps = {
|
const MapsPage = () => {
|
||||||
service: Service
|
|
||||||
}
|
|
||||||
|
|
||||||
const MapsPage = (props: ServiceProps) => {
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
document.title = 'Maps | WiseMapping';
|
document.title = 'Maps | WiseMapping';
|
||||||
@ -423,7 +411,7 @@ const MapsPage = (props: ServiceProps) => {
|
|||||||
<h1> Nav </h1>
|
<h1> Nav </h1>
|
||||||
</NavArea>
|
</NavArea>
|
||||||
<MapsListArea>
|
<MapsListArea>
|
||||||
<EnhancedTable service={props.service} />
|
<EnhancedTable/>
|
||||||
</MapsListArea>
|
</MapsListArea>
|
||||||
</PageContainer>
|
</PageContainer>
|
||||||
);
|
);
|
||||||
|
@ -12,7 +12,7 @@ import SubmitButton from '../submit-button'
|
|||||||
import { StyledReCAPTCHA } from './styled';
|
import { StyledReCAPTCHA } from './styled';
|
||||||
import { PageContent } from '../../theme/global-style';
|
import { PageContent } from '../../theme/global-style';
|
||||||
|
|
||||||
const RegistrationForm = (props: ServiceProps) => {
|
const RegistrationForm = () => {
|
||||||
const [email, setEmail] = useState('');
|
const [email, setEmail] = useState('');
|
||||||
const [lastname, setLastname] = useState('')
|
const [lastname, setLastname] = useState('')
|
||||||
const [firstname, setFirstname] = useState('');
|
const [firstname, setFirstname] = useState('');
|
||||||
@ -40,15 +40,15 @@ const RegistrationForm = (props: ServiceProps) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Call Service ...
|
// Call Service ...
|
||||||
const service = props.service;
|
// const service = props.service;
|
||||||
service.registerNewUser(user)
|
// service.registerNewUser(user)
|
||||||
.then(() => {
|
// .then(() => {
|
||||||
history.push("/c/registration-success")
|
// history.push("/c/registration-success")
|
||||||
}).catch((error: ErrorInfo) => {
|
// }).catch((error: ErrorInfo) => {
|
||||||
const errorMsg = error.msg ? error.msg : undefined;
|
// const errorMsg = error.msg ? error.msg : undefined;
|
||||||
setErrorMsg(errorMsg);
|
// setErrorMsg(errorMsg);
|
||||||
setDisableButton(false);
|
// setDisableButton(false);
|
||||||
});
|
// });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -82,10 +82,7 @@ const RegistrationForm = (props: ServiceProps) => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
type ServiceProps = {
|
const RegistationPage = () => {
|
||||||
service: Service
|
|
||||||
}
|
|
||||||
const RegistationPage = (props: ServiceProps) => {
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
document.title = 'Registration | WiseMapping';
|
document.title = 'Registration | WiseMapping';
|
||||||
@ -94,7 +91,7 @@ const RegistationPage = (props: ServiceProps) => {
|
|||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Header type='only-signin' />
|
<Header type='only-signin' />
|
||||||
<RegistrationForm service={props.service} />
|
<RegistrationForm/>
|
||||||
<Footer />
|
<Footer />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -2,43 +2,13 @@ import React from 'react';
|
|||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
import App from './app';
|
import App from './app';
|
||||||
import { BrowserRouter as Router } from 'react-router-dom';
|
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() {
|
async function bootstrapApplication() {
|
||||||
|
|
||||||
const config: RutimeConfig = await loadRuntimeConfig();
|
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<Router>
|
<Router>
|
||||||
<App baseRestUrl={config.apiBaseUrl} />
|
<App/>
|
||||||
</Router>,
|
</Router>,
|
||||||
document.getElementById('root') as HTMLElement
|
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'
|
import axios from 'axios'
|
||||||
|
|
||||||
export type NewUser = {
|
export type NewUser = {
|
||||||
@ -15,11 +16,12 @@ export type MapInfo = {
|
|||||||
labels: [string];
|
labels: [string];
|
||||||
creator: string;
|
creator: string;
|
||||||
modified: number;
|
modified: number;
|
||||||
|
description: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type BasicMapInfo = {
|
export type BasicMapInfo = {
|
||||||
name: string;
|
name: string;
|
||||||
description: string;
|
description?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type FieldError = {
|
export type FieldError = {
|
||||||
@ -86,6 +88,7 @@ class RestService implements Service {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fetchAllMaps(): Promise<MapInfo[]> {
|
async fetchAllMaps(): Promise<MapInfo[]> {
|
||||||
|
|
||||||
function createMapInfo(
|
function createMapInfo(
|
||||||
id: number,
|
id: number,
|
||||||
starred: boolean,
|
starred: boolean,
|
||||||
@ -93,14 +96,15 @@ class RestService implements Service {
|
|||||||
labels: [string],
|
labels: [string],
|
||||||
creator: string,
|
creator: string,
|
||||||
modified: number,
|
modified: number,
|
||||||
|
description: string
|
||||||
): MapInfo {
|
): MapInfo {
|
||||||
return { id, name, labels, creator, modified, starred };
|
return { id, name, labels, creator, modified, starred, description};
|
||||||
}
|
}
|
||||||
|
|
||||||
const maps = [
|
const maps = [
|
||||||
createMapInfo(1, true, "El Mapa", [""], "Paulo", 67,),
|
createMapInfo(1, true, "El Mapa", [""], "Paulo", 67,""),
|
||||||
createMapInfo(2, false, "El Mapa2", [""], "Paulo2", 67),
|
createMapInfo(2, false, "El Mapa2", [""], "Paulo2", 67,""),
|
||||||
createMapInfo(3, false, "El Mapa3", [""], "Paulo3", 67)
|
createMapInfo(3, false, "El Mapa3", [""], "Paulo3", 67,"")
|
||||||
];
|
];
|
||||||
|
|
||||||
return Promise.resolve(maps);
|
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