mirror of
https://bitbucket.org/wisemapping/wisemapping-frontend.git
synced 2024-11-22 06:37:56 +01:00
Merged in feat/prettier (pull request #3)
adding back semicolons * adding back semicolons
This commit is contained in:
parent
b63d7ee665
commit
3d538923a9
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"trailingComma": "es5",
|
"trailingComma": "es5",
|
||||||
"tabWidth": 4,
|
"tabWidth": 4,
|
||||||
"semi": false,
|
"semi": true,
|
||||||
"singleQuote": true,
|
"singleQuote": true,
|
||||||
"printWidth": 100
|
"printWidth": 100
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import React from 'react'
|
import React from 'react';
|
||||||
import { StyledCanvas } from './styled'
|
import { StyledCanvas } from './styled';
|
||||||
|
|
||||||
const Canvas = (): React.ReactElement => <StyledCanvas>canvas</StyledCanvas>
|
const Canvas = (): React.ReactElement => <StyledCanvas>canvas</StyledCanvas>;
|
||||||
|
|
||||||
export default Canvas
|
export default Canvas;
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import styled from 'styled-components'
|
import styled from 'styled-components';
|
||||||
|
|
||||||
export const StyledCanvas = styled.div`
|
export const StyledCanvas = styled.div`
|
||||||
height: 100%
|
height: 100%
|
||||||
width: 100%;
|
width: 100%;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
|
||||||
`
|
`;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import React from 'react'
|
import React from 'react';
|
||||||
import { StyledFooter } from './styled'
|
import { StyledFooter } from './styled';
|
||||||
|
|
||||||
const Footer = (): React.ReactElement => <StyledFooter>footer</StyledFooter>
|
const Footer = (): React.ReactElement => <StyledFooter>footer</StyledFooter>;
|
||||||
|
|
||||||
export default Footer
|
export default Footer;
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import styled from 'styled-components'
|
import styled from 'styled-components';
|
||||||
import { times } from '../../size'
|
import { times } from '../../size';
|
||||||
|
|
||||||
export const StyledFooter = styled.div`
|
export const StyledFooter = styled.div`
|
||||||
height: ${times(10)};
|
height: ${times(10)};
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border: 1px solid black;
|
border: 1px solid black;
|
||||||
`
|
`;
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import React from 'react'
|
import React from 'react';
|
||||||
import Footer from '../footer'
|
import Footer from '../footer';
|
||||||
import TopBar from '../top-bar'
|
import TopBar from '../top-bar';
|
||||||
import Canvas from '../canvas'
|
import Canvas from '../canvas';
|
||||||
import { StyledFrame } from './styled'
|
import { StyledFrame } from './styled';
|
||||||
|
|
||||||
const Frame = (): React.ReactElement => (
|
const Frame = (): React.ReactElement => (
|
||||||
<StyledFrame>
|
<StyledFrame>
|
||||||
@ -10,6 +10,6 @@ const Frame = (): React.ReactElement => (
|
|||||||
<Canvas />
|
<Canvas />
|
||||||
<Footer />
|
<Footer />
|
||||||
</StyledFrame>
|
</StyledFrame>
|
||||||
)
|
);
|
||||||
|
|
||||||
export default Frame
|
export default Frame;
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import styled from 'styled-components'
|
import styled from 'styled-components';
|
||||||
|
|
||||||
export const StyledFrame = styled.div`
|
export const StyledFrame = styled.div`
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
`
|
`;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import React from 'react'
|
import React from 'react';
|
||||||
import { StyledTopBar } from './styled'
|
import { StyledTopBar } from './styled';
|
||||||
|
|
||||||
const TopBar = (): React.ReactElement => <StyledTopBar>top bar</StyledTopBar>
|
const TopBar = (): React.ReactElement => <StyledTopBar>top bar</StyledTopBar>;
|
||||||
|
|
||||||
export default TopBar
|
export default TopBar;
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import styled from 'styled-components'
|
import styled from 'styled-components';
|
||||||
import { times } from '../../size'
|
import { times } from '../../size';
|
||||||
|
|
||||||
export const StyledTopBar = styled.div`
|
export const StyledTopBar = styled.div`
|
||||||
height: ${times(10)};
|
height: ${times(10)};
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border: 1px solid black;
|
border: 1px solid black;
|
||||||
`
|
`;
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
import Editor from './components/frame'
|
import Editor from './components/frame';
|
||||||
|
|
||||||
export default Editor
|
export default Editor;
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
const unit = 4 // pixels
|
const unit = 4; // pixels
|
||||||
|
|
||||||
export const XS = '4px'
|
export const XS = '4px';
|
||||||
export const S = '8px'
|
export const S = '8px';
|
||||||
export const M = '16px'
|
export const M = '16px';
|
||||||
export const L = '24px'
|
export const L = '24px';
|
||||||
export const XL = '24px'
|
export const XL = '24px';
|
||||||
|
|
||||||
export const times = (n: number): string => `${unit * n}px`
|
export const times = (n: number): string => `${unit * n}px`;
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
import MapsPage from '../pageObject/MapsPage'
|
import MapsPage from '../pageObject/MapsPage';
|
||||||
|
|
||||||
context('Maps Page', () => {
|
context('Maps Page', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.visit('http://localhost:3000/c/maps')
|
cy.visit('http://localhost:3000/c/maps');
|
||||||
})
|
});
|
||||||
|
|
||||||
it('should load the maps page', () => {
|
it('should load the maps page', () => {
|
||||||
MapsPage.isLoaded()
|
MapsPage.isLoaded();
|
||||||
})
|
});
|
||||||
|
|
||||||
it('should open the create dialog', () => {
|
it('should open the create dialog', () => {
|
||||||
MapsPage.create()
|
MapsPage.create();
|
||||||
MapsPage.isCreateDialogVisible()
|
MapsPage.isCreateDialogVisible();
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
export default class MapsPage {
|
export default class MapsPage {
|
||||||
static isLoaded() {
|
static isLoaded() {
|
||||||
return cy.findByTestId('create')
|
return cy.findByTestId('create');
|
||||||
}
|
}
|
||||||
|
|
||||||
static create() {
|
static create() {
|
||||||
return cy.findByTestId('create').click()
|
return cy.findByTestId('create').click();
|
||||||
}
|
}
|
||||||
|
|
||||||
static isCreateDialogVisible() {
|
static isCreateDialogVisible() {
|
||||||
//TODO move to findByText when the double create dialog issue is solved
|
//TODO move to findByText when the double create dialog issue is solved
|
||||||
return cy.findAllByText('Create a new mindmap')
|
return cy.findAllByText('Create a new mindmap');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,4 +4,4 @@
|
|||||||
module.exports = (on, config) => {
|
module.exports = (on, config) => {
|
||||||
// `on` is used to hook into various events Cypress emits
|
// `on` is used to hook into various events Cypress emits
|
||||||
// `config` is the resolved Cypress config
|
// `config` is the resolved Cypress config
|
||||||
}
|
};
|
||||||
|
@ -1 +1 @@
|
|||||||
import '@testing-library/cypress/add-commands'
|
import '@testing-library/cypress/add-commands';
|
||||||
|
@ -1 +1 @@
|
|||||||
import './commands'
|
import './commands';
|
||||||
|
4
packages/webapp/src/@types/index.d.ts
vendored
4
packages/webapp/src/@types/index.d.ts
vendored
@ -1,2 +1,2 @@
|
|||||||
declare module '*.png'
|
declare module '*.png';
|
||||||
declare module '*.svg'
|
declare module '*.svg';
|
||||||
|
24
packages/webapp/src/@types/typings.d.ts
vendored
24
packages/webapp/src/@types/typings.d.ts
vendored
@ -1,19 +1,19 @@
|
|||||||
declare module '*.jpeg'
|
declare module '*.jpeg';
|
||||||
declare module '*.jpg'
|
declare module '*.jpg';
|
||||||
declare module '*.jpeg'
|
declare module '*.jpeg';
|
||||||
declare module '*.png'
|
declare module '*.png';
|
||||||
declare module '*.svg'
|
declare module '*.svg';
|
||||||
declare module '*.json'
|
declare module '*.json';
|
||||||
|
|
||||||
import { Dayjs } from 'dayjs'
|
import { Dayjs } from 'dayjs';
|
||||||
type DateType = string | number | Date | Dayjs
|
type DateType = string | number | Date | Dayjs;
|
||||||
|
|
||||||
// @Todo: review if there is a better support for this.
|
// @Todo: review if there is a better support for this.
|
||||||
declare module 'dayjs' {
|
declare module 'dayjs' {
|
||||||
interface Dayjs {
|
interface Dayjs {
|
||||||
fromNow(withoutSuffix?: boolean): string
|
fromNow(withoutSuffix?: boolean): string;
|
||||||
from(compared: DateType, withoutSuffix?: boolean): string
|
from(compared: DateType, withoutSuffix?: boolean): string;
|
||||||
toNow(withoutSuffix?: boolean): string
|
toNow(withoutSuffix?: boolean): string;
|
||||||
to(compared: DateType, withoutSuffix?: boolean): string
|
to(compared: DateType, withoutSuffix?: boolean): string;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,20 +1,20 @@
|
|||||||
import React, { ReactElement } from 'react'
|
import React, { ReactElement } from 'react';
|
||||||
import { IntlProvider } from 'react-intl'
|
import { IntlProvider } from 'react-intl';
|
||||||
import { Route, Switch, Redirect, BrowserRouter as Router } from 'react-router-dom'
|
import { Route, Switch, Redirect, BrowserRouter as Router } from 'react-router-dom';
|
||||||
|
|
||||||
import RegistrationSuccessPage from './components/registration-success-page'
|
import RegistrationSuccessPage from './components/registration-success-page';
|
||||||
import ForgotPasswordSuccessPage from './components/forgot-password-success-page'
|
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 store from './redux/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';
|
||||||
import { theme } from './theme'
|
import { theme } from './theme';
|
||||||
import AppI18n, { Locales } from './classes/app-i18n'
|
import AppI18n, { Locales } from './classes/app-i18n';
|
||||||
import MapsPage from './components/maps-page'
|
import MapsPage from './components/maps-page';
|
||||||
import CssBaseline from '@material-ui/core/CssBaseline'
|
import CssBaseline from '@material-ui/core/CssBaseline';
|
||||||
import { ThemeProvider } from '@material-ui/core/styles'
|
import { ThemeProvider } from '@material-ui/core/styles';
|
||||||
|
|
||||||
const queryClient = new QueryClient({
|
const queryClient = new QueryClient({
|
||||||
defaultOptions: {
|
defaultOptions: {
|
||||||
@ -23,11 +23,11 @@ const queryClient = new QueryClient({
|
|||||||
staleTime: 5 * 1000 * 60, // 10 minutes
|
staleTime: 5 * 1000 * 60, // 10 minutes
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
});
|
||||||
|
|
||||||
const App = (): ReactElement => {
|
const App = (): ReactElement => {
|
||||||
const appi18n = new AppI18n()
|
const appi18n = new AppI18n();
|
||||||
const locale = appi18n.getBrowserLocale()
|
const locale = appi18n.getBrowserLocale();
|
||||||
|
|
||||||
return locale.message ? (
|
return locale.message ? (
|
||||||
<Provider store={store}>
|
<Provider store={store}>
|
||||||
@ -70,7 +70,7 @@ const App = (): ReactElement => {
|
|||||||
</Provider>
|
</Provider>
|
||||||
) : (
|
) : (
|
||||||
<div>Loading ... </div>
|
<div>Loading ... </div>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
export default App
|
export default App;
|
||||||
|
@ -1,60 +1,60 @@
|
|||||||
import { fetchAccount } from './../../redux/clientSlice'
|
import { fetchAccount } from './../../redux/clientSlice';
|
||||||
import 'dayjs/locale/fr'
|
import 'dayjs/locale/fr';
|
||||||
import 'dayjs/locale/en'
|
import 'dayjs/locale/en';
|
||||||
import 'dayjs/locale/es'
|
import 'dayjs/locale/es';
|
||||||
|
|
||||||
export class Locale {
|
export class Locale {
|
||||||
code: LocaleCode
|
code: LocaleCode;
|
||||||
label: string
|
label: string;
|
||||||
message: Record<string, string>
|
message: Record<string, string>;
|
||||||
|
|
||||||
constructor(code: LocaleCode, label: string, message: unknown) {
|
constructor(code: LocaleCode, label: string, message: unknown) {
|
||||||
this.code = code
|
this.code = code;
|
||||||
this.label = label
|
this.label = label;
|
||||||
this.message = message as Record<string, string>
|
this.message = message as Record<string, string>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class AppI18n {
|
export default class AppI18n {
|
||||||
public getUserLocale(): Locale {
|
public getUserLocale(): Locale {
|
||||||
const account = fetchAccount()
|
const account = fetchAccount();
|
||||||
return account ? account.locale : this.getBrowserLocale()
|
return account ? account.locale : this.getBrowserLocale();
|
||||||
}
|
}
|
||||||
|
|
||||||
public getBrowserLocale(): Locale {
|
public getBrowserLocale(): Locale {
|
||||||
let localeCode = (navigator.languages && navigator.languages[0]) || navigator.language
|
let localeCode = (navigator.languages && navigator.languages[0]) || navigator.language;
|
||||||
|
|
||||||
// Just remove the variant ...
|
// Just remove the variant ...
|
||||||
localeCode = localeCode.split('-')[0]
|
localeCode = localeCode.split('-')[0];
|
||||||
|
|
||||||
let result = Locales.EN
|
let result = Locales.EN;
|
||||||
try {
|
try {
|
||||||
result = localeFromStr(localeCode)
|
result = localeFromStr(localeCode);
|
||||||
} catch {
|
} catch {
|
||||||
console.warn(`Unsupported languange code ${localeCode}`)
|
console.warn(`Unsupported languange code ${localeCode}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export type LocaleCode = 'en' | 'es' | 'fr' | 'de'
|
export type LocaleCode = 'en' | 'es' | 'fr' | 'de';
|
||||||
|
|
||||||
export const Locales = {
|
export const Locales = {
|
||||||
EN: new Locale('en', 'English', require('./../../compiled-lang/en.json')),
|
EN: new Locale('en', 'English', require('./../../compiled-lang/en.json')),
|
||||||
ES: new Locale('es', 'Español', require('./../../compiled-lang/es.json')),
|
ES: new Locale('es', 'Español', require('./../../compiled-lang/es.json')),
|
||||||
DE: new Locale('fr', 'Français', require('./../../compiled-lang/fr.json')),
|
DE: new Locale('fr', 'Français', require('./../../compiled-lang/fr.json')),
|
||||||
FR: new Locale('de', 'Deutsch', require('./../../compiled-lang/de.json')),
|
FR: new Locale('de', 'Deutsch', require('./../../compiled-lang/de.json')),
|
||||||
}
|
};
|
||||||
|
|
||||||
export const localeFromStr = (code: string): Locale => {
|
export const localeFromStr = (code: string): Locale => {
|
||||||
const locales: Locale[] = Object.values(Locales)
|
const locales: Locale[] = Object.values(Locales);
|
||||||
|
|
||||||
const result = locales.find((l) => l.code == code)
|
const result = locales.find((l) => l.code == code);
|
||||||
|
|
||||||
if (!result) {
|
if (!result) {
|
||||||
throw `Language code could not be found in list of default supported: + ${code}`
|
throw `Language code could not be found in list of default supported: + ${code}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result;
|
||||||
}
|
};
|
||||||
|
@ -1,21 +1,21 @@
|
|||||||
import { useSelector } from 'react-redux'
|
import { useSelector } from 'react-redux';
|
||||||
import React from 'react'
|
import React from 'react';
|
||||||
import { activeInstanceStatus, ClientStatus } from '../../../redux/clientSlice'
|
import { activeInstanceStatus, ClientStatus } from '../../../redux/clientSlice';
|
||||||
import { FormattedMessage } from 'react-intl'
|
import { FormattedMessage } from 'react-intl';
|
||||||
import Dialog from '@material-ui/core/Dialog'
|
import Dialog from '@material-ui/core/Dialog';
|
||||||
import DialogTitle from '@material-ui/core/DialogTitle'
|
import DialogTitle from '@material-ui/core/DialogTitle';
|
||||||
import DialogContent from '@material-ui/core/DialogContent'
|
import DialogContent from '@material-ui/core/DialogContent';
|
||||||
import Alert from '@material-ui/lab/Alert'
|
import Alert from '@material-ui/lab/Alert';
|
||||||
import DialogActions from '@material-ui/core/DialogActions'
|
import DialogActions from '@material-ui/core/DialogActions';
|
||||||
import Button from '@material-ui/core/Button'
|
import Button from '@material-ui/core/Button';
|
||||||
import AlertTitle from '@material-ui/lab/AlertTitle'
|
import AlertTitle from '@material-ui/lab/AlertTitle';
|
||||||
|
|
||||||
const ClientHealthSentinel = (): React.ReactElement => {
|
const ClientHealthSentinel = (): React.ReactElement => {
|
||||||
const status: ClientStatus = useSelector(activeInstanceStatus)
|
const status: ClientStatus = useSelector(activeInstanceStatus);
|
||||||
|
|
||||||
const handleOnClose = () => {
|
const handleOnClose = () => {
|
||||||
window.location.href = '/c/login'
|
window.location.href = '/c/login';
|
||||||
}
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@ -50,6 +50,6 @@ const ClientHealthSentinel = (): React.ReactElement => {
|
|||||||
</DialogActions>
|
</DialogActions>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
export default ClientHealthSentinel
|
export default ClientHealthSentinel;
|
||||||
|
@ -1,108 +1,108 @@
|
|||||||
import { Locale, LocaleCode } from '../app-i18n'
|
import { Locale, LocaleCode } from '../app-i18n';
|
||||||
|
|
||||||
export type NewUser = {
|
export type NewUser = {
|
||||||
email: string
|
email: string;
|
||||||
firstname: string
|
firstname: string;
|
||||||
lastname: string
|
lastname: string;
|
||||||
password: string
|
password: string;
|
||||||
recaptcha: string | null
|
recaptcha: string | null;
|
||||||
}
|
};
|
||||||
|
|
||||||
export type ImportMapInfo = {
|
export type ImportMapInfo = {
|
||||||
title: string
|
title: string;
|
||||||
description?: string
|
description?: string;
|
||||||
contentType?: string
|
contentType?: string;
|
||||||
content?: ArrayBuffer | null | string
|
content?: ArrayBuffer | null | string;
|
||||||
}
|
};
|
||||||
|
|
||||||
export type Label = {
|
export type Label = {
|
||||||
id: number
|
id: number;
|
||||||
title: string
|
title: string;
|
||||||
color: string
|
color: string;
|
||||||
iconName: string
|
iconName: string;
|
||||||
}
|
};
|
||||||
|
|
||||||
export type Role = 'owner' | 'editor' | 'viewer'
|
export type Role = 'owner' | 'editor' | 'viewer';
|
||||||
|
|
||||||
export type MapInfo = {
|
export type MapInfo = {
|
||||||
id: number
|
id: number;
|
||||||
starred: boolean
|
starred: boolean;
|
||||||
title: string
|
title: string;
|
||||||
labels: number[]
|
labels: number[];
|
||||||
createdBy: string
|
createdBy: string;
|
||||||
creationTime: string
|
creationTime: string;
|
||||||
lastModificationBy: string
|
lastModificationBy: string;
|
||||||
lastModificationTime: string
|
lastModificationTime: string;
|
||||||
description: string
|
description: string;
|
||||||
isPublic: boolean
|
isPublic: boolean;
|
||||||
role: Role
|
role: Role;
|
||||||
}
|
};
|
||||||
|
|
||||||
export type ChangeHistory = {
|
export type ChangeHistory = {
|
||||||
id: number
|
id: number;
|
||||||
lastModificationBy: string
|
lastModificationBy: string;
|
||||||
lastModificationTime: string
|
lastModificationTime: string;
|
||||||
}
|
};
|
||||||
|
|
||||||
export type BasicMapInfo = {
|
export type BasicMapInfo = {
|
||||||
title: string
|
title: string;
|
||||||
description?: string
|
description?: string;
|
||||||
}
|
};
|
||||||
|
|
||||||
export type FieldError = {
|
export type FieldError = {
|
||||||
id: string
|
id: string;
|
||||||
msg: string
|
msg: string;
|
||||||
}
|
};
|
||||||
|
|
||||||
export type ErrorInfo = {
|
export type ErrorInfo = {
|
||||||
msg?: string
|
msg?: string;
|
||||||
fields?: Map<string, string>
|
fields?: Map<string, string>;
|
||||||
}
|
};
|
||||||
|
|
||||||
export type AccountInfo = {
|
export type AccountInfo = {
|
||||||
firstname: string
|
firstname: string;
|
||||||
lastname: string
|
lastname: string;
|
||||||
email: string
|
email: string;
|
||||||
locale: Locale
|
locale: Locale;
|
||||||
}
|
};
|
||||||
|
|
||||||
export type Permission = {
|
export type Permission = {
|
||||||
name?: string
|
name?: string;
|
||||||
email: string
|
email: string;
|
||||||
role: Role
|
role: Role;
|
||||||
}
|
};
|
||||||
|
|
||||||
interface Client {
|
interface Client {
|
||||||
deleteAccount(): Promise<void>
|
deleteAccount(): Promise<void>;
|
||||||
importMap(model: ImportMapInfo): Promise<number>
|
importMap(model: ImportMapInfo): Promise<number>;
|
||||||
createMap(map: BasicMapInfo): Promise<number>
|
createMap(map: BasicMapInfo): Promise<number>;
|
||||||
deleteMaps(ids: number[]): Promise<void>
|
deleteMaps(ids: number[]): Promise<void>;
|
||||||
deleteMap(id: number): Promise<void>
|
deleteMap(id: number): Promise<void>;
|
||||||
renameMap(id: number, basicInfo: BasicMapInfo): Promise<void>
|
renameMap(id: number, basicInfo: BasicMapInfo): Promise<void>;
|
||||||
fetchAllMaps(): Promise<MapInfo[]>
|
fetchAllMaps(): Promise<MapInfo[]>;
|
||||||
|
|
||||||
fetchMapPermissions(id: number): Promise<Permission[]>
|
fetchMapPermissions(id: number): Promise<Permission[]>;
|
||||||
addMapPermissions(id: number, message: string, permissions: Permission[]): Promise<void>
|
addMapPermissions(id: number, message: string, permissions: Permission[]): Promise<void>;
|
||||||
deleteMapPermission(id: number, email: string): Promise<void>
|
deleteMapPermission(id: number, email: string): Promise<void>;
|
||||||
|
|
||||||
duplicateMap(id: number, basicInfo: BasicMapInfo): Promise<number>
|
duplicateMap(id: number, basicInfo: BasicMapInfo): Promise<number>;
|
||||||
|
|
||||||
updateAccountLanguage(locale: LocaleCode): Promise<void>
|
updateAccountLanguage(locale: LocaleCode): Promise<void>;
|
||||||
updateAccountPassword(pasword: string): Promise<void>
|
updateAccountPassword(pasword: string): Promise<void>;
|
||||||
updateAccountInfo(firstname: string, lastname: string): Promise<void>
|
updateAccountInfo(firstname: string, lastname: string): Promise<void>;
|
||||||
|
|
||||||
updateStarred(id: number, starred: boolean): Promise<void>
|
updateStarred(id: number, starred: boolean): Promise<void>;
|
||||||
updateMapToPublic(id: number, starred: boolean): Promise<void>
|
updateMapToPublic(id: number, starred: boolean): Promise<void>;
|
||||||
|
|
||||||
fetchLabels(): Promise<Label[]>
|
fetchLabels(): Promise<Label[]>;
|
||||||
deleteLabel(id: number): Promise<void>
|
deleteLabel(id: number): Promise<void>;
|
||||||
fetchAccountInfo(): Promise<AccountInfo>
|
fetchAccountInfo(): Promise<AccountInfo>;
|
||||||
|
|
||||||
registerNewUser(user: NewUser): Promise<void>
|
registerNewUser(user: NewUser): Promise<void>;
|
||||||
resetPassword(email: string): Promise<void>
|
resetPassword(email: string): Promise<void>;
|
||||||
|
|
||||||
fetchHistory(id: number): Promise<ChangeHistory[]>
|
fetchHistory(id: number): Promise<ChangeHistory[]>;
|
||||||
revertHistory(id: number, cid: number): Promise<void>
|
revertHistory(id: number, cid: number): Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Client
|
export default Client;
|
||||||
|
@ -7,13 +7,13 @@ import Client, {
|
|||||||
MapInfo,
|
MapInfo,
|
||||||
NewUser,
|
NewUser,
|
||||||
Permission,
|
Permission,
|
||||||
} from '..'
|
} from '..';
|
||||||
import { LocaleCode, localeFromStr } from '../../app-i18n'
|
import { LocaleCode, localeFromStr } from '../../app-i18n';
|
||||||
|
|
||||||
class MockClient implements Client {
|
class MockClient implements Client {
|
||||||
private maps: MapInfo[] = []
|
private maps: MapInfo[] = [];
|
||||||
private labels: Label[] = []
|
private labels: Label[] = [];
|
||||||
private permissionsByMap: Map<number, Permission[]> = new Map()
|
private permissionsByMap: Map<number, Permission[]> = new Map();
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
// Remove, just for develop ....
|
// Remove, just for develop ....
|
||||||
@ -42,7 +42,7 @@ class MockClient implements Client {
|
|||||||
description,
|
description,
|
||||||
isPublic,
|
isPublic,
|
||||||
role,
|
role,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
this.maps = [
|
this.maps = [
|
||||||
@ -85,31 +85,31 @@ class MockClient implements Client {
|
|||||||
false,
|
false,
|
||||||
'editor'
|
'editor'
|
||||||
),
|
),
|
||||||
]
|
];
|
||||||
|
|
||||||
this.labels = [
|
this.labels = [
|
||||||
{ id: 1, title: 'Red Label', iconName: '', color: 'red' },
|
{ id: 1, title: 'Red Label', iconName: '', color: 'red' },
|
||||||
{ id: 2, title: 'Blue Label', iconName: '', color: 'blue' },
|
{ id: 2, title: 'Blue Label', iconName: '', color: 'blue' },
|
||||||
]
|
];
|
||||||
}
|
}
|
||||||
deleteMapPermission(id: number, email: string): Promise<void> {
|
deleteMapPermission(id: number, email: string): Promise<void> {
|
||||||
let perm = this.permissionsByMap.get(id) || []
|
let perm = this.permissionsByMap.get(id) || [];
|
||||||
perm = perm.filter((p) => p.email != email)
|
perm = perm.filter((p) => p.email != email);
|
||||||
this.permissionsByMap.set(id, perm)
|
this.permissionsByMap.set(id, perm);
|
||||||
return Promise.resolve()
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
addMapPermissions(id: number, message: string, permissions: Permission[]): Promise<void> {
|
addMapPermissions(id: number, message: string, permissions: Permission[]): Promise<void> {
|
||||||
let perm = this.permissionsByMap.get(id) || []
|
let perm = this.permissionsByMap.get(id) || [];
|
||||||
perm = perm.concat(permissions)
|
perm = perm.concat(permissions);
|
||||||
this.permissionsByMap.set(id, perm)
|
this.permissionsByMap.set(id, perm);
|
||||||
|
|
||||||
console.log(`Message ${message}`)
|
console.log(`Message ${message}`);
|
||||||
return Promise.resolve()
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
fetchMapPermissions(id: number): Promise<Permission[]> {
|
fetchMapPermissions(id: number): Promise<Permission[]> {
|
||||||
let perm = this.permissionsByMap.get(id)
|
let perm = this.permissionsByMap.get(id);
|
||||||
if (!perm) {
|
if (!perm) {
|
||||||
perm = [
|
perm = [
|
||||||
{
|
{
|
||||||
@ -127,107 +127,107 @@ class MockClient implements Client {
|
|||||||
email: 'pepe3@example.com',
|
email: 'pepe3@example.com',
|
||||||
role: 'viewer',
|
role: 'viewer',
|
||||||
},
|
},
|
||||||
]
|
];
|
||||||
this.permissionsByMap.set(id, perm)
|
this.permissionsByMap.set(id, perm);
|
||||||
}
|
}
|
||||||
return Promise.resolve(perm)
|
return Promise.resolve(perm);
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteAccount(): Promise<void> {
|
deleteAccount(): Promise<void> {
|
||||||
return Promise.resolve()
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
updateAccountInfo(firstname: string, lastname: string): Promise<void> {
|
updateAccountInfo(firstname: string, lastname: string): Promise<void> {
|
||||||
console.log('firstname:' + firstname, +lastname)
|
console.log('firstname:' + firstname, +lastname);
|
||||||
return Promise.resolve()
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
updateAccountPassword(pasword: string): Promise<void> {
|
updateAccountPassword(pasword: string): Promise<void> {
|
||||||
console.log('password:' + pasword)
|
console.log('password:' + pasword);
|
||||||
return Promise.resolve()
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
updateAccountLanguage(locale: LocaleCode): Promise<void> {
|
updateAccountLanguage(locale: LocaleCode): Promise<void> {
|
||||||
localStorage.setItem('locale', locale)
|
localStorage.setItem('locale', locale);
|
||||||
return Promise.resolve()
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
importMap(model: ImportMapInfo): Promise<number> {
|
importMap(model: ImportMapInfo): Promise<number> {
|
||||||
console.log('model:' + model)
|
console.log('model:' + model);
|
||||||
return Promise.resolve(10)
|
return Promise.resolve(10);
|
||||||
}
|
}
|
||||||
|
|
||||||
fetchAccountInfo(): Promise<AccountInfo> {
|
fetchAccountInfo(): Promise<AccountInfo> {
|
||||||
console.log('Fetch account info ...')
|
console.log('Fetch account info ...');
|
||||||
const locale: LocaleCode | null = localStorage.getItem('locale') as LocaleCode
|
const locale: LocaleCode | null = localStorage.getItem('locale') as LocaleCode;
|
||||||
return Promise.resolve({
|
return Promise.resolve({
|
||||||
firstname: 'Costme',
|
firstname: 'Costme',
|
||||||
lastname: 'Fulanito',
|
lastname: 'Fulanito',
|
||||||
email: 'test@example.com',
|
email: 'test@example.com',
|
||||||
locale: localeFromStr(locale),
|
locale: localeFromStr(locale),
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteMaps(ids: number[]): Promise<void> {
|
deleteMaps(ids: number[]): Promise<void> {
|
||||||
ids.forEach((id) => this.deleteMap(id))
|
ids.forEach((id) => this.deleteMap(id));
|
||||||
return Promise.resolve()
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
revertHistory(id: number, cid: number): Promise<void> {
|
revertHistory(id: number, cid: number): Promise<void> {
|
||||||
console.log('model:' + id + cid)
|
console.log('model:' + id + cid);
|
||||||
return Promise.resolve()
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
createMap(map: BasicMapInfo): Promise<number> {
|
createMap(map: BasicMapInfo): Promise<number> {
|
||||||
throw new Error('Method not implemented.' + map)
|
throw new Error('Method not implemented.' + map);
|
||||||
}
|
}
|
||||||
|
|
||||||
fetchLabels(): Promise<Label[]> {
|
fetchLabels(): Promise<Label[]> {
|
||||||
console.log('Fetching labels from server')
|
console.log('Fetching labels from server');
|
||||||
return Promise.resolve(this.labels)
|
return Promise.resolve(this.labels);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateMapToPublic(id: number, isPublic: boolean): Promise<void> {
|
updateMapToPublic(id: number, isPublic: boolean): Promise<void> {
|
||||||
const mapInfo = this.maps.find((m) => m.id == id)
|
const mapInfo = this.maps.find((m) => m.id == id);
|
||||||
if (mapInfo) {
|
if (mapInfo) {
|
||||||
mapInfo.isPublic = isPublic
|
mapInfo.isPublic = isPublic;
|
||||||
}
|
}
|
||||||
return Promise.resolve()
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
updateStarred(id: number, starred: boolean): Promise<void> {
|
updateStarred(id: number, starred: boolean): Promise<void> {
|
||||||
const mapInfo = this.maps.find((m) => m.id == id)
|
const mapInfo = this.maps.find((m) => m.id == id);
|
||||||
if (!mapInfo) {
|
if (!mapInfo) {
|
||||||
console.log(`Could not find the map iwth id ${id}`)
|
console.log(`Could not find the map iwth id ${id}`);
|
||||||
return Promise.reject()
|
return Promise.reject();
|
||||||
}
|
}
|
||||||
mapInfo.starred = starred
|
mapInfo.starred = starred;
|
||||||
return Promise.resolve()
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
renameMap(id: number, basicInfo: BasicMapInfo): Promise<void> {
|
renameMap(id: number, basicInfo: BasicMapInfo): Promise<void> {
|
||||||
const exists = this.maps.find((m) => m.title == basicInfo.title) != undefined
|
const exists = this.maps.find((m) => m.title == basicInfo.title) != undefined;
|
||||||
if (!exists) {
|
if (!exists) {
|
||||||
this.maps = this.maps.map((m) => {
|
this.maps = this.maps.map((m) => {
|
||||||
const result = m
|
const result = m;
|
||||||
if (m.id == id) {
|
if (m.id == id) {
|
||||||
result.description = basicInfo.description ? basicInfo.description : ''
|
result.description = basicInfo.description ? basicInfo.description : '';
|
||||||
result.title = basicInfo.title
|
result.title = basicInfo.title;
|
||||||
}
|
}
|
||||||
return result
|
return result;
|
||||||
})
|
});
|
||||||
return Promise.resolve()
|
return Promise.resolve();
|
||||||
} else {
|
} else {
|
||||||
const fieldErrors: Map<string, string> = new Map<string, string>()
|
const fieldErrors: Map<string, string> = new Map<string, string>();
|
||||||
fieldErrors.set('name', 'name already exists ')
|
fieldErrors.set('name', 'name already exists ');
|
||||||
|
|
||||||
return Promise.reject({
|
return Promise.reject({
|
||||||
msg: 'Map already exists ...' + basicInfo.title,
|
msg: 'Map already exists ...' + basicInfo.title,
|
||||||
fields: fieldErrors,
|
fields: fieldErrors,
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fetchHistory(id: number): Promise<ChangeHistory[]> {
|
fetchHistory(id: number): Promise<ChangeHistory[]> {
|
||||||
console.log(`Fetching history for ${id}`)
|
console.log(`Fetching history for ${id}`);
|
||||||
const result = [
|
const result = [
|
||||||
{
|
{
|
||||||
id: 1,
|
id: 1,
|
||||||
@ -264,12 +264,12 @@ class MockClient implements Client {
|
|||||||
lastModificationBy: 'Paulo',
|
lastModificationBy: 'Paulo',
|
||||||
lastModificationTime: '2008-06-02T00:00:00Z',
|
lastModificationTime: '2008-06-02T00:00:00Z',
|
||||||
},
|
},
|
||||||
]
|
];
|
||||||
return Promise.resolve(result)
|
return Promise.resolve(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
duplicateMap(id: number, basicInfo: BasicMapInfo): Promise<number> {
|
duplicateMap(id: number, basicInfo: BasicMapInfo): Promise<number> {
|
||||||
const exists = this.maps.find((m) => m.title == basicInfo.title) != undefined
|
const exists = this.maps.find((m) => m.title == basicInfo.title) != undefined;
|
||||||
if (!exists) {
|
if (!exists) {
|
||||||
const newMap: MapInfo = {
|
const newMap: MapInfo = {
|
||||||
id: Math.random() * 1000,
|
id: Math.random() * 1000,
|
||||||
@ -283,45 +283,45 @@ class MockClient implements Client {
|
|||||||
creationTime: '2008-06-02T00:00:00Z',
|
creationTime: '2008-06-02T00:00:00Z',
|
||||||
isPublic: false,
|
isPublic: false,
|
||||||
role: 'owner',
|
role: 'owner',
|
||||||
}
|
};
|
||||||
this.maps.push(newMap)
|
this.maps.push(newMap);
|
||||||
return Promise.resolve(newMap.id)
|
return Promise.resolve(newMap.id);
|
||||||
} else {
|
} else {
|
||||||
const fieldErrors: Map<string, string> = new Map<string, string>()
|
const fieldErrors: Map<string, string> = new Map<string, string>();
|
||||||
fieldErrors.set('name', 'name already exists ')
|
fieldErrors.set('name', 'name already exists ');
|
||||||
|
|
||||||
return Promise.reject({
|
return Promise.reject({
|
||||||
msg: 'Maps name must be unique:' + basicInfo.title,
|
msg: 'Maps name must be unique:' + basicInfo.title,
|
||||||
fields: fieldErrors,
|
fields: fieldErrors,
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteLabel(id: number): Promise<void> {
|
deleteLabel(id: number): Promise<void> {
|
||||||
this.labels = this.labels.filter((l) => l.id != id)
|
this.labels = this.labels.filter((l) => l.id != id);
|
||||||
console.log('Label delete:' + this.labels)
|
console.log('Label delete:' + this.labels);
|
||||||
return Promise.resolve()
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteMap(id: number): Promise<void> {
|
deleteMap(id: number): Promise<void> {
|
||||||
this.maps = this.maps.filter((m) => m.id != id)
|
this.maps = this.maps.filter((m) => m.id != id);
|
||||||
return Promise.resolve()
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
registerNewUser(user: NewUser): Promise<void> {
|
registerNewUser(user: NewUser): Promise<void> {
|
||||||
console.log('user:' + user)
|
console.log('user:' + user);
|
||||||
return Promise.resolve()
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
fetchAllMaps(): Promise<MapInfo[]> {
|
fetchAllMaps(): Promise<MapInfo[]> {
|
||||||
console.log('Fetching maps from server')
|
console.log('Fetching maps from server');
|
||||||
return Promise.resolve(this.maps)
|
return Promise.resolve(this.maps);
|
||||||
}
|
}
|
||||||
|
|
||||||
resetPassword(email: string): Promise<void> {
|
resetPassword(email: string): Promise<void> {
|
||||||
console.log('email:' + email)
|
console.log('email:' + email);
|
||||||
return Promise.resolve()
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default MockClient
|
export default MockClient;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import axios from 'axios'
|
import axios from 'axios';
|
||||||
import Client, {
|
import Client, {
|
||||||
ErrorInfo,
|
ErrorInfo,
|
||||||
MapInfo,
|
MapInfo,
|
||||||
@ -9,16 +9,16 @@ import Client, {
|
|||||||
AccountInfo,
|
AccountInfo,
|
||||||
ImportMapInfo,
|
ImportMapInfo,
|
||||||
Permission,
|
Permission,
|
||||||
} from '..'
|
} from '..';
|
||||||
import { LocaleCode, localeFromStr, Locales } from '../../app-i18n'
|
import { LocaleCode, localeFromStr, Locales } from '../../app-i18n';
|
||||||
|
|
||||||
export default class RestClient implements Client {
|
export default class RestClient implements Client {
|
||||||
private baseUrl: string
|
private baseUrl: string;
|
||||||
private sessionExpired: () => void
|
private sessionExpired: () => void;
|
||||||
|
|
||||||
constructor(baseUrl: string, sessionExpired: () => void) {
|
constructor(baseUrl: string, sessionExpired: () => void) {
|
||||||
this.baseUrl = baseUrl
|
this.baseUrl = baseUrl;
|
||||||
this.sessionExpired = sessionExpired
|
this.sessionExpired = sessionExpired;
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteMapPermission(id: number, email: string): Promise<void> {
|
deleteMapPermission(id: number, email: string): Promise<void> {
|
||||||
@ -28,14 +28,14 @@ export default class RestClient implements Client {
|
|||||||
headers: { 'Content-Type': 'text/plain' },
|
headers: { 'Content-Type': 'text/plain' },
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
success()
|
success();
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
const errorInfo = this.parseResponseOnError(error.response)
|
const errorInfo = this.parseResponseOnError(error.response);
|
||||||
reject(errorInfo)
|
reject(errorInfo);
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
return new Promise(handler)
|
return new Promise(handler);
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
addMapPermissions(id: number, message: string, permissions: Permission[]): Promise<void> {
|
addMapPermissions(id: number, message: string, permissions: Permission[]): Promise<void> {
|
||||||
@ -51,14 +51,14 @@ export default class RestClient implements Client {
|
|||||||
)
|
)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
// All was ok, let's sent to success page ...;
|
// All was ok, let's sent to success page ...;
|
||||||
success()
|
success();
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
const errorInfo = this.parseResponseOnError(error.response)
|
const errorInfo = this.parseResponseOnError(error.response);
|
||||||
reject(errorInfo)
|
reject(errorInfo);
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
return new Promise(handler)
|
return new Promise(handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
fetchMapPermissions(id: number): Promise<Permission[]> {
|
fetchMapPermissions(id: number): Promise<Permission[]> {
|
||||||
@ -71,7 +71,7 @@ export default class RestClient implements Client {
|
|||||||
headers: { 'Content-Type': 'text/plain' },
|
headers: { 'Content-Type': 'text/plain' },
|
||||||
})
|
})
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
const data = response.data
|
const data = response.data;
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
const perms: Permission[] = (data.collaborations as any[]).map((p) => {
|
const perms: Permission[] = (data.collaborations as any[]).map((p) => {
|
||||||
return {
|
return {
|
||||||
@ -79,16 +79,16 @@ export default class RestClient implements Client {
|
|||||||
email: p.email,
|
email: p.email,
|
||||||
name: p.name,
|
name: p.name,
|
||||||
role: p.role,
|
role: p.role,
|
||||||
}
|
};
|
||||||
})
|
});
|
||||||
success(perms)
|
success(perms);
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
const errorInfo = this.parseResponseOnError(error.response)
|
const errorInfo = this.parseResponseOnError(error.response);
|
||||||
reject(errorInfo)
|
reject(errorInfo);
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
return new Promise(handler)
|
return new Promise(handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteAccount(): Promise<void> {
|
deleteAccount(): Promise<void> {
|
||||||
@ -98,14 +98,14 @@ export default class RestClient implements Client {
|
|||||||
headers: { 'Content-Type': 'text/plain' },
|
headers: { 'Content-Type': 'text/plain' },
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
success()
|
success();
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
const errorInfo = this.parseResponseOnError(error.response)
|
const errorInfo = this.parseResponseOnError(error.response);
|
||||||
reject(errorInfo)
|
reject(errorInfo);
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
return new Promise(handler)
|
return new Promise(handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateAccountInfo(firstname: string, lastname: string): Promise<void> {
|
updateAccountInfo(firstname: string, lastname: string): Promise<void> {
|
||||||
@ -117,18 +117,18 @@ export default class RestClient implements Client {
|
|||||||
.then(() => {
|
.then(() => {
|
||||||
return axios.put(`${this.baseUrl}/c/restful/account/lastname`, lastname, {
|
return axios.put(`${this.baseUrl}/c/restful/account/lastname`, lastname, {
|
||||||
headers: { 'Content-Type': 'text/plain' },
|
headers: { 'Content-Type': 'text/plain' },
|
||||||
})
|
});
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
// All was ok, let's sent to success page ...;
|
// All was ok, let's sent to success page ...;
|
||||||
success()
|
success();
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
const errorInfo = this.parseResponseOnError(error.response)
|
const errorInfo = this.parseResponseOnError(error.response);
|
||||||
reject(errorInfo)
|
reject(errorInfo);
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
return new Promise(handler)
|
return new Promise(handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateAccountPassword(pasword: string): Promise<void> {
|
updateAccountPassword(pasword: string): Promise<void> {
|
||||||
@ -138,14 +138,14 @@ export default class RestClient implements Client {
|
|||||||
headers: { 'Content-Type': 'text/plain' },
|
headers: { 'Content-Type': 'text/plain' },
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
success()
|
success();
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
const errorInfo = this.parseResponseOnError(error.response)
|
const errorInfo = this.parseResponseOnError(error.response);
|
||||||
reject(errorInfo)
|
reject(errorInfo);
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
return new Promise(handler)
|
return new Promise(handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateAccountLanguage(locale: LocaleCode): Promise<void> {
|
updateAccountLanguage(locale: LocaleCode): Promise<void> {
|
||||||
@ -156,14 +156,14 @@ export default class RestClient implements Client {
|
|||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
// All was ok, let's sent to success page ...;
|
// All was ok, let's sent to success page ...;
|
||||||
success()
|
success();
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
const errorInfo = this.parseResponseOnError(error.response)
|
const errorInfo = this.parseResponseOnError(error.response);
|
||||||
reject(errorInfo)
|
reject(errorInfo);
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
return new Promise(handler)
|
return new Promise(handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
importMap(model: ImportMapInfo): Promise<number> {
|
importMap(model: ImportMapInfo): Promise<number> {
|
||||||
@ -177,15 +177,15 @@ export default class RestClient implements Client {
|
|||||||
{ headers: { 'Content-Type': model.contentType } }
|
{ headers: { 'Content-Type': model.contentType } }
|
||||||
)
|
)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
const mapId = response.headers.resourceid
|
const mapId = response.headers.resourceid;
|
||||||
success(mapId)
|
success(mapId);
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
const errorInfo = this.parseResponseOnError(error.response)
|
const errorInfo = this.parseResponseOnError(error.response);
|
||||||
reject(errorInfo)
|
reject(errorInfo);
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
return new Promise(handler)
|
return new Promise(handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
fetchAccountInfo(): Promise<AccountInfo> {
|
fetchAccountInfo(): Promise<AccountInfo> {
|
||||||
@ -198,21 +198,21 @@ export default class RestClient implements Client {
|
|||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
})
|
})
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
const account = response.data
|
const account = response.data;
|
||||||
const locale: LocaleCode | null = account.locale
|
const locale: LocaleCode | null = account.locale;
|
||||||
success({
|
success({
|
||||||
lastname: account.lastname ? account.lastname : '',
|
lastname: account.lastname ? account.lastname : '',
|
||||||
firstname: account.firstname ? account.firstname : '',
|
firstname: account.firstname ? account.firstname : '',
|
||||||
email: account.email,
|
email: account.email,
|
||||||
locale: locale ? localeFromStr(locale) : Locales.EN,
|
locale: locale ? localeFromStr(locale) : Locales.EN,
|
||||||
})
|
});
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
const errorInfo = this.parseResponseOnError(error.response)
|
const errorInfo = this.parseResponseOnError(error.response);
|
||||||
reject(errorInfo)
|
reject(errorInfo);
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
return new Promise(handler)
|
return new Promise(handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteMaps(ids: number[]): Promise<void> {
|
deleteMaps(ids: number[]): Promise<void> {
|
||||||
@ -222,15 +222,15 @@ export default class RestClient implements Client {
|
|||||||
headers: { 'Content-Type': 'text/plain' },
|
headers: { 'Content-Type': 'text/plain' },
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
success()
|
success();
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
const response = error.response
|
const response = error.response;
|
||||||
const errorInfo = this.parseResponseOnError(response)
|
const errorInfo = this.parseResponseOnError(response);
|
||||||
reject(errorInfo)
|
reject(errorInfo);
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
return new Promise(handler)
|
return new Promise(handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateMapToPublic(id: number, isPublic: boolean): Promise<void> {
|
updateMapToPublic(id: number, isPublic: boolean): Promise<void> {
|
||||||
@ -241,14 +241,14 @@ export default class RestClient implements Client {
|
|||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
// All was ok, let's sent to success page ...;
|
// All was ok, let's sent to success page ...;
|
||||||
success()
|
success();
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
const errorInfo = this.parseResponseOnError(error.response)
|
const errorInfo = this.parseResponseOnError(error.response);
|
||||||
reject(errorInfo)
|
reject(errorInfo);
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
return new Promise(handler)
|
return new Promise(handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
revertHistory(id: number, hid: number): Promise<void> {
|
revertHistory(id: number, hid: number): Promise<void> {
|
||||||
@ -258,18 +258,18 @@ export default class RestClient implements Client {
|
|||||||
headers: { 'Content-Type': 'text/pain' },
|
headers: { 'Content-Type': 'text/pain' },
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
success()
|
success();
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
const errorInfo = this.parseResponseOnError(error.response)
|
const errorInfo = this.parseResponseOnError(error.response);
|
||||||
reject(errorInfo)
|
reject(errorInfo);
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
return new Promise(handler)
|
return new Promise(handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
fetchHistory(id: number): Promise<ChangeHistory[]> {
|
fetchHistory(id: number): Promise<ChangeHistory[]> {
|
||||||
throw new Error(`Method not implemented. ${id}`)
|
throw new Error(`Method not implemented. ${id}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
renameMap(id: number, basicInfo: BasicMapInfo): Promise<void> {
|
renameMap(id: number, basicInfo: BasicMapInfo): Promise<void> {
|
||||||
@ -283,19 +283,19 @@ export default class RestClient implements Client {
|
|||||||
`${this.baseUrl}/c/restful/maps/${id}/description`,
|
`${this.baseUrl}/c/restful/maps/${id}/description`,
|
||||||
basicInfo.description,
|
basicInfo.description,
|
||||||
{ headers: { 'Content-Type': 'text/plain' } }
|
{ headers: { 'Content-Type': 'text/plain' } }
|
||||||
)
|
);
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
// All was ok, let's sent to success page ...;
|
// All was ok, let's sent to success page ...;
|
||||||
success()
|
success();
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
const response = error.response
|
const response = error.response;
|
||||||
const errorInfo = this.parseResponseOnError(response)
|
const errorInfo = this.parseResponseOnError(response);
|
||||||
reject(errorInfo)
|
reject(errorInfo);
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
return new Promise(handler)
|
return new Promise(handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
createMap(model: BasicMapInfo): Promise<number> {
|
createMap(model: BasicMapInfo): Promise<number> {
|
||||||
@ -309,15 +309,15 @@ export default class RestClient implements Client {
|
|||||||
{ headers: { 'Content-Type': 'application/json' } }
|
{ headers: { 'Content-Type': 'application/json' } }
|
||||||
)
|
)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
const mapId = response.headers.resourceid
|
const mapId = response.headers.resourceid;
|
||||||
success(mapId)
|
success(mapId);
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
const errorInfo = this.parseResponseOnError(error.response)
|
const errorInfo = this.parseResponseOnError(error.response);
|
||||||
reject(errorInfo)
|
reject(errorInfo);
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
return new Promise(handler)
|
return new Promise(handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
fetchAllMaps(): Promise<MapInfo[]> {
|
fetchAllMaps(): Promise<MapInfo[]> {
|
||||||
@ -330,7 +330,7 @@ export default class RestClient implements Client {
|
|||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
})
|
})
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
const data = response.data
|
const data = response.data;
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
const maps: MapInfo[] = (data.mindmapsInfo as any[]).map((m) => {
|
const maps: MapInfo[] = (data.mindmapsInfo as any[]).map((m) => {
|
||||||
return {
|
return {
|
||||||
@ -345,20 +345,20 @@ export default class RestClient implements Client {
|
|||||||
description: m.description,
|
description: m.description,
|
||||||
isPublic: m['public'],
|
isPublic: m['public'],
|
||||||
role: m.role,
|
role: m.role,
|
||||||
}
|
};
|
||||||
})
|
});
|
||||||
success(maps)
|
success(maps);
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
console.log('Maps List Error=>')
|
console.log('Maps List Error=>');
|
||||||
console.log(error)
|
console.log(error);
|
||||||
|
|
||||||
const response = error.response
|
const response = error.response;
|
||||||
const errorInfo = this.parseResponseOnError(response)
|
const errorInfo = this.parseResponseOnError(response);
|
||||||
reject(errorInfo)
|
reject(errorInfo);
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
return new Promise(handler)
|
return new Promise(handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
registerNewUser(user: NewUser): Promise<void> {
|
registerNewUser(user: NewUser): Promise<void> {
|
||||||
@ -369,16 +369,16 @@ export default class RestClient implements Client {
|
|||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
// All was ok, let's sent to success page ...;
|
// All was ok, let's sent to success page ...;
|
||||||
success()
|
success();
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
console.log(error)
|
console.log(error);
|
||||||
const response = error.response
|
const response = error.response;
|
||||||
const errorInfo = this.parseResponseOnError(response)
|
const errorInfo = this.parseResponseOnError(response);
|
||||||
reject(errorInfo)
|
reject(errorInfo);
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
return new Promise(handler)
|
return new Promise(handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteMap(id: number): Promise<void> {
|
deleteMap(id: number): Promise<void> {
|
||||||
@ -388,14 +388,14 @@ export default class RestClient implements Client {
|
|||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
success()
|
success();
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
const errorInfo = this.parseResponseOnError(error.response)
|
const errorInfo = this.parseResponseOnError(error.response);
|
||||||
reject(errorInfo)
|
reject(errorInfo);
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
return new Promise(handler)
|
return new Promise(handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
resetPassword(email: string): Promise<void> {
|
resetPassword(email: string): Promise<void> {
|
||||||
@ -406,15 +406,15 @@ export default class RestClient implements Client {
|
|||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
// All was ok, let's sent to success page ...;
|
// All was ok, let's sent to success page ...;
|
||||||
success()
|
success();
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
const response = error.response
|
const response = error.response;
|
||||||
const errorInfo = this.parseResponseOnError(response)
|
const errorInfo = this.parseResponseOnError(response);
|
||||||
reject(errorInfo)
|
reject(errorInfo);
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
return new Promise(handler)
|
return new Promise(handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
duplicateMap(id: number, basicInfo: BasicMapInfo): Promise<number> {
|
duplicateMap(id: number, basicInfo: BasicMapInfo): Promise<number> {
|
||||||
@ -424,16 +424,16 @@ export default class RestClient implements Client {
|
|||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
})
|
})
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
const mapId = response.headers.resourceid
|
const mapId = response.headers.resourceid;
|
||||||
success(mapId)
|
success(mapId);
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
const response = error.response
|
const response = error.response;
|
||||||
const errorInfo = this.parseResponseOnError(response)
|
const errorInfo = this.parseResponseOnError(response);
|
||||||
reject(errorInfo)
|
reject(errorInfo);
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
return new Promise(handler)
|
return new Promise(handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateStarred(id: number, starred: boolean): Promise<void> {
|
updateStarred(id: number, starred: boolean): Promise<void> {
|
||||||
@ -443,15 +443,15 @@ export default class RestClient implements Client {
|
|||||||
headers: { 'Content-Type': 'text/plain' },
|
headers: { 'Content-Type': 'text/plain' },
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
success()
|
success();
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
const response = error.response
|
const response = error.response;
|
||||||
const errorInfo = this.parseResponseOnError(response)
|
const errorInfo = this.parseResponseOnError(response);
|
||||||
reject(errorInfo)
|
reject(errorInfo);
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
return new Promise(handler)
|
return new Promise(handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
fetchLabels(): Promise<Label[]> {
|
fetchLabels(): Promise<Label[]> {
|
||||||
@ -464,7 +464,7 @@ export default class RestClient implements Client {
|
|||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
})
|
})
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
const data = response.data
|
const data = response.data;
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
const maps: Label[] = (data.labels as any[]).map((l) => {
|
const maps: Label[] = (data.labels as any[]).map((l) => {
|
||||||
return {
|
return {
|
||||||
@ -472,16 +472,16 @@ export default class RestClient implements Client {
|
|||||||
color: l.color,
|
color: l.color,
|
||||||
title: l.title,
|
title: l.title,
|
||||||
iconName: l.iconName,
|
iconName: l.iconName,
|
||||||
}
|
};
|
||||||
})
|
});
|
||||||
success(maps)
|
success(maps);
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
const errorInfo = this.parseResponseOnError(error.response)
|
const errorInfo = this.parseResponseOnError(error.response);
|
||||||
reject(errorInfo)
|
reject(errorInfo);
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
return new Promise(handler)
|
return new Promise(handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteLabel(id: number): Promise<void> {
|
deleteLabel(id: number): Promise<void> {
|
||||||
@ -489,60 +489,60 @@ export default class RestClient implements Client {
|
|||||||
axios
|
axios
|
||||||
.delete(`${this.baseUrl}/c/restful/label/${id}`)
|
.delete(`${this.baseUrl}/c/restful/label/${id}`)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
success()
|
success();
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
const errorInfo = this.parseResponseOnError(error.response)
|
const errorInfo = this.parseResponseOnError(error.response);
|
||||||
reject(errorInfo)
|
reject(errorInfo);
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
return new Promise(handler)
|
return new Promise(handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
private parseResponseOnError = (response: any): ErrorInfo => {
|
private parseResponseOnError = (response: any): ErrorInfo => {
|
||||||
let result: ErrorInfo | undefined
|
let result: ErrorInfo | undefined;
|
||||||
if (response) {
|
if (response) {
|
||||||
const status: number = response.status
|
const status: number = response.status;
|
||||||
const data = response.data
|
const data = response.data;
|
||||||
console.log(data)
|
console.log(data);
|
||||||
|
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case 401:
|
case 401:
|
||||||
case 302:
|
case 302:
|
||||||
this.sessionExpired()
|
this.sessionExpired();
|
||||||
result = {
|
result = {
|
||||||
msg: 'Your current session has expired. Please, sign in and try again.',
|
msg: 'Your current session has expired. Please, sign in and try again.',
|
||||||
}
|
};
|
||||||
break
|
break;
|
||||||
default:
|
default:
|
||||||
if (data) {
|
if (data) {
|
||||||
// Set global errors ...
|
// Set global errors ...
|
||||||
result = {}
|
result = {};
|
||||||
const globalErrors = data.globalErrors
|
const globalErrors = data.globalErrors;
|
||||||
if (globalErrors && globalErrors.length > 0) {
|
if (globalErrors && globalErrors.length > 0) {
|
||||||
result.msg = globalErrors[0]
|
result.msg = globalErrors[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set field errors ...
|
// Set field errors ...
|
||||||
if (data.fieldErrors && Object.keys(data.fieldErrors).length > 0) {
|
if (data.fieldErrors && Object.keys(data.fieldErrors).length > 0) {
|
||||||
result.fields = data.fieldErrors
|
result.fields = data.fieldErrors;
|
||||||
if (!result.msg) {
|
if (!result.msg) {
|
||||||
const key = Object.keys(data.fieldErrors)[0]
|
const key = Object.keys(data.fieldErrors)[0];
|
||||||
result.msg = data.fieldErrors[key]
|
result.msg = data.fieldErrors[key];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
result = { msg: response.statusText }
|
result = { msg: response.statusText };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Network related problem ...
|
// Network related problem ...
|
||||||
if (!result) {
|
if (!result) {
|
||||||
result = { msg: 'Unexpected error. Please, try latter' }
|
result = { msg: 'Unexpected error. Please, try latter' };
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result;
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,41 +1,41 @@
|
|||||||
import React, { useState, useEffect } from 'react'
|
import React, { useState, useEffect } from 'react';
|
||||||
import { FormattedMessage, useIntl } from 'react-intl'
|
import { FormattedMessage, useIntl } from 'react-intl';
|
||||||
import { useHistory } from 'react-router-dom'
|
import { useHistory } from 'react-router-dom';
|
||||||
import Client, { ErrorInfo } from '../../classes/client'
|
import Client, { ErrorInfo } from '../../classes/client';
|
||||||
|
|
||||||
import Header from '../layout/header'
|
import Header from '../layout/header';
|
||||||
import Footer from '../layout/footer'
|
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 '../../redux/clientSlice'
|
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';
|
||||||
|
|
||||||
import Typography from '@material-ui/core/Typography'
|
import Typography from '@material-ui/core/Typography';
|
||||||
|
|
||||||
const ForgotPassword = () => {
|
const ForgotPassword = () => {
|
||||||
const [email, setEmail] = useState<string>('')
|
const [email, setEmail] = useState<string>('');
|
||||||
const [error, setError] = useState<ErrorInfo>()
|
const [error, setError] = useState<ErrorInfo>();
|
||||||
const history = useHistory()
|
const history = useHistory();
|
||||||
const intl = useIntl()
|
const intl = useIntl();
|
||||||
|
|
||||||
const service: Client = useSelector(activeInstance)
|
const service: Client = useSelector(activeInstance);
|
||||||
const mutation = useMutation<void, ErrorInfo, string>(
|
const mutation = useMutation<void, ErrorInfo, string>(
|
||||||
(email: string) => service.resetPassword(email),
|
(email: string) => service.resetPassword(email),
|
||||||
{
|
{
|
||||||
onSuccess: () => history.push('/c/forgot-password-success'),
|
onSuccess: () => history.push('/c/forgot-password-success'),
|
||||||
onError: (error) => {
|
onError: (error) => {
|
||||||
setError(error)
|
setError(error);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
)
|
);
|
||||||
|
|
||||||
const handleOnSubmit = (event: React.FormEvent<HTMLFormElement>) => {
|
const handleOnSubmit = (event: React.FormEvent<HTMLFormElement>) => {
|
||||||
event.preventDefault()
|
event.preventDefault();
|
||||||
mutation.mutate(email)
|
mutation.mutate(email);
|
||||||
}
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FormContainer>
|
<FormContainer>
|
||||||
@ -70,13 +70,13 @@ const ForgotPassword = () => {
|
|||||||
/>
|
/>
|
||||||
</form>
|
</form>
|
||||||
</FormContainer>
|
</FormContainer>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
const ForgotPasswordPage = (): React.ReactElement => {
|
const ForgotPasswordPage = (): React.ReactElement => {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
document.title = 'Reset Password | WiseMapping'
|
document.title = 'Reset Password | WiseMapping';
|
||||||
})
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@ -84,7 +84,7 @@ const ForgotPasswordPage = (): React.ReactElement => {
|
|||||||
<ForgotPassword />
|
<ForgotPassword />
|
||||||
<Footer />
|
<Footer />
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
export { ForgotPasswordPage }
|
export { ForgotPasswordPage };
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
import React, { useEffect } from 'react'
|
import React, { useEffect } from 'react';
|
||||||
import { FormattedMessage } from 'react-intl'
|
import { FormattedMessage } from 'react-intl';
|
||||||
import FormContainer from '../layout/form-container'
|
import FormContainer from '../layout/form-container';
|
||||||
import Header from '../layout/header'
|
import Header from '../layout/header';
|
||||||
import Footer from '../layout/footer'
|
import Footer from '../layout/footer';
|
||||||
import { Link as RouterLink } from 'react-router-dom'
|
import { Link as RouterLink } from 'react-router-dom';
|
||||||
import Typography from '@material-ui/core/Typography'
|
import Typography from '@material-ui/core/Typography';
|
||||||
import Button from '@material-ui/core/Button'
|
import Button from '@material-ui/core/Button';
|
||||||
|
|
||||||
const ForgotPasswordSuccessPage = (): React.ReactElement => {
|
const ForgotPasswordSuccessPage = (): React.ReactElement => {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
document.title = 'Reset Password | WiseMapping'
|
document.title = 'Reset Password | WiseMapping';
|
||||||
})
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@ -43,7 +43,7 @@ const ForgotPasswordSuccessPage = (): React.ReactElement => {
|
|||||||
</FormContainer>
|
</FormContainer>
|
||||||
<Footer />
|
<Footer />
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
export default ForgotPasswordSuccessPage
|
export default ForgotPasswordSuccessPage;
|
||||||
|
@ -1,22 +1,22 @@
|
|||||||
import React from 'react'
|
import React from 'react';
|
||||||
import { ErrorInfo } from '../../../classes/client'
|
import { ErrorInfo } from '../../../classes/client';
|
||||||
import StyledAlert from './styled'
|
import StyledAlert from './styled';
|
||||||
|
|
||||||
type GlobalErrorProps = {
|
type GlobalErrorProps = {
|
||||||
error?: ErrorInfo
|
error?: ErrorInfo;
|
||||||
}
|
};
|
||||||
|
|
||||||
const GlobalError = (props: GlobalErrorProps): React.ReactElement | null => {
|
const GlobalError = (props: GlobalErrorProps): React.ReactElement | null => {
|
||||||
const error = props.error
|
const error = props.error;
|
||||||
const hasError = Boolean(error?.msg)
|
const hasError = Boolean(error?.msg);
|
||||||
const errorMsg = error?.msg
|
const errorMsg = error?.msg;
|
||||||
|
|
||||||
return hasError ? (
|
return hasError ? (
|
||||||
<StyledAlert severity="error" variant="filled" hidden={!hasError}>
|
<StyledAlert severity="error" variant="filled" hidden={!hasError}>
|
||||||
{' '}
|
{' '}
|
||||||
{errorMsg}
|
{errorMsg}
|
||||||
</StyledAlert>
|
</StyledAlert>
|
||||||
) : null
|
) : null;
|
||||||
}
|
};
|
||||||
|
|
||||||
export default GlobalError
|
export default GlobalError;
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import withStyles from '@material-ui/core/styles/withStyles'
|
import withStyles from '@material-ui/core/styles/withStyles';
|
||||||
import Alert from '@material-ui/lab/Alert'
|
import Alert from '@material-ui/lab/Alert';
|
||||||
|
|
||||||
export const StyledAlert = withStyles({
|
export const StyledAlert = withStyles({
|
||||||
root: {
|
root: {
|
||||||
padding: '10px 15px',
|
padding: '10px 15px',
|
||||||
margin: '5px 0px ',
|
margin: '5px 0px ',
|
||||||
},
|
},
|
||||||
})(Alert)
|
})(Alert);
|
||||||
|
|
||||||
export default StyledAlert
|
export default StyledAlert;
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
import TextField from '@material-ui/core/TextField'
|
import TextField from '@material-ui/core/TextField';
|
||||||
import React, { ChangeEvent } from 'react'
|
import React, { ChangeEvent } from 'react';
|
||||||
import { ErrorInfo } from '../../../classes/client'
|
import { ErrorInfo } from '../../../classes/client';
|
||||||
|
|
||||||
type InputProps = {
|
type InputProps = {
|
||||||
name: string
|
name: string;
|
||||||
error?: ErrorInfo
|
error?: ErrorInfo;
|
||||||
onChange?: (event: ChangeEvent<HTMLInputElement>) => void
|
onChange?: (event: ChangeEvent<HTMLInputElement>) => void;
|
||||||
label: string
|
label: string;
|
||||||
required?: boolean
|
required?: boolean;
|
||||||
type: string
|
type: string;
|
||||||
value?: string
|
value?: string;
|
||||||
autoComplete?: string
|
autoComplete?: string;
|
||||||
fullWidth?: boolean
|
fullWidth?: boolean;
|
||||||
disabled?: boolean
|
disabled?: boolean;
|
||||||
}
|
};
|
||||||
|
|
||||||
const Input = ({
|
const Input = ({
|
||||||
name,
|
name,
|
||||||
@ -27,7 +27,7 @@ const Input = ({
|
|||||||
fullWidth = true,
|
fullWidth = true,
|
||||||
disabled = false,
|
disabled = false,
|
||||||
}: InputProps): React.ReactElement => {
|
}: InputProps): React.ReactElement => {
|
||||||
const fieldError = error?.fields?.[name]
|
const fieldError = error?.fields?.[name];
|
||||||
return (
|
return (
|
||||||
<TextField
|
<TextField
|
||||||
name={name}
|
name={name}
|
||||||
@ -44,6 +44,6 @@ const Input = ({
|
|||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
autoComplete={autoComplete}
|
autoComplete={autoComplete}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
export default Input
|
export default Input;
|
||||||
|
@ -1,20 +1,20 @@
|
|||||||
import Button from '@material-ui/core/Button'
|
import Button from '@material-ui/core/Button';
|
||||||
import React, { useState } from 'react'
|
import React, { useState } from 'react';
|
||||||
import { useIntl } from 'react-intl'
|
import { useIntl } from 'react-intl';
|
||||||
|
|
||||||
type SubmitButton = {
|
type SubmitButton = {
|
||||||
value: string
|
value: string;
|
||||||
disabled?: boolean
|
disabled?: boolean;
|
||||||
}
|
};
|
||||||
const SubmitButton = (props: SubmitButton): React.ReactElement => {
|
const SubmitButton = (props: SubmitButton): React.ReactElement => {
|
||||||
const [disabled] = useState(props.disabled ? true : false)
|
const [disabled] = useState(props.disabled ? true : false);
|
||||||
const intl = useIntl()
|
const intl = useIntl();
|
||||||
|
|
||||||
let valueTxt = props.value
|
let valueTxt = props.value;
|
||||||
if (disabled) {
|
if (disabled) {
|
||||||
valueTxt = intl.formatMessage({ id: 'common.wait', defaultMessage: 'Please wait ...' })
|
valueTxt = intl.formatMessage({ id: 'common.wait', defaultMessage: 'Please wait ...' });
|
||||||
}
|
}
|
||||||
const [value] = useState(valueTxt)
|
const [value] = useState(valueTxt);
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
color="primary"
|
color="primary"
|
||||||
@ -33,7 +33,7 @@ const SubmitButton = (props: SubmitButton): React.ReactElement => {
|
|||||||
>
|
>
|
||||||
{value}
|
{value}
|
||||||
</Button>
|
</Button>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
export default SubmitButton
|
export default SubmitButton;
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import React from 'react'
|
import React from 'react';
|
||||||
import { FormattedMessage } from 'react-intl'
|
import { FormattedMessage } from 'react-intl';
|
||||||
import { StyledFooter } from './styled'
|
import { StyledFooter } from './styled';
|
||||||
|
|
||||||
// FIXME: use SVG loader
|
// FIXME: use SVG loader
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
const poweredByIcon = require('../../../images/pwrdby-white.svg')
|
const poweredByIcon = require('../../../images/pwrdby-white.svg');
|
||||||
|
|
||||||
const Footer = (): React.ReactElement => {
|
const Footer = (): React.ReactElement => {
|
||||||
return (
|
return (
|
||||||
@ -67,7 +67,7 @@ const Footer = (): React.ReactElement => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</StyledFooter>
|
</StyledFooter>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
export default Footer
|
export default Footer;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import styled from 'styled-components'
|
import styled from 'styled-components';
|
||||||
/* Footer */
|
/* Footer */
|
||||||
|
|
||||||
export const StyledFooter = styled.footer`
|
export const StyledFooter = styled.footer`
|
||||||
@ -41,4 +41,4 @@ export const StyledFooter = styled.footer`
|
|||||||
display: inline-block;
|
display: inline-block;
|
||||||
visibility: visible;
|
visibility: visible;
|
||||||
}
|
}
|
||||||
`
|
`;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import Container from '@material-ui/core/Container'
|
import Container from '@material-ui/core/Container';
|
||||||
import withStyles from '@material-ui/core/styles/withStyles'
|
import withStyles from '@material-ui/core/styles/withStyles';
|
||||||
|
|
||||||
const FormContainer = withStyles({
|
const FormContainer = withStyles({
|
||||||
root: {
|
root: {
|
||||||
@ -7,6 +7,6 @@ const FormContainer = withStyles({
|
|||||||
maxWidth: '380px',
|
maxWidth: '380px',
|
||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
},
|
},
|
||||||
})(Container)
|
})(Container);
|
||||||
|
|
||||||
export default FormContainer
|
export default FormContainer;
|
||||||
|
@ -1,20 +1,20 @@
|
|||||||
import { StyledNav, StyledDiv, Logo } from './styled'
|
import { StyledNav, StyledDiv, Logo } from './styled';
|
||||||
|
|
||||||
import React from 'react'
|
import React from 'react';
|
||||||
import { FormattedMessage } from 'react-intl'
|
import { FormattedMessage } from 'react-intl';
|
||||||
import { Link } from 'react-router-dom'
|
import { Link } from 'react-router-dom';
|
||||||
import Button from '@material-ui/core/Button'
|
import Button from '@material-ui/core/Button';
|
||||||
|
|
||||||
import logo from '../../../images/logo-small.svg'
|
import logo from '../../../images/logo-small.svg';
|
||||||
|
|
||||||
interface HeaderProps {
|
interface HeaderProps {
|
||||||
type: 'only-signup' | 'only-signin' | 'none'
|
type: 'only-signup' | 'only-signin' | 'none';
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Header = ({ type }: HeaderProps): React.ReactElement => {
|
export const Header = ({ type }: HeaderProps): React.ReactElement => {
|
||||||
let signUpButton
|
let signUpButton;
|
||||||
let text
|
let text;
|
||||||
let signInButton
|
let signInButton;
|
||||||
if (type === 'only-signup') {
|
if (type === 'only-signup') {
|
||||||
text = (
|
text = (
|
||||||
<span className="header-area-content-span">
|
<span className="header-area-content-span">
|
||||||
@ -25,8 +25,8 @@ export const Header = ({ type }: HeaderProps): React.ReactElement => {
|
|||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
)
|
);
|
||||||
signUpButton = <SignUpButton className="header-area-right2" />
|
signUpButton = <SignUpButton className="header-area-right2" />;
|
||||||
} else if (type === 'only-signin') {
|
} else if (type === 'only-signin') {
|
||||||
text = (
|
text = (
|
||||||
<span className="header-area-content-span">
|
<span className="header-area-content-span">
|
||||||
@ -37,14 +37,14 @@ export const Header = ({ type }: HeaderProps): React.ReactElement => {
|
|||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
)
|
);
|
||||||
signUpButton = <SignInButton className="header-area-right2" />
|
signUpButton = <SignInButton className="header-area-right2" />;
|
||||||
} else if (type === 'none') {
|
} else if (type === 'none') {
|
||||||
text = ''
|
text = '';
|
||||||
signUpButton = ''
|
signUpButton = '';
|
||||||
} else {
|
} else {
|
||||||
signUpButton = <SignUpButton className="header-area-right2" />
|
signUpButton = <SignUpButton className="header-area-right2" />;
|
||||||
signInButton = <SignInButton className="header-area-right2" />
|
signInButton = <SignInButton className="header-area-right2" />;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -60,11 +60,11 @@ export const Header = ({ type }: HeaderProps): React.ReactElement => {
|
|||||||
{signInButton}
|
{signInButton}
|
||||||
</StyledDiv>
|
</StyledDiv>
|
||||||
</StyledNav>
|
</StyledNav>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
interface ButtonProps {
|
interface ButtonProps {
|
||||||
className?: string
|
className?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const SignInButton = (props: ButtonProps): React.ReactElement => {
|
export const SignInButton = (props: ButtonProps): React.ReactElement => {
|
||||||
@ -74,8 +74,8 @@ export const SignInButton = (props: ButtonProps): React.ReactElement => {
|
|||||||
<FormattedMessage id="login.signin" defaultMessage="Sign In" />
|
<FormattedMessage id="login.signin" defaultMessage="Sign In" />
|
||||||
</Button>
|
</Button>
|
||||||
</span>
|
</span>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
const SignUpButton = (props: ButtonProps): React.ReactElement => {
|
const SignUpButton = (props: ButtonProps): React.ReactElement => {
|
||||||
return (
|
return (
|
||||||
@ -90,7 +90,7 @@ const SignUpButton = (props: ButtonProps): React.ReactElement => {
|
|||||||
<FormattedMessage id="login.signup" defaultMessage="Sign Up" />
|
<FormattedMessage id="login.signup" defaultMessage="Sign Up" />
|
||||||
</Button>
|
</Button>
|
||||||
</span>
|
</span>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
export default Header
|
export default Header;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import styled from 'styled-components'
|
import styled from 'styled-components';
|
||||||
|
|
||||||
export const StyledNav = styled.nav`
|
export const StyledNav = styled.nav`
|
||||||
height: 90px;
|
height: 90px;
|
||||||
@ -50,7 +50,7 @@ export const StyledNav = styled.nav`
|
|||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
}
|
}
|
||||||
`
|
`;
|
||||||
|
|
||||||
export const StyledDiv = styled.nav`
|
export const StyledDiv = styled.nav`
|
||||||
background: white;
|
background: white;
|
||||||
@ -64,7 +64,7 @@ export const StyledDiv = styled.nav`
|
|||||||
display: grid;
|
display: grid;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
grid-template-columns: 150px 1fr 130px 160px 50px;
|
grid-template-columns: 150px 1fr 130px 160px 50px;
|
||||||
`
|
`;
|
||||||
|
|
||||||
export const Logo = styled.span`
|
export const Logo = styled.span`
|
||||||
grid-column-start: 1;
|
grid-column-start: 1;
|
||||||
@ -74,4 +74,4 @@ export const Logo = styled.span`
|
|||||||
.header-logo a {
|
.header-logo a {
|
||||||
padding: 0px;
|
padding: 0px;
|
||||||
}
|
}
|
||||||
`
|
`;
|
||||||
|
@ -1,22 +1,22 @@
|
|||||||
import React, { useEffect } from 'react'
|
import React, { useEffect } from 'react';
|
||||||
import { FormattedMessage, useIntl } from 'react-intl'
|
import { FormattedMessage, useIntl } from 'react-intl';
|
||||||
import { Link as RouterLink } from 'react-router-dom'
|
import { Link as RouterLink } from 'react-router-dom';
|
||||||
import Header from '../layout/header'
|
import Header from '../layout/header';
|
||||||
import Footer from '../layout/footer'
|
import Footer from '../layout/footer';
|
||||||
import SubmitButton from '../form/submit-button'
|
import SubmitButton from '../form/submit-button';
|
||||||
import Input from '../form/input'
|
import Input from '../form/input';
|
||||||
import GlobalError from '../form/global-error'
|
import GlobalError from '../form/global-error';
|
||||||
import FormContainer from '../layout/form-container'
|
import FormContainer from '../layout/form-container';
|
||||||
import Typography from '@material-ui/core/Typography'
|
import Typography from '@material-ui/core/Typography';
|
||||||
import FormControl from '@material-ui/core/FormControl'
|
import FormControl from '@material-ui/core/FormControl';
|
||||||
import Link from '@material-ui/core/Link'
|
import Link from '@material-ui/core/Link';
|
||||||
|
|
||||||
type ConfigStatusProps = {
|
type ConfigStatusProps = {
|
||||||
enabled?: boolean
|
enabled?: boolean;
|
||||||
}
|
};
|
||||||
|
|
||||||
const ConfigStatusMessage = ({ enabled = false }: ConfigStatusProps): React.ReactElement => {
|
const ConfigStatusMessage = ({ enabled = false }: ConfigStatusProps): React.ReactElement => {
|
||||||
let result
|
let result;
|
||||||
if (enabled === true) {
|
if (enabled === true) {
|
||||||
result = (
|
result = (
|
||||||
<div className="db-warn-msg">
|
<div className="db-warn-msg">
|
||||||
@ -32,18 +32,18 @@ const ConfigStatusMessage = ({ enabled = false }: ConfigStatusProps): React.Reac
|
|||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
|
||||||
return result || null
|
|
||||||
}
|
}
|
||||||
|
return result || null;
|
||||||
|
};
|
||||||
|
|
||||||
const LoginError = () => {
|
const LoginError = () => {
|
||||||
// @Todo: This must be reviewed to be based on navigation state.
|
// @Todo: This must be reviewed to be based on navigation state.
|
||||||
// Login error example: http://localhost:8080/c/login?login.error=2
|
// Login error example: http://localhost:8080/c/login?login.error=2
|
||||||
const errorCode = new URLSearchParams(window.location.search).get('login_error')
|
const errorCode = new URLSearchParams(window.location.search).get('login_error');
|
||||||
const intl = useIntl()
|
const intl = useIntl();
|
||||||
|
|
||||||
let msg: null | string = null
|
let msg: null | string = null;
|
||||||
if (errorCode) {
|
if (errorCode) {
|
||||||
switch (errorCode) {
|
switch (errorCode) {
|
||||||
case '3':
|
case '3':
|
||||||
@ -51,24 +51,24 @@ const LoginError = () => {
|
|||||||
id: 'login.userinactive',
|
id: 'login.userinactive',
|
||||||
defaultMessage:
|
defaultMessage:
|
||||||
"Sorry, your account has not been activated yet. You'll receive a notification email when it becomes active. Stay tuned!.",
|
"Sorry, your account has not been activated yet. You'll receive a notification email when it becomes active. Stay tuned!.",
|
||||||
})
|
});
|
||||||
break
|
break;
|
||||||
default:
|
default:
|
||||||
msg = intl.formatMessage({
|
msg = intl.formatMessage({
|
||||||
id: 'login.error',
|
id: 'login.error',
|
||||||
defaultMessage: 'The email address or password you entered is not valid.',
|
defaultMessage: 'The email address or password you entered is not valid.',
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return msg ? <GlobalError error={{ msg: msg }} /> : null
|
return msg ? <GlobalError error={{ msg: msg }} /> : null;
|
||||||
}
|
};
|
||||||
|
|
||||||
const LoginPage = (): React.ReactElement => {
|
const LoginPage = (): React.ReactElement => {
|
||||||
const intl = useIntl()
|
const intl = useIntl();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
document.title = 'Login | WiseMapping'
|
document.title = 'Login | WiseMapping';
|
||||||
})
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@ -133,7 +133,7 @@ const LoginPage = (): React.ReactElement => {
|
|||||||
|
|
||||||
<Footer />
|
<Footer />
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
export default LoginPage
|
export default LoginPage;
|
||||||
|
@ -1,105 +1,105 @@
|
|||||||
import React, { useEffect } from 'react'
|
import React, { useEffect } from 'react';
|
||||||
import { FormattedMessage, useIntl } from 'react-intl'
|
import { FormattedMessage, useIntl } from 'react-intl';
|
||||||
import { useMutation, useQueryClient } from 'react-query'
|
import { useMutation, useQueryClient } from 'react-query';
|
||||||
import Client, { ErrorInfo } from '../../../../classes/client'
|
import Client, { ErrorInfo } from '../../../../classes/client';
|
||||||
import Input from '../../../form/input'
|
import Input from '../../../form/input';
|
||||||
import BaseDialog from '../../action-dispatcher/base-dialog'
|
import BaseDialog from '../../action-dispatcher/base-dialog';
|
||||||
import { useSelector } from 'react-redux'
|
import { useSelector } from 'react-redux';
|
||||||
import { activeInstance, fetchAccount } from '../../../../redux/clientSlice'
|
import { activeInstance, fetchAccount } from '../../../../redux/clientSlice';
|
||||||
|
|
||||||
import Alert from '@material-ui/lab/Alert'
|
import Alert from '@material-ui/lab/Alert';
|
||||||
import FormControl from '@material-ui/core/FormControl'
|
import FormControl from '@material-ui/core/FormControl';
|
||||||
import FormControlLabel from '@material-ui/core/FormControlLabel'
|
import FormControlLabel from '@material-ui/core/FormControlLabel';
|
||||||
import FormGroup from '@material-ui/core/FormGroup'
|
import FormGroup from '@material-ui/core/FormGroup';
|
||||||
import Switch from '@material-ui/core/Switch'
|
import Switch from '@material-ui/core/Switch';
|
||||||
|
|
||||||
type AccountInfoDialogProps = {
|
type AccountInfoDialogProps = {
|
||||||
onClose: () => void
|
onClose: () => void;
|
||||||
}
|
};
|
||||||
|
|
||||||
type AccountInfoModel = {
|
type AccountInfoModel = {
|
||||||
email: string
|
email: string;
|
||||||
firstname: string
|
firstname: string;
|
||||||
lastname: string
|
lastname: string;
|
||||||
}
|
};
|
||||||
|
|
||||||
const defaultModel: AccountInfoModel = { firstname: '', lastname: '', email: '' }
|
const defaultModel: AccountInfoModel = { firstname: '', lastname: '', email: '' };
|
||||||
const AccountInfoDialog = ({ onClose }: AccountInfoDialogProps): React.ReactElement => {
|
const AccountInfoDialog = ({ onClose }: AccountInfoDialogProps): React.ReactElement => {
|
||||||
const client: Client = useSelector(activeInstance)
|
const client: Client = useSelector(activeInstance);
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient();
|
||||||
const [remove, setRemove] = React.useState<boolean>(false)
|
const [remove, setRemove] = React.useState<boolean>(false);
|
||||||
|
|
||||||
const [model, setModel] = React.useState<AccountInfoModel>(defaultModel)
|
const [model, setModel] = React.useState<AccountInfoModel>(defaultModel);
|
||||||
const [error, setError] = React.useState<ErrorInfo>()
|
const [error, setError] = React.useState<ErrorInfo>();
|
||||||
const intl = useIntl()
|
const intl = useIntl();
|
||||||
|
|
||||||
const mutationChangeName = useMutation<void, ErrorInfo, AccountInfoModel>(
|
const mutationChangeName = useMutation<void, ErrorInfo, AccountInfoModel>(
|
||||||
(model: AccountInfoModel) => {
|
(model: AccountInfoModel) => {
|
||||||
return client.updateAccountInfo(model.firstname, model.lastname)
|
return client.updateAccountInfo(model.firstname, model.lastname);
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
queryClient.invalidateQueries('account')
|
queryClient.invalidateQueries('account');
|
||||||
onClose()
|
onClose();
|
||||||
},
|
},
|
||||||
onError: (error) => {
|
onError: (error) => {
|
||||||
setError(error)
|
setError(error);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
)
|
);
|
||||||
|
|
||||||
const mutationRemove = useMutation<void, ErrorInfo, void>(
|
const mutationRemove = useMutation<void, ErrorInfo, void>(
|
||||||
() => {
|
() => {
|
||||||
return client.deleteAccount()
|
return client.deleteAccount();
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
window.location.href = '/c/logout'
|
window.location.href = '/c/logout';
|
||||||
onClose()
|
onClose();
|
||||||
},
|
},
|
||||||
onError: (error) => {
|
onError: (error) => {
|
||||||
setError(error)
|
setError(error);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
)
|
);
|
||||||
|
|
||||||
const account = fetchAccount()
|
const account = fetchAccount();
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (account) {
|
if (account) {
|
||||||
setModel({
|
setModel({
|
||||||
email: account?.email,
|
email: account?.email,
|
||||||
lastname: account?.lastname,
|
lastname: account?.lastname,
|
||||||
firstname: account?.firstname,
|
firstname: account?.firstname,
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}, [account?.email])
|
}, [account?.email]);
|
||||||
|
|
||||||
const handleOnClose = (): void => {
|
const handleOnClose = (): void => {
|
||||||
onClose()
|
onClose();
|
||||||
setModel(defaultModel)
|
setModel(defaultModel);
|
||||||
setError(undefined)
|
setError(undefined);
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleOnSubmit = (event: React.FormEvent<HTMLFormElement>): void => {
|
const handleOnSubmit = (event: React.FormEvent<HTMLFormElement>): void => {
|
||||||
event.preventDefault()
|
event.preventDefault();
|
||||||
if (remove) {
|
if (remove) {
|
||||||
mutationRemove.mutate()
|
mutationRemove.mutate();
|
||||||
} else {
|
} else {
|
||||||
mutationChangeName.mutate(model)
|
mutationChangeName.mutate(model);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const handleOnChange = (event: React.ChangeEvent<HTMLInputElement>): void => {
|
const handleOnChange = (event: React.ChangeEvent<HTMLInputElement>): void => {
|
||||||
event.preventDefault()
|
event.preventDefault();
|
||||||
|
|
||||||
const name = event.target.name
|
const name = event.target.name;
|
||||||
const value = event.target.value
|
const value = event.target.value;
|
||||||
setModel({ ...model, [name as keyof AccountInfoModel]: value })
|
setModel({ ...model, [name as keyof AccountInfoModel]: value });
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleOnRemoveChange = (event) => {
|
const handleOnRemoveChange = (event) => {
|
||||||
setRemove(event.target.checked)
|
setRemove(event.target.checked);
|
||||||
}
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<BaseDialog
|
<BaseDialog
|
||||||
@ -173,6 +173,6 @@ const AccountInfoDialog = ({ onClose }: AccountInfoDialogProps): React.ReactElem
|
|||||||
</FormGroup>
|
</FormGroup>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
</BaseDialog>
|
</BaseDialog>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
export default AccountInfoDialog
|
export default AccountInfoDialog;
|
||||||
|
@ -1,51 +1,51 @@
|
|||||||
import FormControl from '@material-ui/core/FormControl'
|
import FormControl from '@material-ui/core/FormControl';
|
||||||
import React from 'react'
|
import React from 'react';
|
||||||
import { useIntl } from 'react-intl'
|
import { useIntl } from 'react-intl';
|
||||||
import { useMutation } from 'react-query'
|
import { useMutation } from 'react-query';
|
||||||
import Client, { ErrorInfo } from '../../../../classes/client'
|
import Client, { ErrorInfo } from '../../../../classes/client';
|
||||||
import Input from '../../../form/input'
|
import Input from '../../../form/input';
|
||||||
import BaseDialog from '../../action-dispatcher/base-dialog'
|
import BaseDialog from '../../action-dispatcher/base-dialog';
|
||||||
import { useSelector } from 'react-redux'
|
import { useSelector } from 'react-redux';
|
||||||
import { activeInstance } from '../../../../redux/clientSlice'
|
import { activeInstance } from '../../../../redux/clientSlice';
|
||||||
|
|
||||||
type ChangePasswordDialogProps = {
|
type ChangePasswordDialogProps = {
|
||||||
onClose: () => void
|
onClose: () => void;
|
||||||
}
|
};
|
||||||
|
|
||||||
type ChangePasswordModel = {
|
type ChangePasswordModel = {
|
||||||
password: string
|
password: string;
|
||||||
retryPassword: string
|
retryPassword: string;
|
||||||
}
|
};
|
||||||
|
|
||||||
const defaultModel: ChangePasswordModel = { password: '', retryPassword: '' }
|
const defaultModel: ChangePasswordModel = { password: '', retryPassword: '' };
|
||||||
const ChangePasswordDialog = ({ onClose }: ChangePasswordDialogProps): React.ReactElement => {
|
const ChangePasswordDialog = ({ onClose }: ChangePasswordDialogProps): React.ReactElement => {
|
||||||
const client: Client = useSelector(activeInstance)
|
const client: Client = useSelector(activeInstance);
|
||||||
const [model, setModel] = React.useState<ChangePasswordModel>(defaultModel)
|
const [model, setModel] = React.useState<ChangePasswordModel>(defaultModel);
|
||||||
const [error, setError] = React.useState<ErrorInfo>()
|
const [error, setError] = React.useState<ErrorInfo>();
|
||||||
const intl = useIntl()
|
const intl = useIntl();
|
||||||
|
|
||||||
const mutation = useMutation<void, ErrorInfo, ChangePasswordModel>(
|
const mutation = useMutation<void, ErrorInfo, ChangePasswordModel>(
|
||||||
(model: ChangePasswordModel) => {
|
(model: ChangePasswordModel) => {
|
||||||
return client.updateAccountPassword(model.password)
|
return client.updateAccountPassword(model.password);
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
onClose()
|
onClose();
|
||||||
},
|
},
|
||||||
onError: (error) => {
|
onError: (error) => {
|
||||||
setError(error)
|
setError(error);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
)
|
);
|
||||||
|
|
||||||
const handleOnClose = (): void => {
|
const handleOnClose = (): void => {
|
||||||
onClose()
|
onClose();
|
||||||
setModel(defaultModel)
|
setModel(defaultModel);
|
||||||
setError(undefined)
|
setError(undefined);
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleOnSubmit = (event: React.FormEvent<HTMLFormElement>): void => {
|
const handleOnSubmit = (event: React.FormEvent<HTMLFormElement>): void => {
|
||||||
event.preventDefault()
|
event.preventDefault();
|
||||||
|
|
||||||
// Check password are equal ...
|
// Check password are equal ...
|
||||||
if (model.password != model.retryPassword) {
|
if (model.password != model.retryPassword) {
|
||||||
@ -54,20 +54,20 @@ const ChangePasswordDialog = ({ onClose }: ChangePasswordDialogProps): React.Rea
|
|||||||
id: 'changepwd.password-match',
|
id: 'changepwd.password-match',
|
||||||
defaultMessage: 'Password do not match. Please, try again.',
|
defaultMessage: 'Password do not match. Please, try again.',
|
||||||
}),
|
}),
|
||||||
})
|
});
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
mutation.mutate(model)
|
mutation.mutate(model);
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleOnChange = (event: React.ChangeEvent<HTMLInputElement>): void => {
|
const handleOnChange = (event: React.ChangeEvent<HTMLInputElement>): void => {
|
||||||
event.preventDefault()
|
event.preventDefault();
|
||||||
|
|
||||||
const name = event.target.name
|
const name = event.target.name;
|
||||||
const value = event.target.value
|
const value = event.target.value;
|
||||||
setModel({ ...model, [name as keyof ChangePasswordModel]: value })
|
setModel({ ...model, [name as keyof ChangePasswordModel]: value });
|
||||||
}
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<BaseDialog
|
<BaseDialog
|
||||||
@ -111,6 +111,6 @@ const ChangePasswordDialog = ({ onClose }: ChangePasswordDialogProps): React.Rea
|
|||||||
/>
|
/>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
</BaseDialog>
|
</BaseDialog>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
export default ChangePasswordDialog
|
export default ChangePasswordDialog;
|
||||||
|
@ -1,34 +1,34 @@
|
|||||||
import IconButton from '@material-ui/core/IconButton'
|
import IconButton from '@material-ui/core/IconButton';
|
||||||
import ListItemIcon from '@material-ui/core/ListItemIcon'
|
import ListItemIcon from '@material-ui/core/ListItemIcon';
|
||||||
import Menu from '@material-ui/core/Menu'
|
import Menu from '@material-ui/core/Menu';
|
||||||
import MenuItem from '@material-ui/core/MenuItem'
|
import MenuItem from '@material-ui/core/MenuItem';
|
||||||
import Tooltip from '@material-ui/core/Tooltip'
|
import Tooltip from '@material-ui/core/Tooltip';
|
||||||
import SettingsApplicationsOutlined from '@material-ui/icons/SettingsApplicationsOutlined'
|
import SettingsApplicationsOutlined from '@material-ui/icons/SettingsApplicationsOutlined';
|
||||||
import AccountCircle from '@material-ui/icons/AccountCircle'
|
import AccountCircle from '@material-ui/icons/AccountCircle';
|
||||||
import React from 'react'
|
import React from 'react';
|
||||||
import { FormattedMessage } from 'react-intl'
|
import { FormattedMessage } from 'react-intl';
|
||||||
import { fetchAccount } from '../../../redux/clientSlice'
|
import { fetchAccount } from '../../../redux/clientSlice';
|
||||||
import AccountInfoDialog from './account-info-dialog'
|
import AccountInfoDialog from './account-info-dialog';
|
||||||
import ChangePasswordDialog from './change-password-dialog'
|
import ChangePasswordDialog from './change-password-dialog';
|
||||||
import LockOpenOutlined from '@material-ui/icons/LockOpenOutlined'
|
import LockOpenOutlined from '@material-ui/icons/LockOpenOutlined';
|
||||||
import Link from '@material-ui/core/Link'
|
import Link from '@material-ui/core/Link';
|
||||||
import ExitToAppOutlined from '@material-ui/icons/ExitToAppOutlined'
|
import ExitToAppOutlined from '@material-ui/icons/ExitToAppOutlined';
|
||||||
|
|
||||||
type ActionType = 'change-password' | 'account-info' | undefined
|
type ActionType = 'change-password' | 'account-info' | undefined;
|
||||||
const AccountMenu = (): React.ReactElement => {
|
const AccountMenu = (): React.ReactElement => {
|
||||||
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null)
|
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
|
||||||
const open = Boolean(anchorEl)
|
const open = Boolean(anchorEl);
|
||||||
const [action, setAction] = React.useState<ActionType>(undefined)
|
const [action, setAction] = React.useState<ActionType>(undefined);
|
||||||
|
|
||||||
const handleMenu = (event: React.MouseEvent<HTMLElement>) => {
|
const handleMenu = (event: React.MouseEvent<HTMLElement>) => {
|
||||||
setAnchorEl(event.currentTarget)
|
setAnchorEl(event.currentTarget);
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
setAnchorEl(null)
|
setAnchorEl(null);
|
||||||
}
|
};
|
||||||
|
|
||||||
const account = fetchAccount()
|
const account = fetchAccount();
|
||||||
return (
|
return (
|
||||||
<span>
|
<span>
|
||||||
<Tooltip
|
<Tooltip
|
||||||
@ -57,7 +57,7 @@ const AccountMenu = (): React.ReactElement => {
|
|||||||
>
|
>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
handleClose(), setAction('account-info')
|
handleClose(), setAction('account-info');
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
@ -68,7 +68,7 @@ const AccountMenu = (): React.ReactElement => {
|
|||||||
|
|
||||||
<MenuItem
|
<MenuItem
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
handleClose(), setAction('change-password')
|
handleClose(), setAction('change-password');
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
@ -91,7 +91,7 @@ const AccountMenu = (): React.ReactElement => {
|
|||||||
)}
|
)}
|
||||||
{action == 'account-info' && <AccountInfoDialog onClose={() => setAction(undefined)} />}
|
{action == 'account-info' && <AccountInfoDialog onClose={() => setAction(undefined)} />}
|
||||||
</span>
|
</span>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
export default AccountMenu
|
export default AccountMenu;
|
||||||
|
@ -1,21 +1,21 @@
|
|||||||
import React from 'react'
|
import React from 'react';
|
||||||
import DescriptionOutlinedIcon from '@material-ui/icons/DescriptionOutlined'
|
import DescriptionOutlinedIcon from '@material-ui/icons/DescriptionOutlined';
|
||||||
import FileCopyOutlinedIcon from '@material-ui/icons/FileCopyOutlined'
|
import FileCopyOutlinedIcon from '@material-ui/icons/FileCopyOutlined';
|
||||||
import DeleteOutlinedIcon from '@material-ui/icons/DeleteOutlined'
|
import DeleteOutlinedIcon from '@material-ui/icons/DeleteOutlined';
|
||||||
import CloudDownloadOutlinedIcon from '@material-ui/icons/CloudDownloadOutlined'
|
import CloudDownloadOutlinedIcon from '@material-ui/icons/CloudDownloadOutlined';
|
||||||
import InfoOutlinedIcon from '@material-ui/icons/InfoOutlined'
|
import InfoOutlinedIcon from '@material-ui/icons/InfoOutlined';
|
||||||
import EditOutlinedIcon from '@material-ui/icons/EditOutlined'
|
import EditOutlinedIcon from '@material-ui/icons/EditOutlined';
|
||||||
import PublicOutlinedIcon from '@material-ui/icons/PublicOutlined'
|
import PublicOutlinedIcon from '@material-ui/icons/PublicOutlined';
|
||||||
import PrintOutlinedIcon from '@material-ui/icons/PrintOutlined'
|
import PrintOutlinedIcon from '@material-ui/icons/PrintOutlined';
|
||||||
import ShareOutlinedIcon from '@material-ui/icons/ShareOutlined'
|
import ShareOutlinedIcon from '@material-ui/icons/ShareOutlined';
|
||||||
import LabelOutlined from '@material-ui/icons/LabelOutlined'
|
import LabelOutlined from '@material-ui/icons/LabelOutlined';
|
||||||
|
|
||||||
import { FormattedMessage } from 'react-intl'
|
import { FormattedMessage } from 'react-intl';
|
||||||
import { fetchMapById } from '../../../redux/clientSlice'
|
import { fetchMapById } from '../../../redux/clientSlice';
|
||||||
import Menu from '@material-ui/core/Menu'
|
import Menu from '@material-ui/core/Menu';
|
||||||
import MenuItem from '@material-ui/core/MenuItem'
|
import MenuItem from '@material-ui/core/MenuItem';
|
||||||
import ListItemIcon from '@material-ui/core/ListItemIcon'
|
import ListItemIcon from '@material-ui/core/ListItemIcon';
|
||||||
import Divider from '@material-ui/core/Divider'
|
import Divider from '@material-ui/core/Divider';
|
||||||
export type ActionType =
|
export type ActionType =
|
||||||
| 'open'
|
| 'open'
|
||||||
| 'share'
|
| 'share'
|
||||||
@ -31,27 +31,27 @@ export type ActionType =
|
|||||||
| 'info'
|
| 'info'
|
||||||
| 'publish'
|
| 'publish'
|
||||||
| 'history'
|
| 'history'
|
||||||
| undefined
|
| undefined;
|
||||||
|
|
||||||
interface ActionProps {
|
interface ActionProps {
|
||||||
onClose: (action: ActionType) => void
|
onClose: (action: ActionType) => void;
|
||||||
anchor?: HTMLElement
|
anchor?: HTMLElement;
|
||||||
mapId?: number
|
mapId?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ActionChooser = (props: ActionProps): React.ReactElement => {
|
const ActionChooser = (props: ActionProps): React.ReactElement => {
|
||||||
const { anchor, onClose, mapId } = props
|
const { anchor, onClose, mapId } = props;
|
||||||
|
|
||||||
const handleOnClose = (
|
const handleOnClose = (
|
||||||
action: ActionType
|
action: ActionType
|
||||||
): ((event: React.MouseEvent<HTMLLIElement>) => void) => {
|
): ((event: React.MouseEvent<HTMLLIElement>) => void) => {
|
||||||
return (event): void => {
|
return (event): void => {
|
||||||
event.stopPropagation()
|
event.stopPropagation();
|
||||||
onClose(action)
|
onClose(action);
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
const role = mapId ? fetchMapById(mapId)?.map?.role : undefined
|
const role = mapId ? fetchMapById(mapId)?.map?.role : undefined;
|
||||||
return (
|
return (
|
||||||
<Menu
|
<Menu
|
||||||
anchorEl={anchor}
|
anchorEl={anchor}
|
||||||
@ -149,7 +149,7 @@ const ActionChooser = (props: ActionProps): React.ReactElement => {
|
|||||||
</MenuItem>
|
</MenuItem>
|
||||||
)}
|
)}
|
||||||
</Menu>
|
</Menu>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
export default ActionChooser
|
export default ActionChooser;
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import MenuItem from '@material-ui/core/MenuItem'
|
import MenuItem from '@material-ui/core/MenuItem';
|
||||||
import withStyles from '@material-ui/core/styles/withStyles'
|
import withStyles from '@material-ui/core/styles/withStyles';
|
||||||
|
|
||||||
export const StyledMenuItem = withStyles({
|
export const StyledMenuItem = withStyles({
|
||||||
root: {
|
root: {
|
||||||
width: '300px',
|
width: '300px',
|
||||||
},
|
},
|
||||||
})(MenuItem)
|
})(MenuItem);
|
||||||
|
@ -1,40 +1,40 @@
|
|||||||
import React from 'react'
|
import React from 'react';
|
||||||
import { FormattedMessage } from 'react-intl'
|
import { FormattedMessage } from 'react-intl';
|
||||||
import { ErrorInfo } from '../../../../classes/client'
|
import { ErrorInfo } from '../../../../classes/client';
|
||||||
import { StyledDialog, StyledDialogActions, StyledDialogContent, StyledDialogTitle } from './style'
|
import { StyledDialog, StyledDialogActions, StyledDialogContent, StyledDialogTitle } from './style';
|
||||||
import GlobalError from '../../../form/global-error'
|
import GlobalError from '../../../form/global-error';
|
||||||
import DialogContentText from '@material-ui/core/DialogContentText'
|
import DialogContentText from '@material-ui/core/DialogContentText';
|
||||||
import Button from '@material-ui/core/Button'
|
import Button from '@material-ui/core/Button';
|
||||||
import { PaperProps } from '@material-ui/core/Paper'
|
import { PaperProps } from '@material-ui/core/Paper';
|
||||||
|
|
||||||
export type DialogProps = {
|
export type DialogProps = {
|
||||||
onClose: () => void
|
onClose: () => void;
|
||||||
onSubmit?: (event: React.FormEvent<HTMLFormElement>) => void
|
onSubmit?: (event: React.FormEvent<HTMLFormElement>) => void;
|
||||||
children: unknown
|
children: unknown;
|
||||||
error?: ErrorInfo
|
error?: ErrorInfo;
|
||||||
|
|
||||||
title: string
|
title: string;
|
||||||
description?: string
|
description?: string;
|
||||||
|
|
||||||
submitButton?: string
|
submitButton?: string;
|
||||||
actionUrl?: string
|
actionUrl?: string;
|
||||||
maxWidth?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | false
|
maxWidth?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | false;
|
||||||
PaperProps?: Partial<PaperProps>
|
PaperProps?: Partial<PaperProps>;
|
||||||
}
|
};
|
||||||
|
|
||||||
const BaseDialog = (props: DialogProps): React.ReactElement => {
|
const BaseDialog = (props: DialogProps): React.ReactElement => {
|
||||||
const { onClose, onSubmit, maxWidth = 'sm', PaperProps } = props
|
const { onClose, onSubmit, maxWidth = 'sm', PaperProps } = props;
|
||||||
|
|
||||||
const handleOnSubmit = (e: React.FormEvent<HTMLFormElement>) => {
|
const handleOnSubmit = (e: React.FormEvent<HTMLFormElement>) => {
|
||||||
e.preventDefault()
|
e.preventDefault();
|
||||||
if (onSubmit) {
|
if (onSubmit) {
|
||||||
onSubmit(e)
|
onSubmit(e);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const description = props.description ? (
|
const description = props.description ? (
|
||||||
<DialogContentText>{props.description}</DialogContentText>
|
<DialogContentText>{props.description}</DialogContentText>
|
||||||
) : null
|
) : null;
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<StyledDialog
|
<StyledDialog
|
||||||
@ -79,7 +79,7 @@ const BaseDialog = (props: DialogProps): React.ReactElement => {
|
|||||||
</form>
|
</form>
|
||||||
</StyledDialog>
|
</StyledDialog>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
export default BaseDialog
|
export default BaseDialog;
|
||||||
|
@ -1,29 +1,29 @@
|
|||||||
import Dialog from '@material-ui/core/Dialog'
|
import Dialog from '@material-ui/core/Dialog';
|
||||||
import DialogActions from '@material-ui/core/DialogActions'
|
import DialogActions from '@material-ui/core/DialogActions';
|
||||||
import DialogContent from '@material-ui/core/DialogContent'
|
import DialogContent from '@material-ui/core/DialogContent';
|
||||||
import DialogTitle from '@material-ui/core/DialogTitle'
|
import DialogTitle from '@material-ui/core/DialogTitle';
|
||||||
import withStyles from '@material-ui/core/styles/withStyles'
|
import withStyles from '@material-ui/core/styles/withStyles';
|
||||||
|
|
||||||
export const StyledDialogContent = withStyles({
|
export const StyledDialogContent = withStyles({
|
||||||
root: {
|
root: {
|
||||||
padding: '0px 39px',
|
padding: '0px 39px',
|
||||||
},
|
},
|
||||||
})(DialogContent)
|
})(DialogContent);
|
||||||
|
|
||||||
export const StyledDialogTitle = withStyles({
|
export const StyledDialogTitle = withStyles({
|
||||||
root: {
|
root: {
|
||||||
padding: '39px 39px 10px 39px',
|
padding: '39px 39px 10px 39px',
|
||||||
},
|
},
|
||||||
})(DialogTitle)
|
})(DialogTitle);
|
||||||
|
|
||||||
export const StyledDialogActions = withStyles({
|
export const StyledDialogActions = withStyles({
|
||||||
root: {
|
root: {
|
||||||
padding: '39px 39px 39px 39px',
|
padding: '39px 39px 39px 39px',
|
||||||
},
|
},
|
||||||
})(DialogActions)
|
})(DialogActions);
|
||||||
|
|
||||||
export const StyledDialog = withStyles({
|
export const StyledDialog = withStyles({
|
||||||
root: {
|
root: {
|
||||||
borderRadius: '9px',
|
borderRadius: '9px',
|
||||||
},
|
},
|
||||||
})(Dialog)
|
})(Dialog);
|
||||||
|
@ -1,62 +1,62 @@
|
|||||||
import React from 'react'
|
import React from 'react';
|
||||||
import { useIntl } from 'react-intl'
|
import { useIntl } from 'react-intl';
|
||||||
import { useMutation } from 'react-query'
|
import { useMutation } from 'react-query';
|
||||||
import { useSelector } from 'react-redux'
|
import { useSelector } from 'react-redux';
|
||||||
import FormControl from '@material-ui/core/FormControl'
|
import FormControl from '@material-ui/core/FormControl';
|
||||||
|
|
||||||
import Client, { BasicMapInfo, ErrorInfo } from '../../../../classes/client'
|
import Client, { BasicMapInfo, ErrorInfo } from '../../../../classes/client';
|
||||||
import { activeInstance } from '../../../../redux/clientSlice'
|
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';
|
||||||
|
|
||||||
export type CreateModel = {
|
export type CreateModel = {
|
||||||
title: string
|
title: string;
|
||||||
description?: string
|
description?: string;
|
||||||
}
|
};
|
||||||
|
|
||||||
export type CreateProps = {
|
export type CreateProps = {
|
||||||
onClose: () => void
|
onClose: () => void;
|
||||||
}
|
};
|
||||||
|
|
||||||
const defaultModel: CreateModel = { title: '', description: '' }
|
const defaultModel: CreateModel = { title: '', description: '' };
|
||||||
const CreateDialog = ({ onClose }: CreateProps): React.ReactElement => {
|
const CreateDialog = ({ onClose }: CreateProps): React.ReactElement => {
|
||||||
const client: Client = useSelector(activeInstance)
|
const client: Client = useSelector(activeInstance);
|
||||||
const [model, setModel] = React.useState<CreateModel>(defaultModel)
|
const [model, setModel] = React.useState<CreateModel>(defaultModel);
|
||||||
const [error, setError] = React.useState<ErrorInfo>()
|
const [error, setError] = React.useState<ErrorInfo>();
|
||||||
const intl = useIntl()
|
const intl = useIntl();
|
||||||
|
|
||||||
const mutation = useMutation<number, ErrorInfo, CreateModel>(
|
const mutation = useMutation<number, ErrorInfo, CreateModel>(
|
||||||
(model: CreateModel) => {
|
(model: CreateModel) => {
|
||||||
return client.createMap(model)
|
return client.createMap(model);
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
onSuccess: (mapId: number) => {
|
onSuccess: (mapId: number) => {
|
||||||
window.location.href = `/c/maps/${mapId}/edit`
|
window.location.href = `/c/maps/${mapId}/edit`;
|
||||||
},
|
},
|
||||||
onError: (error) => {
|
onError: (error) => {
|
||||||
setError(error)
|
setError(error);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
)
|
);
|
||||||
|
|
||||||
const handleOnClose = (): void => {
|
const handleOnClose = (): void => {
|
||||||
onClose()
|
onClose();
|
||||||
setModel(defaultModel)
|
setModel(defaultModel);
|
||||||
setError(undefined)
|
setError(undefined);
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleOnSubmit = (event: React.FormEvent<HTMLFormElement>): void => {
|
const handleOnSubmit = (event: React.FormEvent<HTMLFormElement>): void => {
|
||||||
event.preventDefault()
|
event.preventDefault();
|
||||||
mutation.mutate(model)
|
mutation.mutate(model);
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleOnChange = (event: React.ChangeEvent<HTMLInputElement>): void => {
|
const handleOnChange = (event: React.ChangeEvent<HTMLInputElement>): void => {
|
||||||
event.preventDefault()
|
event.preventDefault();
|
||||||
|
|
||||||
const name = event.target.name
|
const name = event.target.name;
|
||||||
const value = event.target.value
|
const value = event.target.value;
|
||||||
setModel({ ...model, [name as keyof BasicMapInfo]: value })
|
setModel({ ...model, [name as keyof BasicMapInfo]: value });
|
||||||
}
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@ -103,7 +103,7 @@ const CreateDialog = ({ onClose }: CreateProps): React.ReactElement => {
|
|||||||
</FormControl>
|
</FormControl>
|
||||||
</BaseDialog>
|
</BaseDialog>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
export default CreateDialog
|
export default CreateDialog;
|
||||||
|
@ -1,38 +1,38 @@
|
|||||||
import React from 'react'
|
import React from 'react';
|
||||||
import { FormattedMessage, useIntl } from 'react-intl'
|
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, { ErrorInfo } from '../../../../classes/client'
|
import Client, { ErrorInfo } from '../../../../classes/client';
|
||||||
import { activeInstance, fetchMapById } from '../../../../redux/clientSlice'
|
import { activeInstance, fetchMapById } from '../../../../redux/clientSlice';
|
||||||
import { SimpleDialogProps, handleOnMutationSuccess } from '..'
|
import { SimpleDialogProps, handleOnMutationSuccess } from '..';
|
||||||
import BaseDialog from '../base-dialog'
|
import BaseDialog from '../base-dialog';
|
||||||
import Alert from '@material-ui/lab/Alert'
|
import Alert from '@material-ui/lab/Alert';
|
||||||
import AlertTitle from '@material-ui/lab/AlertTitle'
|
import AlertTitle from '@material-ui/lab/AlertTitle';
|
||||||
|
|
||||||
const DeleteDialog = ({ mapId, onClose }: SimpleDialogProps): React.ReactElement => {
|
const DeleteDialog = ({ mapId, onClose }: SimpleDialogProps): React.ReactElement => {
|
||||||
const intl = useIntl()
|
const intl = useIntl();
|
||||||
const client: Client = useSelector(activeInstance)
|
const client: Client = useSelector(activeInstance);
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient();
|
||||||
const [error, setError] = React.useState<ErrorInfo>()
|
const [error, setError] = React.useState<ErrorInfo>();
|
||||||
|
|
||||||
const mutation = useMutation((id: number) => client.deleteMap(id), {
|
const mutation = useMutation((id: number) => client.deleteMap(id), {
|
||||||
onSuccess: () => handleOnMutationSuccess(onClose, queryClient),
|
onSuccess: () => handleOnMutationSuccess(onClose, queryClient),
|
||||||
onError: (error: ErrorInfo) => {
|
onError: (error: ErrorInfo) => {
|
||||||
setError(error)
|
setError(error);
|
||||||
},
|
},
|
||||||
})
|
});
|
||||||
|
|
||||||
const handleOnClose = (): void => {
|
const handleOnClose = (): void => {
|
||||||
onClose()
|
onClose();
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleOnSubmit = (): void => {
|
const handleOnSubmit = (): void => {
|
||||||
mutation.mutate(mapId)
|
mutation.mutate(mapId);
|
||||||
}
|
};
|
||||||
|
|
||||||
// Fetch map model to be rendered ...
|
// Fetch map model to be rendered ...
|
||||||
const { map } = fetchMapById(mapId)
|
const { map } = fetchMapById(mapId);
|
||||||
const alertTitle = `Delete ${map?.title}`
|
const alertTitle = `Delete ${map?.title}`;
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<BaseDialog
|
<BaseDialog
|
||||||
@ -54,7 +54,7 @@ const DeleteDialog = ({ mapId, onClose }: SimpleDialogProps): React.ReactElement
|
|||||||
</Alert>
|
</Alert>
|
||||||
</BaseDialog>
|
</BaseDialog>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
export default DeleteDialog
|
export default DeleteDialog;
|
||||||
|
@ -1,41 +1,41 @@
|
|||||||
import React from 'react'
|
import React from 'react';
|
||||||
import { FormattedMessage, useIntl } from 'react-intl'
|
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 '../../../../classes/client'
|
import Client from '../../../../classes/client';
|
||||||
import { activeInstance } from '../../../../redux/clientSlice'
|
import { activeInstance } from '../../../../redux/clientSlice';
|
||||||
import { handleOnMutationSuccess } from '..'
|
import { handleOnMutationSuccess } from '..';
|
||||||
import BaseDialog from '../base-dialog'
|
import BaseDialog from '../base-dialog';
|
||||||
import Alert from '@material-ui/lab/Alert'
|
import Alert from '@material-ui/lab/Alert';
|
||||||
import AlertTitle from '@material-ui/lab/AlertTitle'
|
import AlertTitle from '@material-ui/lab/AlertTitle';
|
||||||
|
|
||||||
export type DeleteMultiselectDialogProps = {
|
export type DeleteMultiselectDialogProps = {
|
||||||
mapsId: number[]
|
mapsId: number[];
|
||||||
onClose: () => void
|
onClose: () => void;
|
||||||
}
|
};
|
||||||
|
|
||||||
const DeleteMultiselectDialog = ({
|
const DeleteMultiselectDialog = ({
|
||||||
onClose,
|
onClose,
|
||||||
mapsId,
|
mapsId,
|
||||||
}: DeleteMultiselectDialogProps): React.ReactElement => {
|
}: DeleteMultiselectDialogProps): React.ReactElement => {
|
||||||
const intl = useIntl()
|
const intl = useIntl();
|
||||||
const client: Client = useSelector(activeInstance)
|
const client: Client = useSelector(activeInstance);
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
const mutation = useMutation((ids: number[]) => client.deleteMaps(ids), {
|
const mutation = useMutation((ids: number[]) => client.deleteMaps(ids), {
|
||||||
onSuccess: () => handleOnMutationSuccess(onClose, queryClient),
|
onSuccess: () => handleOnMutationSuccess(onClose, queryClient),
|
||||||
onError: (error) => {
|
onError: (error) => {
|
||||||
console.error(`Unexpected error ${error}`)
|
console.error(`Unexpected error ${error}`);
|
||||||
},
|
},
|
||||||
})
|
});
|
||||||
|
|
||||||
const handleOnClose = (): void => {
|
const handleOnClose = (): void => {
|
||||||
onClose()
|
onClose();
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleOnSubmit = (): void => {
|
const handleOnSubmit = (): void => {
|
||||||
mutation.mutate(mapsId)
|
mutation.mutate(mapsId);
|
||||||
}
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@ -62,7 +62,7 @@ const DeleteMultiselectDialog = ({
|
|||||||
</Alert>
|
</Alert>
|
||||||
</BaseDialog>
|
</BaseDialog>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
export default DeleteMultiselectDialog
|
export default DeleteMultiselectDialog;
|
||||||
|
@ -1,70 +1,70 @@
|
|||||||
import React, { useEffect } from 'react'
|
import React, { useEffect } from 'react';
|
||||||
import { useIntl } from 'react-intl'
|
import { useIntl } from 'react-intl';
|
||||||
import { useMutation } from 'react-query'
|
import { useMutation } from 'react-query';
|
||||||
import FormControl from '@material-ui/core/FormControl'
|
import FormControl from '@material-ui/core/FormControl';
|
||||||
import { useSelector } from 'react-redux'
|
import { useSelector } from 'react-redux';
|
||||||
|
|
||||||
import Client, { BasicMapInfo, ErrorInfo } from '../../../../classes/client'
|
import Client, { BasicMapInfo, ErrorInfo } from '../../../../classes/client';
|
||||||
import { activeInstance, fetchMapById } from '../../../../redux/clientSlice'
|
import { activeInstance, fetchMapById } from '../../../../redux/clientSlice';
|
||||||
import Input from '../../../form/input'
|
import Input from '../../../form/input';
|
||||||
import { SimpleDialogProps } from '..'
|
import { SimpleDialogProps } from '..';
|
||||||
import BaseDialog from '../base-dialog'
|
import BaseDialog from '../base-dialog';
|
||||||
|
|
||||||
export type DuplicateModel = {
|
export type DuplicateModel = {
|
||||||
id: number
|
id: number;
|
||||||
title: string
|
title: string;
|
||||||
description?: string
|
description?: string;
|
||||||
}
|
};
|
||||||
|
|
||||||
const defaultModel: DuplicateModel = { title: '', description: '', id: -1 }
|
const defaultModel: DuplicateModel = { title: '', description: '', id: -1 };
|
||||||
const DuplicateDialog = ({ mapId, onClose }: SimpleDialogProps): React.ReactElement => {
|
const DuplicateDialog = ({ mapId, onClose }: SimpleDialogProps): React.ReactElement => {
|
||||||
const service: Client = useSelector(activeInstance)
|
const service: Client = useSelector(activeInstance);
|
||||||
const [model, setModel] = React.useState<DuplicateModel>(defaultModel)
|
const [model, setModel] = React.useState<DuplicateModel>(defaultModel);
|
||||||
const [error, setError] = React.useState<ErrorInfo>()
|
const [error, setError] = React.useState<ErrorInfo>();
|
||||||
|
|
||||||
const intl = useIntl()
|
const intl = useIntl();
|
||||||
|
|
||||||
const mutation = useMutation<number, ErrorInfo, DuplicateModel>(
|
const mutation = useMutation<number, ErrorInfo, DuplicateModel>(
|
||||||
(model: DuplicateModel) => {
|
(model: DuplicateModel) => {
|
||||||
const { id, ...rest } = model
|
const { id, ...rest } = model;
|
||||||
return service.duplicateMap(id, rest)
|
return service.duplicateMap(id, rest);
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
onSuccess: (mapId) => {
|
onSuccess: (mapId) => {
|
||||||
window.location.href = `/c/maps/${mapId}/edit`
|
window.location.href = `/c/maps/${mapId}/edit`;
|
||||||
},
|
},
|
||||||
onError: (error) => {
|
onError: (error) => {
|
||||||
setError(error)
|
setError(error);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
)
|
);
|
||||||
|
|
||||||
const handleOnClose = (): void => {
|
const handleOnClose = (): void => {
|
||||||
onClose()
|
onClose();
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleOnSubmit = (event: React.FormEvent<HTMLFormElement>): void => {
|
const handleOnSubmit = (event: React.FormEvent<HTMLFormElement>): void => {
|
||||||
event.preventDefault()
|
event.preventDefault();
|
||||||
mutation.mutate(model)
|
mutation.mutate(model);
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleOnChange = (event: React.ChangeEvent<HTMLInputElement>): void => {
|
const handleOnChange = (event: React.ChangeEvent<HTMLInputElement>): void => {
|
||||||
event.preventDefault()
|
event.preventDefault();
|
||||||
|
|
||||||
const name = event.target.name
|
const name = event.target.name;
|
||||||
const value = event.target.value
|
const value = event.target.value;
|
||||||
setModel({ ...model, [name as keyof BasicMapInfo]: value })
|
setModel({ ...model, [name as keyof BasicMapInfo]: value });
|
||||||
}
|
};
|
||||||
|
|
||||||
const { map } = fetchMapById(mapId)
|
const { map } = fetchMapById(mapId);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (open && map) {
|
if (open && map) {
|
||||||
setModel(map)
|
setModel(map);
|
||||||
} else {
|
} else {
|
||||||
setModel(defaultModel)
|
setModel(defaultModel);
|
||||||
setError(undefined)
|
setError(undefined);
|
||||||
}
|
}
|
||||||
}, [mapId])
|
}, [mapId]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@ -111,7 +111,7 @@ const DuplicateDialog = ({ mapId, onClose }: SimpleDialogProps): React.ReactElem
|
|||||||
</FormControl>
|
</FormControl>
|
||||||
</BaseDialog>
|
</BaseDialog>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
export default DuplicateDialog
|
export default DuplicateDialog;
|
||||||
|
@ -1,25 +1,25 @@
|
|||||||
import React, { useEffect } from 'react'
|
import React, { useEffect } from 'react';
|
||||||
import { FormattedMessage, useIntl } from 'react-intl'
|
import { FormattedMessage, useIntl } from 'react-intl';
|
||||||
import BaseDialog from '../base-dialog'
|
import BaseDialog from '../base-dialog';
|
||||||
import { useStyles } from './style'
|
import { useStyles } from './style';
|
||||||
import Alert from '@material-ui/lab/Alert'
|
import Alert from '@material-ui/lab/Alert';
|
||||||
import { fetchMapById } from '../../../../redux/clientSlice'
|
import { fetchMapById } from '../../../../redux/clientSlice';
|
||||||
import FormControl from '@material-ui/core/FormControl'
|
import FormControl from '@material-ui/core/FormControl';
|
||||||
import RadioGroup from '@material-ui/core/RadioGroup'
|
import RadioGroup from '@material-ui/core/RadioGroup';
|
||||||
import FormControlLabel from '@material-ui/core/FormControlLabel'
|
import FormControlLabel from '@material-ui/core/FormControlLabel';
|
||||||
import Radio from '@material-ui/core/Radio'
|
import Radio from '@material-ui/core/Radio';
|
||||||
import Select from '@material-ui/core/Select'
|
import Select from '@material-ui/core/Select';
|
||||||
import MenuItem from '@material-ui/core/MenuItem'
|
import MenuItem from '@material-ui/core/MenuItem';
|
||||||
|
|
||||||
type ExportFormat = 'pdf' | 'svg' | 'jpg' | 'png' | 'txt' | 'mm' | 'wxml' | 'xls' | 'txt'
|
type ExportFormat = 'pdf' | 'svg' | 'jpg' | 'png' | 'txt' | 'mm' | 'wxml' | 'xls' | 'txt';
|
||||||
type ExportGroup = 'image' | 'document' | 'mindmap-tool'
|
type ExportGroup = 'image' | 'document' | 'mindmap-tool';
|
||||||
|
|
||||||
type ExportDialogProps = {
|
type ExportDialogProps = {
|
||||||
mapId: number
|
mapId: number;
|
||||||
enableImgExport: boolean
|
enableImgExport: boolean;
|
||||||
svgXml?: string
|
svgXml?: string;
|
||||||
onClose: () => void
|
onClose: () => void;
|
||||||
}
|
};
|
||||||
|
|
||||||
const ExportDialog = ({
|
const ExportDialog = ({
|
||||||
mapId,
|
mapId,
|
||||||
@ -27,50 +27,50 @@ const ExportDialog = ({
|
|||||||
enableImgExport,
|
enableImgExport,
|
||||||
svgXml,
|
svgXml,
|
||||||
}: ExportDialogProps): React.ReactElement => {
|
}: ExportDialogProps): React.ReactElement => {
|
||||||
const intl = useIntl()
|
const intl = useIntl();
|
||||||
const [submit, setSubmit] = React.useState<boolean>(false)
|
const [submit, setSubmit] = React.useState<boolean>(false);
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
const [formExportRef, setExportFormRef] = React.useState<any>()
|
const [formExportRef, setExportFormRef] = React.useState<any>();
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
const [formTransformtRef, setTransformFormRef] = React.useState<any>()
|
const [formTransformtRef, setTransformFormRef] = React.useState<any>();
|
||||||
const [exportGroup, setExportGroup] = React.useState<ExportGroup>(
|
const [exportGroup, setExportGroup] = React.useState<ExportGroup>(
|
||||||
enableImgExport ? 'image' : 'document'
|
enableImgExport ? 'image' : 'document'
|
||||||
)
|
);
|
||||||
const [exportFormat, setExportFormat] = React.useState<ExportFormat>(
|
const [exportFormat, setExportFormat] = React.useState<ExportFormat>(
|
||||||
enableImgExport ? 'svg' : 'xls'
|
enableImgExport ? 'svg' : 'xls'
|
||||||
)
|
);
|
||||||
const classes = useStyles()
|
const classes = useStyles();
|
||||||
|
|
||||||
const handleOnExportFormatChange = (event) => {
|
const handleOnExportFormatChange = (event) => {
|
||||||
setExportFormat(event.target.value)
|
setExportFormat(event.target.value);
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleOnGroupChange = (event) => {
|
const handleOnGroupChange = (event) => {
|
||||||
const value: ExportGroup = event.target.value
|
const value: ExportGroup = event.target.value;
|
||||||
setExportGroup(value)
|
setExportGroup(value);
|
||||||
|
|
||||||
let defaultFormat: ExportFormat
|
let defaultFormat: ExportFormat;
|
||||||
switch (value) {
|
switch (value) {
|
||||||
case 'document':
|
case 'document':
|
||||||
defaultFormat = 'pdf'
|
defaultFormat = 'pdf';
|
||||||
break
|
break;
|
||||||
case 'image':
|
case 'image':
|
||||||
defaultFormat = 'svg'
|
defaultFormat = 'svg';
|
||||||
break
|
break;
|
||||||
case 'mindmap-tool':
|
case 'mindmap-tool':
|
||||||
defaultFormat = 'wxml'
|
defaultFormat = 'wxml';
|
||||||
break
|
break;
|
||||||
}
|
|
||||||
setExportFormat(defaultFormat)
|
|
||||||
}
|
}
|
||||||
|
setExportFormat(defaultFormat);
|
||||||
|
};
|
||||||
|
|
||||||
const handleOnClose = (): void => {
|
const handleOnClose = (): void => {
|
||||||
onClose()
|
onClose();
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleOnSubmit = (): void => {
|
const handleOnSubmit = (): void => {
|
||||||
setSubmit(true)
|
setSubmit(true);
|
||||||
}
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (submit) {
|
if (submit) {
|
||||||
@ -81,15 +81,15 @@ const ExportDialog = ({
|
|||||||
exportFormat == 'jpg' ||
|
exportFormat == 'jpg' ||
|
||||||
exportFormat == 'png'
|
exportFormat == 'png'
|
||||||
) {
|
) {
|
||||||
formTransformtRef?.submit()
|
formTransformtRef?.submit();
|
||||||
} else {
|
} else {
|
||||||
formExportRef?.submit()
|
formExportRef?.submit();
|
||||||
}
|
}
|
||||||
onClose()
|
onClose();
|
||||||
}
|
}
|
||||||
}, [submit])
|
}, [submit]);
|
||||||
|
|
||||||
const { map } = fetchMapById(mapId)
|
const { map } = fetchMapById(mapId);
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<BaseDialog
|
<BaseDialog
|
||||||
@ -231,7 +231,7 @@ const ExportDialog = ({
|
|||||||
<input name="svgXml" id="svgXml" value={svgXml} type="hidden" />
|
<input name="svgXml" id="svgXml" value={svgXml} type="hidden" />
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
export default ExportDialog
|
export default ExportDialog;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import createStyles from '@material-ui/core/styles/createStyles'
|
import createStyles from '@material-ui/core/styles/createStyles';
|
||||||
import makeStyles from '@material-ui/core/styles/makeStyles'
|
import makeStyles from '@material-ui/core/styles/makeStyles';
|
||||||
|
|
||||||
export const useStyles = makeStyles(() =>
|
export const useStyles = makeStyles(() =>
|
||||||
createStyles({
|
createStyles({
|
||||||
@ -17,4 +17,4 @@ export const useStyles = makeStyles(() =>
|
|||||||
margin: '5px 0px',
|
margin: '5px 0px',
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
)
|
);
|
||||||
|
@ -1,42 +1,42 @@
|
|||||||
import React, { ErrorInfo } from 'react'
|
import React, { ErrorInfo } from 'react';
|
||||||
import { FormattedMessage, useIntl } from 'react-intl'
|
import { FormattedMessage, useIntl } from 'react-intl';
|
||||||
import { useQuery } from 'react-query'
|
import { useQuery } from 'react-query';
|
||||||
import { useSelector } from 'react-redux'
|
import { useSelector } from 'react-redux';
|
||||||
import Client, { ChangeHistory } from '../../../../classes/client'
|
import Client, { ChangeHistory } from '../../../../classes/client';
|
||||||
import { activeInstance } from '../../../../redux/clientSlice'
|
import { activeInstance } from '../../../../redux/clientSlice';
|
||||||
import { SimpleDialogProps } from '..'
|
import { SimpleDialogProps } from '..';
|
||||||
import BaseDialog from '../base-dialog'
|
import BaseDialog from '../base-dialog';
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs';
|
||||||
|
|
||||||
import TableContainer from '@material-ui/core/TableContainer'
|
import TableContainer from '@material-ui/core/TableContainer';
|
||||||
import Table from '@material-ui/core/Table'
|
import Table from '@material-ui/core/Table';
|
||||||
import TableRow from '@material-ui/core/TableRow'
|
import TableRow from '@material-ui/core/TableRow';
|
||||||
import TableCell from '@material-ui/core/TableCell'
|
import TableCell from '@material-ui/core/TableCell';
|
||||||
import TableHead from '@material-ui/core/TableHead'
|
import TableHead from '@material-ui/core/TableHead';
|
||||||
import TableBody from '@material-ui/core/TableBody'
|
import TableBody from '@material-ui/core/TableBody';
|
||||||
import Tooltip from '@material-ui/core/Tooltip'
|
import Tooltip from '@material-ui/core/Tooltip';
|
||||||
import Link from '@material-ui/core/Link'
|
import Link from '@material-ui/core/Link';
|
||||||
import Paper from '@material-ui/core/Paper'
|
import Paper from '@material-ui/core/Paper';
|
||||||
|
|
||||||
const HistoryDialog = ({ mapId, onClose }: SimpleDialogProps): React.ReactElement => {
|
const HistoryDialog = ({ mapId, onClose }: SimpleDialogProps): React.ReactElement => {
|
||||||
const intl = useIntl()
|
const intl = useIntl();
|
||||||
|
|
||||||
const client: Client = useSelector(activeInstance)
|
const client: Client = useSelector(activeInstance);
|
||||||
const { data } = useQuery<unknown, ErrorInfo, ChangeHistory[]>('history', () => {
|
const { data } = useQuery<unknown, ErrorInfo, ChangeHistory[]>('history', () => {
|
||||||
return client.fetchHistory(mapId)
|
return client.fetchHistory(mapId);
|
||||||
})
|
});
|
||||||
const changeHistory: ChangeHistory[] = data ? data : []
|
const changeHistory: ChangeHistory[] = data ? data : [];
|
||||||
|
|
||||||
const handleOnClose = (): void => {
|
const handleOnClose = (): void => {
|
||||||
onClose()
|
onClose();
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleOnClick = (event, vid): void => {
|
const handleOnClick = (event, vid): void => {
|
||||||
event.preventDefault()
|
event.preventDefault();
|
||||||
client.revertHistory(mapId, vid).then(() => {
|
client.revertHistory(mapId, vid).then(() => {
|
||||||
handleOnClose()
|
handleOnClose();
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@ -127,7 +127,7 @@ const HistoryDialog = ({ mapId, onClose }: SimpleDialogProps): React.ReactElemen
|
|||||||
</TableContainer>
|
</TableContainer>
|
||||||
</BaseDialog>
|
</BaseDialog>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
export default HistoryDialog
|
export default HistoryDialog;
|
||||||
|
@ -1,96 +1,96 @@
|
|||||||
import Button from '@material-ui/core/Button'
|
import Button from '@material-ui/core/Button';
|
||||||
import FormControl from '@material-ui/core/FormControl'
|
import FormControl from '@material-ui/core/FormControl';
|
||||||
import React from 'react'
|
import React from 'react';
|
||||||
|
|
||||||
import { FormattedMessage, useIntl } from 'react-intl'
|
import { FormattedMessage, useIntl } from 'react-intl';
|
||||||
import { useMutation } from 'react-query'
|
import { useMutation } from 'react-query';
|
||||||
import { useSelector } from 'react-redux'
|
import { useSelector } from 'react-redux';
|
||||||
import Client, { ErrorInfo } from '../../../../classes/client'
|
import Client, { ErrorInfo } from '../../../../classes/client';
|
||||||
import { activeInstance } from '../../../../redux/clientSlice'
|
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';
|
||||||
|
|
||||||
export type ImportModel = {
|
export type ImportModel = {
|
||||||
title: string
|
title: string;
|
||||||
description?: string
|
description?: string;
|
||||||
contentType?: string
|
contentType?: string;
|
||||||
content?: ArrayBuffer | null | string
|
content?: ArrayBuffer | null | string;
|
||||||
}
|
};
|
||||||
|
|
||||||
export type CreateProps = {
|
export type CreateProps = {
|
||||||
onClose: () => void
|
onClose: () => void;
|
||||||
}
|
};
|
||||||
|
|
||||||
const defaultModel: ImportModel = { title: '' }
|
const defaultModel: ImportModel = { title: '' };
|
||||||
const ImportDialog = ({ onClose }: CreateProps): React.ReactElement => {
|
const ImportDialog = ({ onClose }: CreateProps): React.ReactElement => {
|
||||||
const client: Client = useSelector(activeInstance)
|
const client: Client = useSelector(activeInstance);
|
||||||
const [model, setModel] = React.useState<ImportModel>(defaultModel)
|
const [model, setModel] = React.useState<ImportModel>(defaultModel);
|
||||||
const [error, setError] = React.useState<ErrorInfo>()
|
const [error, setError] = React.useState<ErrorInfo>();
|
||||||
const intl = useIntl()
|
const intl = useIntl();
|
||||||
|
|
||||||
const mutation = useMutation<number, ErrorInfo, ImportModel>(
|
const mutation = useMutation<number, ErrorInfo, ImportModel>(
|
||||||
(model: ImportModel) => {
|
(model: ImportModel) => {
|
||||||
return client.importMap(model)
|
return client.importMap(model);
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
onSuccess: (mapId: number) => {
|
onSuccess: (mapId: number) => {
|
||||||
window.location.href = `/c/maps/${mapId}/edit`
|
window.location.href = `/c/maps/${mapId}/edit`;
|
||||||
},
|
},
|
||||||
onError: (error) => {
|
onError: (error) => {
|
||||||
setError(error)
|
setError(error);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
)
|
);
|
||||||
|
|
||||||
const handleOnClose = (): void => {
|
const handleOnClose = (): void => {
|
||||||
onClose()
|
onClose();
|
||||||
setModel(defaultModel)
|
setModel(defaultModel);
|
||||||
setError(undefined)
|
setError(undefined);
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleOnSubmit = (event: React.FormEvent<HTMLFormElement>): void => {
|
const handleOnSubmit = (event: React.FormEvent<HTMLFormElement>): void => {
|
||||||
event.preventDefault()
|
event.preventDefault();
|
||||||
mutation.mutate(model)
|
mutation.mutate(model);
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleOnChange = (event: React.ChangeEvent<HTMLInputElement>): void => {
|
const handleOnChange = (event: React.ChangeEvent<HTMLInputElement>): void => {
|
||||||
event.preventDefault()
|
event.preventDefault();
|
||||||
|
|
||||||
const name = event.target.name
|
const name = event.target.name;
|
||||||
const value = event.target.value
|
const value = event.target.value;
|
||||||
setModel({ ...model, [name as keyof ImportModel]: value })
|
setModel({ ...model, [name as keyof ImportModel]: value });
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleOnFileChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
const handleOnFileChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
const files = event?.target?.files
|
const files = event?.target?.files;
|
||||||
const reader = new FileReader()
|
const reader = new FileReader();
|
||||||
|
|
||||||
if (files) {
|
if (files) {
|
||||||
const file = files[0]
|
const file = files[0];
|
||||||
// Closure to capture the file information.
|
// Closure to capture the file information.
|
||||||
reader.onload = (event) => {
|
reader.onload = (event) => {
|
||||||
const fileContent = event?.target?.result
|
const fileContent = event?.target?.result;
|
||||||
model.content = fileContent
|
model.content = fileContent;
|
||||||
|
|
||||||
// Suggest file name ...
|
// Suggest file name ...
|
||||||
const fileName = file.name
|
const fileName = file.name;
|
||||||
if (fileName) {
|
if (fileName) {
|
||||||
const title = fileName.split('.')[0]
|
const title = fileName.split('.')[0];
|
||||||
if (!model.title || 0 === model.title.length) {
|
if (!model.title || 0 === model.title.length) {
|
||||||
model.title = title
|
model.title = title;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
model.contentType =
|
model.contentType =
|
||||||
file.name.lastIndexOf('.wxml') != -1
|
file.name.lastIndexOf('.wxml') != -1
|
||||||
? 'application/xml'
|
? 'application/xml'
|
||||||
: 'application/freemind'
|
: 'application/freemind';
|
||||||
setModel({ ...model })
|
setModel({ ...model });
|
||||||
}
|
};
|
||||||
|
|
||||||
// Read in the image file as a data URL.
|
// Read in the image file as a data URL.
|
||||||
reader.readAsText(file)
|
reader.readAsText(file);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@ -161,7 +161,7 @@ const ImportDialog = ({ onClose }: CreateProps): React.ReactElement => {
|
|||||||
</FormControl>
|
</FormControl>
|
||||||
</BaseDialog>
|
</BaseDialog>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
export default ImportDialog
|
export default ImportDialog;
|
||||||
|
@ -1,41 +1,41 @@
|
|||||||
import React from 'react'
|
import React from 'react';
|
||||||
import RenameDialog from './rename-dialog'
|
import RenameDialog from './rename-dialog';
|
||||||
import DeleteDialog from './delete-dialog'
|
import DeleteDialog from './delete-dialog';
|
||||||
import { ActionType } from '../action-chooser'
|
import { ActionType } from '../action-chooser';
|
||||||
import { QueryClient } from 'react-query'
|
import { QueryClient } from 'react-query';
|
||||||
import DuplicateDialog from './duplicate-dialog'
|
import DuplicateDialog from './duplicate-dialog';
|
||||||
import CreateDialog from './create-dialog'
|
import CreateDialog from './create-dialog';
|
||||||
import HistoryDialog from './history-dialog'
|
import HistoryDialog from './history-dialog';
|
||||||
import ImportDialog from './import-dialog'
|
import ImportDialog from './import-dialog';
|
||||||
import PublishDialog from './publish-dialog'
|
import PublishDialog from './publish-dialog';
|
||||||
import InfoDialog from './info-dialog'
|
import InfoDialog from './info-dialog';
|
||||||
import DeleteMultiselectDialog from './delete-multiselect-dialog'
|
import DeleteMultiselectDialog from './delete-multiselect-dialog';
|
||||||
import ExportDialog from './export-dialog'
|
import ExportDialog from './export-dialog';
|
||||||
import ShareDialog from './share-dialog'
|
import ShareDialog from './share-dialog';
|
||||||
|
|
||||||
export type BasicMapInfo = {
|
export type BasicMapInfo = {
|
||||||
name: string
|
name: string;
|
||||||
description: string | undefined
|
description: string | undefined;
|
||||||
}
|
};
|
||||||
|
|
||||||
type ActionDialogProps = {
|
type ActionDialogProps = {
|
||||||
action?: ActionType
|
action?: ActionType;
|
||||||
mapsId: number[]
|
mapsId: number[];
|
||||||
onClose: () => void
|
onClose: () => void;
|
||||||
}
|
};
|
||||||
|
|
||||||
const ActionDispatcher = ({ mapsId, action, onClose }: ActionDialogProps): React.ReactElement => {
|
const ActionDispatcher = ({ mapsId, action, onClose }: ActionDialogProps): React.ReactElement => {
|
||||||
const handleOnClose = (): void => {
|
const handleOnClose = (): void => {
|
||||||
onClose()
|
onClose();
|
||||||
}
|
};
|
||||||
|
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case 'open':
|
case 'open':
|
||||||
window.location.href = `/c/maps/${mapsId}/edit`
|
window.location.href = `/c/maps/${mapsId}/edit`;
|
||||||
break
|
break;
|
||||||
case 'print':
|
case 'print':
|
||||||
window.open(`/c/maps/${mapsId}/print`, 'print')
|
window.open(`/c/maps/${mapsId}/print`, 'print');
|
||||||
break
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -61,16 +61,16 @@ const ActionDispatcher = ({ mapsId, action, onClose }: ActionDialogProps): React
|
|||||||
)}
|
)}
|
||||||
{action === 'share' && <ShareDialog onClose={handleOnClose} mapId={mapsId[0]} />}
|
{action === 'share' && <ShareDialog onClose={handleOnClose} mapId={mapsId[0]} />}
|
||||||
</span>
|
</span>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
export const handleOnMutationSuccess = (onClose: () => void, queryClient: QueryClient): void => {
|
export const handleOnMutationSuccess = (onClose: () => void, queryClient: QueryClient): void => {
|
||||||
queryClient.invalidateQueries('maps')
|
queryClient.invalidateQueries('maps');
|
||||||
onClose()
|
onClose();
|
||||||
}
|
};
|
||||||
|
|
||||||
export type SimpleDialogProps = {
|
export type SimpleDialogProps = {
|
||||||
mapId: number
|
mapId: number;
|
||||||
onClose: () => void
|
onClose: () => void;
|
||||||
}
|
};
|
||||||
|
|
||||||
export default ActionDispatcher
|
export default ActionDispatcher;
|
||||||
|
@ -1,29 +1,29 @@
|
|||||||
import React from 'react'
|
import React from 'react';
|
||||||
import { FormattedMessage, useIntl } from 'react-intl'
|
import { FormattedMessage, useIntl } from 'react-intl';
|
||||||
|
|
||||||
import { ErrorInfo } from '../../../../classes/client'
|
import { ErrorInfo } from '../../../../classes/client';
|
||||||
import BaseDialog from '../base-dialog'
|
import BaseDialog from '../base-dialog';
|
||||||
import { SimpleDialogProps } from '..'
|
import { SimpleDialogProps } from '..';
|
||||||
import { useStyles } from './style'
|
import { useStyles } from './style';
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs';
|
||||||
import { fetchMapById } from '../../../../redux/clientSlice'
|
import { fetchMapById } from '../../../../redux/clientSlice';
|
||||||
import Paper from '@material-ui/core/Paper'
|
import Paper from '@material-ui/core/Paper';
|
||||||
import Card from '@material-ui/core/Card'
|
import Card from '@material-ui/core/Card';
|
||||||
import ListItem from '@material-ui/core/ListItem'
|
import ListItem from '@material-ui/core/ListItem';
|
||||||
import Typography from '@material-ui/core/Typography'
|
import Typography from '@material-ui/core/Typography';
|
||||||
import List from '@material-ui/core/List'
|
import List from '@material-ui/core/List';
|
||||||
|
|
||||||
const InfoDialog = ({ mapId, onClose }: SimpleDialogProps): React.ReactElement => {
|
const InfoDialog = ({ mapId, onClose }: SimpleDialogProps): React.ReactElement => {
|
||||||
const { map } = fetchMapById(mapId)
|
const { map } = fetchMapById(mapId);
|
||||||
const [error, setError] = React.useState<ErrorInfo>()
|
const [error, setError] = React.useState<ErrorInfo>();
|
||||||
|
|
||||||
const intl = useIntl()
|
const intl = useIntl();
|
||||||
const classes = useStyles()
|
const classes = useStyles();
|
||||||
|
|
||||||
const handleOnClose = (): void => {
|
const handleOnClose = (): void => {
|
||||||
onClose()
|
onClose();
|
||||||
setError(undefined)
|
setError(undefined);
|
||||||
}
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<BaseDialog
|
<BaseDialog
|
||||||
@ -175,7 +175,7 @@ const InfoDialog = ({ mapId, onClose }: SimpleDialogProps): React.ReactElement =
|
|||||||
</Card>
|
</Card>
|
||||||
</Paper>
|
</Paper>
|
||||||
</BaseDialog>
|
</BaseDialog>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
export default InfoDialog
|
export default InfoDialog;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import createStyles from '@material-ui/core/styles/createStyles'
|
import createStyles from '@material-ui/core/styles/createStyles';
|
||||||
import makeStyles from '@material-ui/core/styles/makeStyles'
|
import makeStyles from '@material-ui/core/styles/makeStyles';
|
||||||
|
|
||||||
export const useStyles = makeStyles(() =>
|
export const useStyles = makeStyles(() =>
|
||||||
createStyles({
|
createStyles({
|
||||||
@ -12,4 +12,4 @@ export const useStyles = makeStyles(() =>
|
|||||||
width: '150px',
|
width: '150px',
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
)
|
);
|
||||||
|
@ -1,68 +1,68 @@
|
|||||||
import React from 'react'
|
import React from 'react';
|
||||||
import { FormattedMessage, useIntl } from 'react-intl'
|
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, { ErrorInfo } from '../../../../classes/client'
|
import Client, { ErrorInfo } from '../../../../classes/client';
|
||||||
import { activeInstance, fetchMapById } from '../../../../redux/clientSlice'
|
import { activeInstance, fetchMapById } from '../../../../redux/clientSlice';
|
||||||
import BaseDialog from '../base-dialog'
|
import BaseDialog from '../base-dialog';
|
||||||
import { handleOnMutationSuccess, SimpleDialogProps } from '..'
|
import { handleOnMutationSuccess, SimpleDialogProps } from '..';
|
||||||
import { useStyles } from './style'
|
import { useStyles } from './style';
|
||||||
|
|
||||||
import FormControl from '@material-ui/core/FormControl'
|
import FormControl from '@material-ui/core/FormControl';
|
||||||
import FormControlLabel from '@material-ui/core/FormControlLabel'
|
import FormControlLabel from '@material-ui/core/FormControlLabel';
|
||||||
import Checkbox from '@material-ui/core/Checkbox'
|
import Checkbox from '@material-ui/core/Checkbox';
|
||||||
import TabContext from '@material-ui/lab/TabContext'
|
import TabContext from '@material-ui/lab/TabContext';
|
||||||
import AppBar from '@material-ui/core/AppBar'
|
import AppBar from '@material-ui/core/AppBar';
|
||||||
import TabList from '@material-ui/lab/TabList'
|
import TabList from '@material-ui/lab/TabList';
|
||||||
import Tab from '@material-ui/core/Tab'
|
import Tab from '@material-ui/core/Tab';
|
||||||
import TabPanel from '@material-ui/lab/TabPanel'
|
import TabPanel from '@material-ui/lab/TabPanel';
|
||||||
import Typography from '@material-ui/core/Typography'
|
import Typography from '@material-ui/core/Typography';
|
||||||
import TextareaAutosize from '@material-ui/core/TextareaAutosize'
|
import TextareaAutosize from '@material-ui/core/TextareaAutosize';
|
||||||
|
|
||||||
const PublishDialog = ({ mapId, onClose }: SimpleDialogProps): React.ReactElement => {
|
const PublishDialog = ({ mapId, onClose }: SimpleDialogProps): React.ReactElement => {
|
||||||
const { map } = fetchMapById(mapId)
|
const { map } = fetchMapById(mapId);
|
||||||
|
|
||||||
const client: Client = useSelector(activeInstance)
|
const client: Client = useSelector(activeInstance);
|
||||||
const [model, setModel] = React.useState<boolean>(map ? map.isPublic : false)
|
const [model, setModel] = React.useState<boolean>(map ? map.isPublic : false);
|
||||||
const [error, setError] = React.useState<ErrorInfo>()
|
const [error, setError] = React.useState<ErrorInfo>();
|
||||||
const [activeTab, setActiveTab] = React.useState('1')
|
const [activeTab, setActiveTab] = React.useState('1');
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient();
|
||||||
const intl = useIntl()
|
const intl = useIntl();
|
||||||
|
|
||||||
const classes = useStyles()
|
const classes = useStyles();
|
||||||
const mutation = useMutation<void, ErrorInfo, boolean>(
|
const mutation = useMutation<void, ErrorInfo, boolean>(
|
||||||
(model: boolean) => {
|
(model: boolean) => {
|
||||||
return client.updateMapToPublic(mapId, model)
|
return client.updateMapToPublic(mapId, model);
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
setModel(model)
|
setModel(model);
|
||||||
handleOnMutationSuccess(onClose, queryClient)
|
handleOnMutationSuccess(onClose, queryClient);
|
||||||
},
|
},
|
||||||
onError: (error) => {
|
onError: (error) => {
|
||||||
setError(error)
|
setError(error);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
)
|
);
|
||||||
|
|
||||||
const handleOnClose = (): void => {
|
const handleOnClose = (): void => {
|
||||||
onClose()
|
onClose();
|
||||||
setError(undefined)
|
setError(undefined);
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleOnSubmit = (event: React.FormEvent<HTMLFormElement>): void => {
|
const handleOnSubmit = (event: React.FormEvent<HTMLFormElement>): void => {
|
||||||
event.preventDefault()
|
event.preventDefault();
|
||||||
mutation.mutate(model)
|
mutation.mutate(model);
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleOnChange = (event: React.ChangeEvent<HTMLInputElement>, checked: boolean): void => {
|
const handleOnChange = (event: React.ChangeEvent<HTMLInputElement>, checked: boolean): void => {
|
||||||
event.preventDefault()
|
event.preventDefault();
|
||||||
setModel(checked)
|
setModel(checked);
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleTabChange = (event, newValue) => {
|
const handleTabChange = (event, newValue) => {
|
||||||
setActiveTab(newValue)
|
setActiveTab(newValue);
|
||||||
}
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@ -152,7 +152,7 @@ const PublishDialog = ({ mapId, onClose }: SimpleDialogProps): React.ReactElemen
|
|||||||
</div>
|
</div>
|
||||||
</BaseDialog>
|
</BaseDialog>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
export default PublishDialog
|
export default PublishDialog;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import createStyles from '@material-ui/core/styles/createStyles'
|
import createStyles from '@material-ui/core/styles/createStyles';
|
||||||
import makeStyles from '@material-ui/core/styles/makeStyles'
|
import makeStyles from '@material-ui/core/styles/makeStyles';
|
||||||
|
|
||||||
export const useStyles = makeStyles(() =>
|
export const useStyles = makeStyles(() =>
|
||||||
createStyles({
|
createStyles({
|
||||||
@ -9,4 +9,4 @@ export const useStyles = makeStyles(() =>
|
|||||||
marging: '0px 10px',
|
marging: '0px 10px',
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
)
|
);
|
||||||
|
@ -1,72 +1,72 @@
|
|||||||
import React, { useEffect } from 'react'
|
import React, { useEffect } from 'react';
|
||||||
import { useIntl } from 'react-intl'
|
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 '../../../../classes/client'
|
import Client, { BasicMapInfo, ErrorInfo } from '../../../../classes/client';
|
||||||
import { activeInstance, fetchMapById } from '../../../../redux/clientSlice'
|
import { activeInstance, fetchMapById } from '../../../../redux/clientSlice';
|
||||||
import { SimpleDialogProps, handleOnMutationSuccess } from '..'
|
import { SimpleDialogProps, handleOnMutationSuccess } from '..';
|
||||||
import Input from '../../../form/input'
|
import Input from '../../../form/input';
|
||||||
import BaseDialog from '../base-dialog'
|
import BaseDialog from '../base-dialog';
|
||||||
import FormControl from '@material-ui/core/FormControl'
|
import FormControl from '@material-ui/core/FormControl';
|
||||||
|
|
||||||
export type RenameModel = {
|
export type RenameModel = {
|
||||||
id: number
|
id: number;
|
||||||
title: string
|
title: string;
|
||||||
description?: string
|
description?: string;
|
||||||
}
|
};
|
||||||
|
|
||||||
const defaultModel: RenameModel = { title: '', description: '', id: -1 }
|
const defaultModel: RenameModel = { title: '', description: '', id: -1 };
|
||||||
const RenameDialog = ({ mapId, onClose }: SimpleDialogProps): React.ReactElement => {
|
const RenameDialog = ({ mapId, onClose }: SimpleDialogProps): React.ReactElement => {
|
||||||
const service: Client = useSelector(activeInstance)
|
const service: Client = useSelector(activeInstance);
|
||||||
const [model, setModel] = React.useState<RenameModel>(defaultModel)
|
const [model, setModel] = React.useState<RenameModel>(defaultModel);
|
||||||
const [error, setError] = React.useState<ErrorInfo>()
|
const [error, setError] = React.useState<ErrorInfo>();
|
||||||
|
|
||||||
const intl = useIntl()
|
const intl = useIntl();
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
const mutation = useMutation<RenameModel, ErrorInfo, RenameModel>(
|
const mutation = useMutation<RenameModel, ErrorInfo, RenameModel>(
|
||||||
(model: RenameModel) => {
|
(model: RenameModel) => {
|
||||||
const { id, ...rest } = model
|
const { id, ...rest } = model;
|
||||||
return service.renameMap(id, rest).then(() => model)
|
return service.renameMap(id, rest).then(() => model);
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
handleOnMutationSuccess(onClose, queryClient)
|
handleOnMutationSuccess(onClose, queryClient);
|
||||||
},
|
},
|
||||||
onError: (error) => {
|
onError: (error) => {
|
||||||
setError(error)
|
setError(error);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
)
|
);
|
||||||
|
|
||||||
const handleOnClose = (): void => {
|
const handleOnClose = (): void => {
|
||||||
onClose()
|
onClose();
|
||||||
setModel(defaultModel)
|
setModel(defaultModel);
|
||||||
setError(undefined)
|
setError(undefined);
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleOnSubmit = (event: React.FormEvent<HTMLFormElement>): void => {
|
const handleOnSubmit = (event: React.FormEvent<HTMLFormElement>): void => {
|
||||||
event.preventDefault()
|
event.preventDefault();
|
||||||
mutation.mutate(model)
|
mutation.mutate(model);
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleOnChange = (event: React.ChangeEvent<HTMLInputElement>): void => {
|
const handleOnChange = (event: React.ChangeEvent<HTMLInputElement>): void => {
|
||||||
event.preventDefault()
|
event.preventDefault();
|
||||||
|
|
||||||
const name = event.target.name
|
const name = event.target.name;
|
||||||
const value = event.target.value
|
const value = event.target.value;
|
||||||
setModel({ ...model, [name as keyof BasicMapInfo]: value })
|
setModel({ ...model, [name as keyof BasicMapInfo]: value });
|
||||||
}
|
};
|
||||||
|
|
||||||
const { map } = fetchMapById(mapId)
|
const { map } = fetchMapById(mapId);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (open && map) {
|
if (open && map) {
|
||||||
setModel(map)
|
setModel(map);
|
||||||
} else {
|
} else {
|
||||||
setModel(defaultModel)
|
setModel(defaultModel);
|
||||||
setError(undefined)
|
setError(undefined);
|
||||||
}
|
}
|
||||||
}, [mapId])
|
}, [mapId]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@ -110,7 +110,7 @@ const RenameDialog = ({ mapId, onClose }: SimpleDialogProps): React.ReactElement
|
|||||||
</FormControl>
|
</FormControl>
|
||||||
</BaseDialog>
|
</BaseDialog>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
export default RenameDialog
|
export default RenameDialog;
|
||||||
|
@ -1,115 +1,115 @@
|
|||||||
import React from 'react'
|
import React from 'react';
|
||||||
import { FormattedMessage, useIntl } from 'react-intl'
|
import { FormattedMessage, useIntl } from 'react-intl';
|
||||||
import { useMutation, useQuery, useQueryClient } from 'react-query'
|
import { useMutation, useQuery, useQueryClient } from 'react-query';
|
||||||
import { useSelector } from 'react-redux'
|
import { useSelector } from 'react-redux';
|
||||||
import Client, { ErrorInfo, Permission } from '../../../../classes/client'
|
import Client, { ErrorInfo, Permission } from '../../../../classes/client';
|
||||||
import { activeInstance } from '../../../../redux/clientSlice'
|
import { activeInstance } from '../../../../redux/clientSlice';
|
||||||
import { SimpleDialogProps } from '..'
|
import { SimpleDialogProps } from '..';
|
||||||
import BaseDialog from '../base-dialog'
|
import BaseDialog from '../base-dialog';
|
||||||
import List from '@material-ui/core/List'
|
import List from '@material-ui/core/List';
|
||||||
import ListItem from '@material-ui/core/ListItem'
|
import ListItem from '@material-ui/core/ListItem';
|
||||||
import ListItemText from '@material-ui/core/ListItemText'
|
import ListItemText from '@material-ui/core/ListItemText';
|
||||||
import IconButton from '@material-ui/core/IconButton'
|
import IconButton from '@material-ui/core/IconButton';
|
||||||
|
|
||||||
import ListItemSecondaryAction from '@material-ui/core/ListItemSecondaryAction'
|
import ListItemSecondaryAction from '@material-ui/core/ListItemSecondaryAction';
|
||||||
import DeleteIcon from '@material-ui/icons/Delete'
|
import DeleteIcon from '@material-ui/icons/Delete';
|
||||||
import Paper from '@material-ui/core/Paper'
|
import Paper from '@material-ui/core/Paper';
|
||||||
import Select from '@material-ui/core/Select'
|
import Select from '@material-ui/core/Select';
|
||||||
import MenuItem from '@material-ui/core/MenuItem'
|
import MenuItem from '@material-ui/core/MenuItem';
|
||||||
import Button from '@material-ui/core/Button'
|
import Button from '@material-ui/core/Button';
|
||||||
import TextField from '@material-ui/core/TextField'
|
import TextField from '@material-ui/core/TextField';
|
||||||
import FormControlLabel from '@material-ui/core/FormControlLabel'
|
import FormControlLabel from '@material-ui/core/FormControlLabel';
|
||||||
import Checkbox from '@material-ui/core/Checkbox'
|
import Checkbox from '@material-ui/core/Checkbox';
|
||||||
import Typography from '@material-ui/core/Typography'
|
import Typography from '@material-ui/core/Typography';
|
||||||
import { useStyles } from './style'
|
import { useStyles } from './style';
|
||||||
import RoleIcon from '../../role-icon'
|
import RoleIcon from '../../role-icon';
|
||||||
import Tooltip from '@material-ui/core/Tooltip'
|
import Tooltip from '@material-ui/core/Tooltip';
|
||||||
|
|
||||||
type ShareModel = {
|
type ShareModel = {
|
||||||
emails: string
|
emails: string;
|
||||||
role: 'editor' | 'viewer'
|
role: 'editor' | 'viewer';
|
||||||
message: string
|
message: string;
|
||||||
}
|
};
|
||||||
|
|
||||||
const defaultModel: ShareModel = { emails: '', role: 'editor', message: '' }
|
const defaultModel: ShareModel = { emails: '', role: 'editor', message: '' };
|
||||||
const ShareDialog = ({ mapId, onClose }: SimpleDialogProps): React.ReactElement => {
|
const ShareDialog = ({ mapId, onClose }: SimpleDialogProps): React.ReactElement => {
|
||||||
const intl = useIntl()
|
const intl = useIntl();
|
||||||
const client: Client = useSelector(activeInstance)
|
const client: Client = useSelector(activeInstance);
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient();
|
||||||
const classes = useStyles()
|
const classes = useStyles();
|
||||||
const [showMessage, setShowMessage] = React.useState<boolean>(false)
|
const [showMessage, setShowMessage] = React.useState<boolean>(false);
|
||||||
const [model, setModel] = React.useState<ShareModel>(defaultModel)
|
const [model, setModel] = React.useState<ShareModel>(defaultModel);
|
||||||
const [error, setError] = React.useState<ErrorInfo>()
|
const [error, setError] = React.useState<ErrorInfo>();
|
||||||
|
|
||||||
const deleteMutation = useMutation(
|
const deleteMutation = useMutation(
|
||||||
(email: string) => {
|
(email: string) => {
|
||||||
return client.deleteMapPermission(mapId, email)
|
return client.deleteMapPermission(mapId, email);
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
queryClient.invalidateQueries(`perm-${mapId}`)
|
queryClient.invalidateQueries(`perm-${mapId}`);
|
||||||
setModel(defaultModel)
|
setModel(defaultModel);
|
||||||
},
|
},
|
||||||
onError: (error: ErrorInfo) => {
|
onError: (error: ErrorInfo) => {
|
||||||
setError(error)
|
setError(error);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
)
|
);
|
||||||
|
|
||||||
const addMutation = useMutation(
|
const addMutation = useMutation(
|
||||||
(model: ShareModel) => {
|
(model: ShareModel) => {
|
||||||
const emails = model.emails.split("'")
|
const emails = model.emails.split("'");
|
||||||
const permissions = emails.map((email) => {
|
const permissions = emails.map((email) => {
|
||||||
return { email: email, role: model.role }
|
return { email: email, role: model.role };
|
||||||
})
|
});
|
||||||
return client.addMapPermissions(mapId, model.message, permissions)
|
return client.addMapPermissions(mapId, model.message, permissions);
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
queryClient.invalidateQueries(`perm-${mapId}`)
|
queryClient.invalidateQueries(`perm-${mapId}`);
|
||||||
setModel(defaultModel)
|
setModel(defaultModel);
|
||||||
},
|
},
|
||||||
onError: (error: ErrorInfo) => {
|
onError: (error: ErrorInfo) => {
|
||||||
setError(error)
|
setError(error);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
)
|
);
|
||||||
|
|
||||||
const handleOnClose = (): void => {
|
const handleOnClose = (): void => {
|
||||||
onClose()
|
onClose();
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleOnChange = (event: React.ChangeEvent<HTMLInputElement>): void => {
|
const handleOnChange = (event: React.ChangeEvent<HTMLInputElement>): void => {
|
||||||
event.preventDefault()
|
event.preventDefault();
|
||||||
|
|
||||||
const name = event.target.name
|
const name = event.target.name;
|
||||||
const value = event.target.value
|
const value = event.target.value;
|
||||||
setModel({ ...model, [name as keyof ShareModel]: value })
|
setModel({ ...model, [name as keyof ShareModel]: value });
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleOnAddClick = (event: React.MouseEvent<HTMLButtonElement, MouseEvent>): void => {
|
const handleOnAddClick = (event: React.MouseEvent<HTMLButtonElement, MouseEvent>): void => {
|
||||||
event.stopPropagation()
|
event.stopPropagation();
|
||||||
addMutation.mutate(model)
|
addMutation.mutate(model);
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleOnDeleteClick = (
|
const handleOnDeleteClick = (
|
||||||
event: React.MouseEvent<HTMLButtonElement, MouseEvent>,
|
event: React.MouseEvent<HTMLButtonElement, MouseEvent>,
|
||||||
email: string
|
email: string
|
||||||
): void => {
|
): void => {
|
||||||
event.stopPropagation()
|
event.stopPropagation();
|
||||||
deleteMutation.mutate(email)
|
deleteMutation.mutate(email);
|
||||||
}
|
};
|
||||||
|
|
||||||
const { isLoading, data: permissions = [] } = useQuery<unknown, ErrorInfo, Permission[]>(
|
const { isLoading, data: permissions = [] } = useQuery<unknown, ErrorInfo, Permission[]>(
|
||||||
`perm-${mapId}`,
|
`perm-${mapId}`,
|
||||||
() => {
|
() => {
|
||||||
return client.fetchMapPermissions(mapId)
|
return client.fetchMapPermissions(mapId);
|
||||||
}
|
}
|
||||||
)
|
);
|
||||||
|
|
||||||
const formatName = (perm: Permission): string => {
|
const formatName = (perm: Permission): string => {
|
||||||
return perm.name ? `${perm.name}<${perm.email}>` : perm.email
|
return perm.name ? `${perm.name}<${perm.email}>` : perm.email;
|
||||||
}
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@ -160,7 +160,7 @@ const ShareDialog = ({ mapId, onClose }: SimpleDialogProps): React.ReactElement
|
|||||||
<FormControlLabel
|
<FormControlLabel
|
||||||
value="start"
|
value="start"
|
||||||
onChange={(event, value) => {
|
onChange={(event, value) => {
|
||||||
setShowMessage(value)
|
setShowMessage(value);
|
||||||
}}
|
}}
|
||||||
style={{ fontSize: '5px' }}
|
style={{ fontSize: '5px' }}
|
||||||
control={<Checkbox color="primary" />}
|
control={<Checkbox color="primary" />}
|
||||||
@ -242,14 +242,14 @@ const ShareDialog = ({ mapId, onClose }: SimpleDialogProps): React.ReactElement
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
</ListItemSecondaryAction>
|
</ListItemSecondaryAction>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
)
|
);
|
||||||
})}
|
})}
|
||||||
</List>
|
</List>
|
||||||
</Paper>
|
</Paper>
|
||||||
)}
|
)}
|
||||||
</BaseDialog>
|
</BaseDialog>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
export default ShareDialog
|
export default ShareDialog;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import createStyles from '@material-ui/core/styles/createStyles'
|
import createStyles from '@material-ui/core/styles/createStyles';
|
||||||
import makeStyles from '@material-ui/core/styles/makeStyles'
|
import makeStyles from '@material-ui/core/styles/makeStyles';
|
||||||
|
|
||||||
export const useStyles = makeStyles(() =>
|
export const useStyles = makeStyles(() =>
|
||||||
createStyles({
|
createStyles({
|
||||||
@ -23,4 +23,4 @@ export const useStyles = makeStyles(() =>
|
|||||||
minWidth: '850px',
|
minWidth: '850px',
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
)
|
);
|
||||||
|
@ -1,30 +1,30 @@
|
|||||||
import React from 'react'
|
import React from 'react';
|
||||||
import { FormattedMessage, useIntl } from 'react-intl'
|
import { FormattedMessage, useIntl } from 'react-intl';
|
||||||
|
|
||||||
import Help from '@material-ui/icons/Help'
|
import Help from '@material-ui/icons/Help';
|
||||||
import PolicyOutlined from '@material-ui/icons/PolicyOutlined'
|
import PolicyOutlined from '@material-ui/icons/PolicyOutlined';
|
||||||
import FeedbackOutlined from '@material-ui/icons/FeedbackOutlined'
|
import FeedbackOutlined from '@material-ui/icons/FeedbackOutlined';
|
||||||
import EmojiPeopleOutlined from '@material-ui/icons/EmailOutlined'
|
import EmojiPeopleOutlined from '@material-ui/icons/EmailOutlined';
|
||||||
import EmailOutlined from '@material-ui/icons/EmailOutlined'
|
import EmailOutlined from '@material-ui/icons/EmailOutlined';
|
||||||
import IconButton from '@material-ui/core/IconButton'
|
import IconButton from '@material-ui/core/IconButton';
|
||||||
import Menu from '@material-ui/core/Menu'
|
import Menu from '@material-ui/core/Menu';
|
||||||
import MenuItem from '@material-ui/core/MenuItem'
|
import MenuItem from '@material-ui/core/MenuItem';
|
||||||
import Link from '@material-ui/core/Link'
|
import Link from '@material-ui/core/Link';
|
||||||
import ListItemIcon from '@material-ui/core/ListItemIcon'
|
import ListItemIcon from '@material-ui/core/ListItemIcon';
|
||||||
import Tooltip from '@material-ui/core/Tooltip'
|
import Tooltip from '@material-ui/core/Tooltip';
|
||||||
|
|
||||||
const HelpMenu = (): React.ReactElement => {
|
const HelpMenu = (): React.ReactElement => {
|
||||||
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null)
|
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
|
||||||
const open = Boolean(anchorEl)
|
const open = Boolean(anchorEl);
|
||||||
const intl = useIntl()
|
const intl = useIntl();
|
||||||
|
|
||||||
const handleMenu = (event: React.MouseEvent<HTMLElement>) => {
|
const handleMenu = (event: React.MouseEvent<HTMLElement>) => {
|
||||||
setAnchorEl(event.currentTarget)
|
setAnchorEl(event.currentTarget);
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
setAnchorEl(null)
|
setAnchorEl(null);
|
||||||
}
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<span>
|
<span>
|
||||||
@ -100,7 +100,7 @@ const HelpMenu = (): React.ReactElement => {
|
|||||||
</MenuItem>
|
</MenuItem>
|
||||||
</Menu>
|
</Menu>
|
||||||
</span>
|
</span>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
export default HelpMenu
|
export default HelpMenu;
|
||||||
|
@ -1,96 +1,96 @@
|
|||||||
import React, { ErrorInfo, ReactElement, useEffect } from 'react'
|
import React, { ErrorInfo, ReactElement, useEffect } from 'react';
|
||||||
import clsx from 'clsx'
|
import clsx from 'clsx';
|
||||||
import Drawer from '@material-ui/core/Drawer'
|
import Drawer from '@material-ui/core/Drawer';
|
||||||
import AppBar from '@material-ui/core/AppBar'
|
import AppBar from '@material-ui/core/AppBar';
|
||||||
import Toolbar from '@material-ui/core/Toolbar'
|
import Toolbar from '@material-ui/core/Toolbar';
|
||||||
import List from '@material-ui/core/List'
|
import List from '@material-ui/core/List';
|
||||||
import IconButton from '@material-ui/core/IconButton'
|
import IconButton from '@material-ui/core/IconButton';
|
||||||
import { useStyles } from './style'
|
import { useStyles } from './style';
|
||||||
import { MapsList } from './maps-list'
|
import { MapsList } from './maps-list';
|
||||||
import { FormattedMessage, IntlProvider, useIntl } from 'react-intl'
|
import { FormattedMessage, IntlProvider, useIntl } from 'react-intl';
|
||||||
import { useQuery, useMutation, useQueryClient } from 'react-query'
|
import { useQuery, useMutation, useQueryClient } from 'react-query';
|
||||||
import { activeInstance } from '../../redux/clientSlice'
|
import { activeInstance } from '../../redux/clientSlice';
|
||||||
import { useSelector } from 'react-redux'
|
import { useSelector } from 'react-redux';
|
||||||
import Client, { Label } from '../../classes/client'
|
import Client, { Label } from '../../classes/client';
|
||||||
import ActionDispatcher from './action-dispatcher'
|
import ActionDispatcher from './action-dispatcher';
|
||||||
import { ActionType } from './action-chooser'
|
import { ActionType } from './action-chooser';
|
||||||
import AccountMenu from './account-menu'
|
import AccountMenu from './account-menu';
|
||||||
import ClientHealthSentinel from '../../classes/client/client-health-sentinel'
|
import ClientHealthSentinel from '../../classes/client/client-health-sentinel';
|
||||||
import HelpMenu from './help-menu'
|
import HelpMenu from './help-menu';
|
||||||
import LanguageMenu from './language-menu'
|
import LanguageMenu from './language-menu';
|
||||||
import AppI18n, { Locales } from '../../classes/app-i18n'
|
import AppI18n, { Locales } from '../../classes/app-i18n';
|
||||||
|
|
||||||
import ListItemIcon from '@material-ui/core/ListItemIcon'
|
import ListItemIcon from '@material-ui/core/ListItemIcon';
|
||||||
import ListItem from '@material-ui/core/ListItem'
|
import ListItem from '@material-ui/core/ListItem';
|
||||||
|
|
||||||
import AddCircleTwoTone from '@material-ui/icons/AddCircleTwoTone'
|
import AddCircleTwoTone from '@material-ui/icons/AddCircleTwoTone';
|
||||||
import CloudUploadTwoTone from '@material-ui/icons/CloudUploadTwoTone'
|
import CloudUploadTwoTone from '@material-ui/icons/CloudUploadTwoTone';
|
||||||
import DeleteOutlineTwoTone from '@material-ui/icons/DeleteOutlineTwoTone'
|
import DeleteOutlineTwoTone from '@material-ui/icons/DeleteOutlineTwoTone';
|
||||||
import LabelTwoTone from '@material-ui/icons/LabelTwoTone'
|
import LabelTwoTone from '@material-ui/icons/LabelTwoTone';
|
||||||
import PersonOutlineTwoTone from '@material-ui/icons/PersonOutlineTwoTone'
|
import PersonOutlineTwoTone from '@material-ui/icons/PersonOutlineTwoTone';
|
||||||
import PublicTwoTone from '@material-ui/icons/PublicTwoTone'
|
import PublicTwoTone from '@material-ui/icons/PublicTwoTone';
|
||||||
import ScatterPlotTwoTone from '@material-ui/icons/ScatterPlotTwoTone'
|
import ScatterPlotTwoTone from '@material-ui/icons/ScatterPlotTwoTone';
|
||||||
import ShareTwoTone from '@material-ui/icons/ShareTwoTone'
|
import ShareTwoTone from '@material-ui/icons/ShareTwoTone';
|
||||||
import StarTwoTone from '@material-ui/icons/StarTwoTone'
|
import StarTwoTone from '@material-ui/icons/StarTwoTone';
|
||||||
import Tooltip from '@material-ui/core/Tooltip'
|
import Tooltip from '@material-ui/core/Tooltip';
|
||||||
import Button from '@material-ui/core/Button'
|
import Button from '@material-ui/core/Button';
|
||||||
import Link from '@material-ui/core/Link'
|
import Link from '@material-ui/core/Link';
|
||||||
import ListItemText from '@material-ui/core/ListItemText'
|
import ListItemText from '@material-ui/core/ListItemText';
|
||||||
import ListItemSecondaryAction from '@material-ui/core/ListItemSecondaryAction'
|
import ListItemSecondaryAction from '@material-ui/core/ListItemSecondaryAction';
|
||||||
|
|
||||||
import logoIcon from '../../images/logo-small.svg'
|
import logoIcon from '../../images/logo-small.svg';
|
||||||
import poweredByIcon from '../../images/pwrdby-white.svg'
|
import poweredByIcon from '../../images/pwrdby-white.svg';
|
||||||
|
|
||||||
export type Filter = GenericFilter | LabelFilter
|
export type Filter = GenericFilter | LabelFilter;
|
||||||
|
|
||||||
export interface GenericFilter {
|
export interface GenericFilter {
|
||||||
type: 'public' | 'all' | 'starred' | 'shared' | 'label' | 'owned'
|
type: 'public' | 'all' | 'starred' | 'shared' | 'label' | 'owned';
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LabelFilter {
|
export interface LabelFilter {
|
||||||
type: 'label'
|
type: 'label';
|
||||||
label: Label
|
label: Label;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ToolbarButtonInfo {
|
interface ToolbarButtonInfo {
|
||||||
filter: GenericFilter | LabelFilter
|
filter: GenericFilter | LabelFilter;
|
||||||
label: string
|
label: string;
|
||||||
icon: React.ReactElement
|
icon: React.ReactElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
const MapsPage = (): ReactElement => {
|
const MapsPage = (): ReactElement => {
|
||||||
const classes = useStyles()
|
const classes = useStyles();
|
||||||
const [filter, setFilter] = React.useState<Filter>({ type: 'all' })
|
const [filter, setFilter] = React.useState<Filter>({ type: 'all' });
|
||||||
const client: Client = useSelector(activeInstance)
|
const client: Client = useSelector(activeInstance);
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient();
|
||||||
const [activeDialog, setActiveDialog] = React.useState<ActionType | undefined>(undefined)
|
const [activeDialog, setActiveDialog] = React.useState<ActionType | undefined>(undefined);
|
||||||
const intl = useIntl()
|
const intl = useIntl();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
document.title = 'Maps | WiseMapping'
|
document.title = 'Maps | WiseMapping';
|
||||||
}, [])
|
}, []);
|
||||||
|
|
||||||
const mutation = useMutation((id: number) => client.deleteLabel(id), {
|
const mutation = useMutation((id: number) => client.deleteLabel(id), {
|
||||||
onSuccess: () => queryClient.invalidateQueries('labels'),
|
onSuccess: () => queryClient.invalidateQueries('labels'),
|
||||||
onError: (error) => {
|
onError: (error) => {
|
||||||
console.error(`Unexpected error ${error}`)
|
console.error(`Unexpected error ${error}`);
|
||||||
},
|
},
|
||||||
})
|
});
|
||||||
|
|
||||||
const handleMenuClick = (filter: Filter) => {
|
const handleMenuClick = (filter: Filter) => {
|
||||||
queryClient.invalidateQueries('maps')
|
queryClient.invalidateQueries('maps');
|
||||||
setFilter(filter)
|
setFilter(filter);
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleLabelDelete = (id: number) => {
|
const handleLabelDelete = (id: number) => {
|
||||||
mutation.mutate(id)
|
mutation.mutate(id);
|
||||||
}
|
};
|
||||||
|
|
||||||
const { data } = useQuery<unknown, ErrorInfo, Label[]>('labels', () => {
|
const { data } = useQuery<unknown, ErrorInfo, Label[]>('labels', () => {
|
||||||
return client.fetchLabels()
|
return client.fetchLabels();
|
||||||
})
|
});
|
||||||
|
|
||||||
const labels: Label[] = data ? data : []
|
const labels: Label[] = data ? data : [];
|
||||||
const filterButtons: ToolbarButtonInfo[] = [
|
const filterButtons: ToolbarButtonInfo[] = [
|
||||||
{
|
{
|
||||||
filter: { type: 'all' },
|
filter: { type: 'all' },
|
||||||
@ -117,7 +117,7 @@ const MapsPage = (): ReactElement => {
|
|||||||
label: 'Public',
|
label: 'Public',
|
||||||
icon: <PublicTwoTone color="secondary" />,
|
icon: <PublicTwoTone color="secondary" />,
|
||||||
},
|
},
|
||||||
]
|
];
|
||||||
|
|
||||||
labels.forEach((l) =>
|
labels.forEach((l) =>
|
||||||
filterButtons.push({
|
filterButtons.push({
|
||||||
@ -125,11 +125,11 @@ const MapsPage = (): ReactElement => {
|
|||||||
label: l.title,
|
label: l.title,
|
||||||
icon: <LabelTwoTone style={{ color: l.color ? l.color : 'inherit' }} />,
|
icon: <LabelTwoTone style={{ color: l.color ? l.color : 'inherit' }} />,
|
||||||
})
|
})
|
||||||
)
|
);
|
||||||
|
|
||||||
// Configure using user settings ...
|
// Configure using user settings ...
|
||||||
const appi18n = new AppI18n()
|
const appi18n = new AppI18n();
|
||||||
const userLocale = appi18n.getUserLocale()
|
const userLocale = appi18n.getUserLocale();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<IntlProvider
|
<IntlProvider
|
||||||
@ -232,7 +232,7 @@ const MapsPage = (): ReactElement => {
|
|||||||
(buttonInfo.filter as LabelFilter).label
|
(buttonInfo.filter as LabelFilter).label
|
||||||
}`}
|
}`}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
})}
|
})}
|
||||||
</List>
|
</List>
|
||||||
|
|
||||||
@ -251,46 +251,46 @@ const MapsPage = (): ReactElement => {
|
|||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
</IntlProvider>
|
</IntlProvider>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
interface ListItemProps {
|
interface ListItemProps {
|
||||||
icon: React.ReactElement
|
icon: React.ReactElement;
|
||||||
label: string
|
label: string;
|
||||||
filter: Filter
|
filter: Filter;
|
||||||
active?: Filter
|
active?: Filter;
|
||||||
onClick: (filter: Filter) => void
|
onClick: (filter: Filter) => void;
|
||||||
onDelete?: (id: number) => void
|
onDelete?: (id: number) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const StyleListItem = (props: ListItemProps) => {
|
const StyleListItem = (props: ListItemProps) => {
|
||||||
const icon = props.icon
|
const icon = props.icon;
|
||||||
const label = props.label
|
const label = props.label;
|
||||||
const filter = props.filter
|
const filter = props.filter;
|
||||||
const activeFilter = props.active
|
const activeFilter = props.active;
|
||||||
const onClick = props.onClick
|
const onClick = props.onClick;
|
||||||
const onDeleteLabel = props.onDelete
|
const onDeleteLabel = props.onDelete;
|
||||||
const isSelected =
|
const isSelected =
|
||||||
activeFilter &&
|
activeFilter &&
|
||||||
activeFilter.type == filter.type &&
|
activeFilter.type == filter.type &&
|
||||||
(activeFilter.type != 'label' ||
|
(activeFilter.type != 'label' ||
|
||||||
(activeFilter as LabelFilter).label == (filter as LabelFilter).label)
|
(activeFilter as LabelFilter).label == (filter as LabelFilter).label);
|
||||||
|
|
||||||
const handleOnClick = (event: React.MouseEvent<HTMLDivElement, MouseEvent>, filter: Filter) => {
|
const handleOnClick = (event: React.MouseEvent<HTMLDivElement, MouseEvent>, filter: Filter) => {
|
||||||
event.stopPropagation()
|
event.stopPropagation();
|
||||||
onClick(filter)
|
onClick(filter);
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleOnDelete = (
|
const handleOnDelete = (
|
||||||
event: React.MouseEvent<HTMLButtonElement, MouseEvent>,
|
event: React.MouseEvent<HTMLButtonElement, MouseEvent>,
|
||||||
filter: Filter
|
filter: Filter
|
||||||
) => {
|
) => {
|
||||||
event.stopPropagation()
|
event.stopPropagation();
|
||||||
if (!onDeleteLabel) {
|
if (!onDeleteLabel) {
|
||||||
throw 'Illegal state exeption'
|
throw 'Illegal state exeption';
|
||||||
}
|
|
||||||
onDeleteLabel((filter as LabelFilter).label.id)
|
|
||||||
}
|
}
|
||||||
|
onDeleteLabel((filter as LabelFilter).label.id);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ListItem button selected={isSelected} onClick={(e) => handleOnClick(e, filter)}>
|
<ListItem button selected={isSelected} onClick={(e) => handleOnClick(e, filter)}>
|
||||||
@ -308,7 +308,7 @@ const StyleListItem = (props: ListItemProps) => {
|
|||||||
</ListItemSecondaryAction>
|
</ListItemSecondaryAction>
|
||||||
)}
|
)}
|
||||||
</ListItem>
|
</ListItem>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
export default MapsPage
|
export default MapsPage;
|
||||||
|
@ -1,55 +1,55 @@
|
|||||||
import TranslateTwoTone from '@material-ui/icons/TranslateTwoTone'
|
import TranslateTwoTone from '@material-ui/icons/TranslateTwoTone';
|
||||||
import React from 'react'
|
import React from 'react';
|
||||||
import { useMutation, useQueryClient } from 'react-query'
|
import { useMutation, useQueryClient } from 'react-query';
|
||||||
import Client from '../../../classes/client'
|
import Client from '../../../classes/client';
|
||||||
import { useSelector } from 'react-redux'
|
import { useSelector } from 'react-redux';
|
||||||
import { activeInstance, fetchAccount } from '../../../redux/clientSlice'
|
import { activeInstance, fetchAccount } from '../../../redux/clientSlice';
|
||||||
import { FormattedMessage, useIntl } from 'react-intl'
|
import { FormattedMessage, useIntl } from 'react-intl';
|
||||||
import { LocaleCode, Locales } from '../../../classes/app-i18n'
|
import { LocaleCode, Locales } from '../../../classes/app-i18n';
|
||||||
import Tooltip from '@material-ui/core/Tooltip'
|
import Tooltip from '@material-ui/core/Tooltip';
|
||||||
import Button from '@material-ui/core/Button'
|
import Button from '@material-ui/core/Button';
|
||||||
import Menu from '@material-ui/core/Menu'
|
import Menu from '@material-ui/core/Menu';
|
||||||
import MenuItem from '@material-ui/core/MenuItem'
|
import MenuItem from '@material-ui/core/MenuItem';
|
||||||
import Dialog from '@material-ui/core/Dialog'
|
import Dialog from '@material-ui/core/Dialog';
|
||||||
import DialogTitle from '@material-ui/core/DialogTitle'
|
import DialogTitle from '@material-ui/core/DialogTitle';
|
||||||
import DialogContent from '@material-ui/core/DialogContent'
|
import DialogContent from '@material-ui/core/DialogContent';
|
||||||
import DialogContentText from '@material-ui/core/DialogContentText'
|
import DialogContentText from '@material-ui/core/DialogContentText';
|
||||||
import DialogActions from '@material-ui/core/DialogActions'
|
import DialogActions from '@material-ui/core/DialogActions';
|
||||||
import Divider from '@material-ui/core/Divider'
|
import Divider from '@material-ui/core/Divider';
|
||||||
|
|
||||||
const LanguageMenu = (): React.ReactElement => {
|
const LanguageMenu = (): React.ReactElement => {
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient();
|
||||||
const client: Client = useSelector(activeInstance)
|
const client: Client = useSelector(activeInstance);
|
||||||
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null)
|
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
|
||||||
const [openHelpDialog, setHelpDialogOpen] = React.useState<boolean>(false)
|
const [openHelpDialog, setHelpDialogOpen] = React.useState<boolean>(false);
|
||||||
|
|
||||||
const open = Boolean(anchorEl)
|
const open = Boolean(anchorEl);
|
||||||
const intl = useIntl()
|
const intl = useIntl();
|
||||||
|
|
||||||
const mutation = useMutation((locale: LocaleCode) => client.updateAccountLanguage(locale), {
|
const mutation = useMutation((locale: LocaleCode) => client.updateAccountLanguage(locale), {
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
queryClient.invalidateQueries('account')
|
queryClient.invalidateQueries('account');
|
||||||
handleClose()
|
handleClose();
|
||||||
},
|
},
|
||||||
onError: (error) => {
|
onError: (error) => {
|
||||||
console.error(`Unexpected error ${error}`)
|
console.error(`Unexpected error ${error}`);
|
||||||
},
|
},
|
||||||
})
|
});
|
||||||
|
|
||||||
const handleMenu = (event: React.MouseEvent<HTMLElement>) => {
|
const handleMenu = (event: React.MouseEvent<HTMLElement>) => {
|
||||||
setAnchorEl(event.currentTarget)
|
setAnchorEl(event.currentTarget);
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
setAnchorEl(null)
|
setAnchorEl(null);
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleOnClick = (event: React.MouseEvent<HTMLElement>) => {
|
const handleOnClick = (event: React.MouseEvent<HTMLElement>) => {
|
||||||
const localeCode = event.target['id']
|
const localeCode = event.target['id'];
|
||||||
mutation.mutate(localeCode)
|
mutation.mutate(localeCode);
|
||||||
}
|
};
|
||||||
|
|
||||||
const accountInfo = fetchAccount()
|
const accountInfo = fetchAccount();
|
||||||
return (
|
return (
|
||||||
<span>
|
<span>
|
||||||
<Tooltip
|
<Tooltip
|
||||||
@ -106,8 +106,8 @@ const LanguageMenu = (): React.ReactElement => {
|
|||||||
|
|
||||||
<MenuItem
|
<MenuItem
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
handleClose()
|
handleClose();
|
||||||
setHelpDialogOpen(true)
|
setHelpDialogOpen(true);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<FormattedMessage id="language.help" defaultMessage="Help to Translate" />
|
<FormattedMessage id="language.help" defaultMessage="Help to Translate" />
|
||||||
@ -115,12 +115,12 @@ const LanguageMenu = (): React.ReactElement => {
|
|||||||
</Menu>
|
</Menu>
|
||||||
{openHelpDialog && <HelpUsToTranslateDialog onClose={() => setHelpDialogOpen(false)} />}
|
{openHelpDialog && <HelpUsToTranslateDialog onClose={() => setHelpDialogOpen(false)} />}
|
||||||
</span>
|
</span>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
type HelpUsToTranslateDialogProp = {
|
type HelpUsToTranslateDialogProp = {
|
||||||
onClose: () => void
|
onClose: () => void;
|
||||||
}
|
};
|
||||||
const HelpUsToTranslateDialog = ({ onClose }: HelpUsToTranslateDialogProp) => {
|
const HelpUsToTranslateDialog = ({ onClose }: HelpUsToTranslateDialogProp) => {
|
||||||
return (
|
return (
|
||||||
<Dialog open={true} onClose={onClose}>
|
<Dialog open={true} onClose={onClose}>
|
||||||
@ -137,7 +137,7 @@ const HelpUsToTranslateDialog = ({ onClose }: HelpUsToTranslateDialogProp) => {
|
|||||||
</Button>
|
</Button>
|
||||||
</DialogActions>
|
</DialogActions>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
export default LanguageMenu
|
export default LanguageMenu;
|
||||||
|
@ -1,54 +1,54 @@
|
|||||||
import React, { useEffect, CSSProperties } from 'react'
|
import React, { useEffect, CSSProperties } from 'react';
|
||||||
|
|
||||||
import { useStyles } from './styled'
|
import { useStyles } from './styled';
|
||||||
import { useSelector } from 'react-redux'
|
import { useSelector } from 'react-redux';
|
||||||
import { activeInstance, fetchAccount } from '../../../redux/clientSlice'
|
import { activeInstance, fetchAccount } from '../../../redux/clientSlice';
|
||||||
import { useMutation, useQuery, useQueryClient } from 'react-query'
|
import { useMutation, useQuery, useQueryClient } from 'react-query';
|
||||||
import Client, { ErrorInfo, MapInfo } from '../../../classes/client'
|
import Client, { ErrorInfo, MapInfo } from '../../../classes/client';
|
||||||
import ActionChooser, { ActionType } from '../action-chooser'
|
import ActionChooser, { ActionType } from '../action-chooser';
|
||||||
import ActionDispatcher from '../action-dispatcher'
|
import ActionDispatcher from '../action-dispatcher';
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs';
|
||||||
import { Filter, LabelFilter } from '..'
|
import { Filter, LabelFilter } from '..';
|
||||||
import { FormattedMessage, useIntl } from 'react-intl'
|
import { FormattedMessage, useIntl } from 'react-intl';
|
||||||
|
|
||||||
import Table from '@material-ui/core/Table'
|
import Table from '@material-ui/core/Table';
|
||||||
import TableBody from '@material-ui/core/TableBody'
|
import TableBody from '@material-ui/core/TableBody';
|
||||||
import TableCell from '@material-ui/core/TableCell'
|
import TableCell from '@material-ui/core/TableCell';
|
||||||
import TableContainer from '@material-ui/core/TableContainer'
|
import TableContainer from '@material-ui/core/TableContainer';
|
||||||
import TableHead from '@material-ui/core/TableHead'
|
import TableHead from '@material-ui/core/TableHead';
|
||||||
import TablePagination from '@material-ui/core/TablePagination'
|
import TablePagination from '@material-ui/core/TablePagination';
|
||||||
import TableRow from '@material-ui/core/TableRow'
|
import TableRow from '@material-ui/core/TableRow';
|
||||||
import TableSortLabel from '@material-ui/core/TableSortLabel'
|
import TableSortLabel from '@material-ui/core/TableSortLabel';
|
||||||
import Toolbar from '@material-ui/core/Toolbar'
|
import Toolbar from '@material-ui/core/Toolbar';
|
||||||
import Paper from '@material-ui/core/Paper'
|
import Paper from '@material-ui/core/Paper';
|
||||||
import Checkbox from '@material-ui/core/Checkbox'
|
import Checkbox from '@material-ui/core/Checkbox';
|
||||||
import IconButton from '@material-ui/core/IconButton'
|
import IconButton from '@material-ui/core/IconButton';
|
||||||
import Tooltip from '@material-ui/core/Tooltip'
|
import Tooltip from '@material-ui/core/Tooltip';
|
||||||
import Button from '@material-ui/core/Button'
|
import Button from '@material-ui/core/Button';
|
||||||
import InputBase from '@material-ui/core/InputBase'
|
import InputBase from '@material-ui/core/InputBase';
|
||||||
import Link from '@material-ui/core/Link'
|
import Link from '@material-ui/core/Link';
|
||||||
|
|
||||||
import LabelTwoTone from '@material-ui/icons/LabelTwoTone'
|
import LabelTwoTone from '@material-ui/icons/LabelTwoTone';
|
||||||
import DeleteOutlined from '@material-ui/icons/DeleteOutlined'
|
import DeleteOutlined from '@material-ui/icons/DeleteOutlined';
|
||||||
import MoreHorizIcon from '@material-ui/icons/MoreHoriz'
|
import MoreHorizIcon from '@material-ui/icons/MoreHoriz';
|
||||||
import StarRateRoundedIcon from '@material-ui/icons/StarRateRounded'
|
import StarRateRoundedIcon from '@material-ui/icons/StarRateRounded';
|
||||||
import SearchIcon from '@material-ui/icons/Search'
|
import SearchIcon from '@material-ui/icons/Search';
|
||||||
|
|
||||||
// Load fromNow pluggin
|
// Load fromNow pluggin
|
||||||
import relativeTime from 'dayjs/plugin/relativeTime'
|
import relativeTime from 'dayjs/plugin/relativeTime';
|
||||||
dayjs.extend(relativeTime)
|
dayjs.extend(relativeTime);
|
||||||
|
|
||||||
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]) {
|
||||||
return -1
|
return -1;
|
||||||
}
|
}
|
||||||
if (b[orderBy] > a[orderBy]) {
|
if (b[orderBy] > a[orderBy]) {
|
||||||
return 1
|
return 1;
|
||||||
}
|
}
|
||||||
return 0
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
type Order = 'asc' | 'desc'
|
type Order = 'asc' | 'desc';
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
function getComparator<Key extends keyof any>(
|
function getComparator<Key extends keyof any>(
|
||||||
@ -60,38 +60,38 @@ function getComparator<Key extends keyof any>(
|
|||||||
) => number {
|
) => number {
|
||||||
return order === 'desc'
|
return order === 'desc'
|
||||||
? (a, b) => descendingComparator(a, b, orderBy)
|
? (a, b) => descendingComparator(a, b, orderBy)
|
||||||
: (a, b) => -descendingComparator(a, b, orderBy)
|
: (a, b) => -descendingComparator(a, b, orderBy);
|
||||||
}
|
}
|
||||||
|
|
||||||
function stableSort<T>(array: T[], comparator: (a: T, b: T) => number) {
|
function stableSort<T>(array: T[], comparator: (a: T, b: T) => number) {
|
||||||
const stabilizedThis = array.map((el, index) => [el, index] as [T, number])
|
const stabilizedThis = array.map((el, index) => [el, index] as [T, number]);
|
||||||
stabilizedThis.sort((a, b) => {
|
stabilizedThis.sort((a, b) => {
|
||||||
const order = comparator(a[0], b[0])
|
const order = comparator(a[0], b[0]);
|
||||||
if (order !== 0) return order
|
if (order !== 0) return order;
|
||||||
return a[1] - b[1]
|
return a[1] - b[1];
|
||||||
})
|
});
|
||||||
return stabilizedThis.map((el) => el[0])
|
return stabilizedThis.map((el) => el[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
interface HeadCell {
|
interface HeadCell {
|
||||||
id: keyof MapInfo
|
id: keyof MapInfo;
|
||||||
label?: string
|
label?: string;
|
||||||
numeric: boolean
|
numeric: boolean;
|
||||||
style?: CSSProperties
|
style?: CSSProperties;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface EnhancedTableProps {
|
interface EnhancedTableProps {
|
||||||
classes: ReturnType<typeof useStyles>
|
classes: ReturnType<typeof useStyles>;
|
||||||
numSelected: number
|
numSelected: number;
|
||||||
onRequestSort: (event: React.MouseEvent<unknown>, property: keyof MapInfo) => void
|
onRequestSort: (event: React.MouseEvent<unknown>, property: keyof MapInfo) => void;
|
||||||
onSelectAllClick: (event: React.ChangeEvent<HTMLInputElement>) => void
|
onSelectAllClick: (event: React.ChangeEvent<HTMLInputElement>) => void;
|
||||||
order: Order
|
order: Order;
|
||||||
orderBy: string
|
orderBy: string;
|
||||||
rowCount: number
|
rowCount: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
function EnhancedTableHead(props: EnhancedTableProps) {
|
function EnhancedTableHead(props: EnhancedTableProps) {
|
||||||
const intl = useIntl()
|
const intl = useIntl();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
classes,
|
classes,
|
||||||
@ -101,11 +101,11 @@ function EnhancedTableHead(props: EnhancedTableProps) {
|
|||||||
numSelected,
|
numSelected,
|
||||||
rowCount,
|
rowCount,
|
||||||
onRequestSort,
|
onRequestSort,
|
||||||
} = props
|
} = 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);
|
||||||
}
|
};
|
||||||
|
|
||||||
const headCells: HeadCell[] = [
|
const headCells: HeadCell[] = [
|
||||||
{
|
{
|
||||||
@ -126,7 +126,7 @@ function EnhancedTableHead(props: EnhancedTableProps) {
|
|||||||
label: intl.formatMessage({ id: 'map.last-update', defaultMessage: 'Last Update' }),
|
label: intl.formatMessage({ id: 'map.last-update', defaultMessage: 'Last Update' }),
|
||||||
style: { width: '70px', whiteSpace: 'nowrap' },
|
style: { width: '70px', whiteSpace: 'nowrap' },
|
||||||
},
|
},
|
||||||
]
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TableHead>
|
<TableHead>
|
||||||
@ -176,7 +176,7 @@ function EnhancedTableHead(props: EnhancedTableProps) {
|
|||||||
)}
|
)}
|
||||||
</TableSortLabel>
|
</TableSortLabel>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
)
|
);
|
||||||
})}
|
})}
|
||||||
|
|
||||||
<TableCell
|
<TableCell
|
||||||
@ -186,195 +186,195 @@ function EnhancedTableHead(props: EnhancedTableProps) {
|
|||||||
></TableCell>
|
></TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
</TableHead>
|
</TableHead>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
type ActionPanelState = {
|
type ActionPanelState = {
|
||||||
el: HTMLElement | undefined
|
el: HTMLElement | undefined;
|
||||||
mapId: number
|
mapId: number;
|
||||||
}
|
};
|
||||||
|
|
||||||
interface MapsListProps {
|
interface MapsListProps {
|
||||||
filter: Filter
|
filter: Filter;
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapsFilter = (filter: Filter, search: string): ((mapInfo: MapInfo) => boolean) => {
|
const mapsFilter = (filter: Filter, search: string): ((mapInfo: MapInfo) => boolean) => {
|
||||||
return (mapInfo: MapInfo) => {
|
return (mapInfo: MapInfo) => {
|
||||||
// Check for filter condition
|
// Check for filter condition
|
||||||
let result = false
|
let result = false;
|
||||||
switch (filter.type) {
|
switch (filter.type) {
|
||||||
case 'all':
|
case 'all':
|
||||||
result = true
|
result = true;
|
||||||
break
|
break;
|
||||||
case 'starred':
|
case 'starred':
|
||||||
result = mapInfo.starred
|
result = mapInfo.starred;
|
||||||
break
|
break;
|
||||||
case 'owned':
|
case 'owned':
|
||||||
result = mapInfo.role == 'owner'
|
result = mapInfo.role == 'owner';
|
||||||
break
|
break;
|
||||||
case 'shared':
|
case 'shared':
|
||||||
result = mapInfo.role != 'owner'
|
result = mapInfo.role != 'owner';
|
||||||
break
|
break;
|
||||||
case 'label':
|
case 'label':
|
||||||
result =
|
result =
|
||||||
!mapInfo.labels || mapInfo.labels.includes((filter as LabelFilter).label.id)
|
!mapInfo.labels || mapInfo.labels.includes((filter as LabelFilter).label.id);
|
||||||
break
|
break;
|
||||||
case 'public':
|
case 'public':
|
||||||
result = mapInfo.isPublic
|
result = mapInfo.isPublic;
|
||||||
break
|
break;
|
||||||
default:
|
default:
|
||||||
result = false
|
result = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Does it match search filter criteria...
|
// Does it match search filter criteria...
|
||||||
if (search && result) {
|
if (search && result) {
|
||||||
result = mapInfo.title.toLowerCase().indexOf(search.toLowerCase()) != -1
|
result = mapInfo.title.toLowerCase().indexOf(search.toLowerCase()) != -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result;
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export const MapsList = (props: MapsListProps): React.ReactElement => {
|
export const MapsList = (props: MapsListProps): React.ReactElement => {
|
||||||
const classes = useStyles()
|
const classes = useStyles();
|
||||||
const [order, setOrder] = React.useState<Order>('asc')
|
const [order, setOrder] = React.useState<Order>('asc');
|
||||||
const [filter, setFilter] = React.useState<Filter>({ type: 'all' })
|
const [filter, setFilter] = React.useState<Filter>({ type: 'all' });
|
||||||
|
|
||||||
const [orderBy, setOrderBy] = React.useState<keyof MapInfo>('lastModificationTime')
|
const [orderBy, setOrderBy] = React.useState<keyof MapInfo>('lastModificationTime');
|
||||||
const [selected, setSelected] = React.useState<number[]>([])
|
const [selected, setSelected] = React.useState<number[]>([]);
|
||||||
const [searchCondition, setSearchCondition] = React.useState<string>('')
|
const [searchCondition, setSearchCondition] = React.useState<string>('');
|
||||||
|
|
||||||
const [page, setPage] = React.useState(0)
|
const [page, setPage] = React.useState(0);
|
||||||
const [rowsPerPage, setRowsPerPage] = React.useState(10)
|
const [rowsPerPage, setRowsPerPage] = React.useState(10);
|
||||||
const client: Client = useSelector(activeInstance)
|
const client: Client = useSelector(activeInstance);
|
||||||
const intl = useIntl()
|
const intl = useIntl();
|
||||||
|
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
// Configure locale ...
|
// Configure locale ...
|
||||||
const account = fetchAccount()
|
const account = fetchAccount();
|
||||||
if (account) {
|
if (account) {
|
||||||
dayjs.locale(account.locale.code)
|
dayjs.locale(account.locale.code);
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setSelected([])
|
setSelected([]);
|
||||||
setPage(0)
|
setPage(0);
|
||||||
setFilter(props.filter)
|
setFilter(props.filter);
|
||||||
}, [props.filter.type, (props.filter as LabelFilter).label])
|
}, [props.filter.type, (props.filter as LabelFilter).label]);
|
||||||
|
|
||||||
const { isLoading, data } = useQuery<unknown, ErrorInfo, MapInfo[]>('maps', () => {
|
const { isLoading, data } = useQuery<unknown, ErrorInfo, MapInfo[]>('maps', () => {
|
||||||
return client.fetchAllMaps()
|
return client.fetchAllMaps();
|
||||||
})
|
});
|
||||||
const mapsInfo: MapInfo[] = data ? data.filter(mapsFilter(filter, searchCondition)) : []
|
const mapsInfo: MapInfo[] = data ? data.filter(mapsFilter(filter, searchCondition)) : [];
|
||||||
|
|
||||||
const [activeRowAction, setActiveRowAction] = React.useState<ActionPanelState | undefined>(
|
const [activeRowAction, setActiveRowAction] = React.useState<ActionPanelState | undefined>(
|
||||||
undefined
|
undefined
|
||||||
)
|
);
|
||||||
type ActiveDialog = {
|
type ActiveDialog = {
|
||||||
actionType: ActionType
|
actionType: ActionType;
|
||||||
mapsId: number[]
|
mapsId: number[];
|
||||||
}
|
};
|
||||||
|
|
||||||
const [activeDialog, setActiveDialog] = React.useState<ActiveDialog | undefined>(undefined)
|
const [activeDialog, setActiveDialog] = React.useState<ActiveDialog | undefined>(undefined);
|
||||||
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');
|
||||||
setOrderBy(property)
|
setOrderBy(property);
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleSelectAllClick = (event: React.ChangeEvent<HTMLInputElement>): void => {
|
const handleSelectAllClick = (event: React.ChangeEvent<HTMLInputElement>): void => {
|
||||||
if (event.target.checked) {
|
if (event.target.checked) {
|
||||||
const newSelecteds = mapsInfo.map((n) => n.id)
|
const newSelecteds = mapsInfo.map((n) => n.id);
|
||||||
setSelected(newSelecteds)
|
setSelected(newSelecteds);
|
||||||
return
|
return;
|
||||||
}
|
|
||||||
setSelected([])
|
|
||||||
}
|
}
|
||||||
|
setSelected([]);
|
||||||
|
};
|
||||||
|
|
||||||
const handleRowClick = (event: React.MouseEvent<unknown>, id: number): void => {
|
const handleRowClick = (event: React.MouseEvent<unknown>, id: number): void => {
|
||||||
const selectedIndex = selected.indexOf(id)
|
const selectedIndex = selected.indexOf(id);
|
||||||
let newSelected: number[] = []
|
let newSelected: number[] = [];
|
||||||
|
|
||||||
if (selectedIndex === -1) {
|
if (selectedIndex === -1) {
|
||||||
newSelected = newSelected.concat(selected, id)
|
newSelected = newSelected.concat(selected, id);
|
||||||
} else if (selectedIndex === 0) {
|
} else if (selectedIndex === 0) {
|
||||||
newSelected = newSelected.concat(selected.slice(1))
|
newSelected = newSelected.concat(selected.slice(1));
|
||||||
} else if (selectedIndex === selected.length - 1) {
|
} else if (selectedIndex === selected.length - 1) {
|
||||||
newSelected = newSelected.concat(selected.slice(0, -1))
|
newSelected = newSelected.concat(selected.slice(0, -1));
|
||||||
} else if (selectedIndex > 0) {
|
} else if (selectedIndex > 0) {
|
||||||
newSelected = newSelected.concat(
|
newSelected = newSelected.concat(
|
||||||
selected.slice(0, selectedIndex),
|
selected.slice(0, selectedIndex),
|
||||||
selected.slice(selectedIndex + 1)
|
selected.slice(selectedIndex + 1)
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
setSelected(newSelected)
|
setSelected(newSelected);
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleChangePage = (event: unknown, newPage: number) => {
|
const handleChangePage = (event: unknown, newPage: number) => {
|
||||||
setPage(newPage)
|
setPage(newPage);
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleChangeRowsPerPage = (event: React.ChangeEvent<HTMLInputElement>) => {
|
const handleChangeRowsPerPage = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
setRowsPerPage(parseInt(event.target.value, 10))
|
setRowsPerPage(parseInt(event.target.value, 10));
|
||||||
setPage(0)
|
setPage(0);
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleActionClick = (mapId: number): ((event) => void) => {
|
const handleActionClick = (mapId: number): ((event) => void) => {
|
||||||
return (event): void => {
|
return (event): void => {
|
||||||
setActiveRowAction({
|
setActiveRowAction({
|
||||||
mapId: mapId,
|
mapId: mapId,
|
||||||
el: event.currentTarget,
|
el: event.currentTarget,
|
||||||
})
|
});
|
||||||
event.stopPropagation()
|
event.stopPropagation();
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
const starredMultation = useMutation<void, ErrorInfo, number>(
|
const starredMultation = useMutation<void, ErrorInfo, number>(
|
||||||
(id: number) => {
|
(id: number) => {
|
||||||
const map = mapsInfo.find((m) => m.id == id)
|
const map = mapsInfo.find((m) => m.id == id);
|
||||||
return client.updateStarred(id, !map?.starred)
|
return client.updateStarred(id, !map?.starred);
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
queryClient.invalidateQueries('maps')
|
queryClient.invalidateQueries('maps');
|
||||||
},
|
},
|
||||||
onError: () => {
|
onError: () => {
|
||||||
// setError(error);
|
// setError(error);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
)
|
);
|
||||||
|
|
||||||
const handleStarred = (event: React.MouseEvent<HTMLButtonElement, MouseEvent>, id: number) => {
|
const handleStarred = (event: React.MouseEvent<HTMLButtonElement, MouseEvent>, id: number) => {
|
||||||
event.stopPropagation()
|
event.stopPropagation();
|
||||||
starredMultation.mutate(id)
|
starredMultation.mutate(id);
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleActionMenuClose = (action: ActionType): void => {
|
const handleActionMenuClose = (action: ActionType): void => {
|
||||||
if (action) {
|
if (action) {
|
||||||
const mapId = activeRowAction?.mapId
|
const mapId = activeRowAction?.mapId;
|
||||||
|
|
||||||
setActiveDialog({
|
setActiveDialog({
|
||||||
actionType: action as ActionType,
|
actionType: action as ActionType,
|
||||||
mapsId: [mapId] as number[],
|
mapsId: [mapId] as number[],
|
||||||
})
|
});
|
||||||
}
|
|
||||||
setActiveRowAction(undefined)
|
|
||||||
}
|
}
|
||||||
|
setActiveRowAction(undefined);
|
||||||
|
};
|
||||||
|
|
||||||
const handleOnSearchChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
const handleOnSearchChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
setSearchCondition(e.target.value)
|
setSearchCondition(e.target.value);
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleDeleteClick = () => {
|
const handleDeleteClick = () => {
|
||||||
setActiveDialog({
|
setActiveDialog({
|
||||||
actionType: 'delete',
|
actionType: 'delete',
|
||||||
mapsId: selected,
|
mapsId: selected,
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
const isSelected = (id: number) => selected.indexOf(id) !== -1
|
const isSelected = (id: number) => selected.indexOf(id) !== -1;
|
||||||
return (
|
return (
|
||||||
<div className={classes.root}>
|
<div className={classes.root}>
|
||||||
<ActionChooser
|
<ActionChooser
|
||||||
@ -480,8 +480,8 @@ export const MapsList = (props: MapsListProps): React.ReactElement => {
|
|||||||
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) => {
|
||||||
const isItemSelected = isSelected(row.id)
|
const isItemSelected = isSelected(row.id);
|
||||||
const labelId = row.id
|
const labelId = row.id;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TableRow
|
<TableRow
|
||||||
@ -592,7 +592,7 @@ export const MapsList = (props: MapsListProps): React.ReactElement => {
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
)
|
);
|
||||||
})
|
})
|
||||||
)}
|
)}
|
||||||
</TableBody>
|
</TableBody>
|
||||||
@ -606,5 +606,5 @@ export const MapsList = (props: MapsListProps): React.ReactElement => {
|
|||||||
mapsId={activeDialog ? activeDialog.mapsId : []}
|
mapsId={activeDialog ? activeDialog.mapsId : []}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { fade } from '@material-ui/core/styles'
|
import { fade } from '@material-ui/core/styles';
|
||||||
import { Theme } from '@material-ui/core/styles/createMuiTheme'
|
import { Theme } from '@material-ui/core/styles/createMuiTheme';
|
||||||
import createStyles from '@material-ui/core/styles/createStyles'
|
import createStyles from '@material-ui/core/styles/createStyles';
|
||||||
import makeStyles from '@material-ui/core/styles/makeStyles'
|
import makeStyles from '@material-ui/core/styles/makeStyles';
|
||||||
|
|
||||||
export const useStyles = makeStyles((theme: Theme) =>
|
export const useStyles = makeStyles((theme: Theme) =>
|
||||||
createStyles({
|
createStyles({
|
||||||
@ -100,4 +100,4 @@ export const useStyles = makeStyles((theme: Theme) =>
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
)
|
);
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
import React from 'react'
|
import React from 'react';
|
||||||
|
|
||||||
import Tooltip from '@material-ui/core/Tooltip'
|
import Tooltip from '@material-ui/core/Tooltip';
|
||||||
import PersonSharpIcon from '@material-ui/icons/PersonSharp'
|
import PersonSharpIcon from '@material-ui/icons/PersonSharp';
|
||||||
import EditSharpIcon from '@material-ui/icons/EditSharp'
|
import EditSharpIcon from '@material-ui/icons/EditSharp';
|
||||||
import VisibilitySharpIcon from '@material-ui/icons/VisibilitySharp'
|
import VisibilitySharpIcon from '@material-ui/icons/VisibilitySharp';
|
||||||
|
|
||||||
import { FormattedMessage } from 'react-intl'
|
import { FormattedMessage } from 'react-intl';
|
||||||
import { Role } from '../../../classes/client'
|
import { Role } from '../../../classes/client';
|
||||||
|
|
||||||
type RoleIconProps = {
|
type RoleIconProps = {
|
||||||
role: Role
|
role: Role;
|
||||||
}
|
};
|
||||||
|
|
||||||
const RoleIcon = ({ role }: RoleIconProps): React.ReactElement => {
|
const RoleIcon = ({ role }: RoleIconProps): React.ReactElement => {
|
||||||
return (
|
return (
|
||||||
@ -42,7 +42,7 @@ const RoleIcon = ({ role }: RoleIconProps): React.ReactElement => {
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
export default RoleIcon
|
export default RoleIcon;
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import { Theme } from '@material-ui/core/styles/createMuiTheme'
|
import { Theme } from '@material-ui/core/styles/createMuiTheme';
|
||||||
import createStyles from '@material-ui/core/styles/createStyles'
|
import createStyles from '@material-ui/core/styles/createStyles';
|
||||||
import makeStyles from '@material-ui/core/styles/makeStyles'
|
import makeStyles from '@material-ui/core/styles/makeStyles';
|
||||||
|
|
||||||
const drawerWidth = 300
|
const drawerWidth = 300;
|
||||||
|
|
||||||
export const useStyles = makeStyles((theme: Theme) =>
|
export const useStyles = makeStyles((theme: Theme) =>
|
||||||
createStyles({
|
createStyles({
|
||||||
@ -60,4 +60,4 @@ export const useStyles = makeStyles((theme: Theme) =>
|
|||||||
padding: theme.spacing(3),
|
padding: theme.spacing(3),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
)
|
);
|
||||||
|
@ -1,60 +1,60 @@
|
|||||||
import React, { useState, useEffect } from 'react'
|
import React, { useState, useEffect } from 'react';
|
||||||
import { FormattedMessage, useIntl } from 'react-intl'
|
import { FormattedMessage, useIntl } from 'react-intl';
|
||||||
import ReCAPTCHA from 'react-google-recaptcha'
|
import ReCAPTCHA from 'react-google-recaptcha';
|
||||||
import { useHistory } from 'react-router-dom'
|
import { useHistory } from 'react-router-dom';
|
||||||
import Client, { ErrorInfo } from '../../classes/client'
|
import Client, { ErrorInfo } from '../../classes/client';
|
||||||
import FormContainer from '../layout/form-container'
|
import FormContainer from '../layout/form-container';
|
||||||
|
|
||||||
import Header from '../layout/header'
|
import Header from '../layout/header';
|
||||||
import Footer from '../layout/footer'
|
import Footer from '../layout/footer';
|
||||||
|
|
||||||
import { useSelector } from 'react-redux'
|
import { useSelector } from 'react-redux';
|
||||||
import { useMutation } from 'react-query'
|
import { useMutation } from 'react-query';
|
||||||
import { activeInstance } from '../../redux/clientSlice'
|
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';
|
||||||
import Typography from '@material-ui/core/Typography'
|
import Typography from '@material-ui/core/Typography';
|
||||||
import FormControl from '@material-ui/core/FormControl'
|
import FormControl from '@material-ui/core/FormControl';
|
||||||
|
|
||||||
export type Model = {
|
export type Model = {
|
||||||
email: string
|
email: string;
|
||||||
lastname: string
|
lastname: string;
|
||||||
firstname: string
|
firstname: string;
|
||||||
password: string
|
password: string;
|
||||||
recaptcha: string
|
recaptcha: string;
|
||||||
}
|
};
|
||||||
|
|
||||||
const defaultModel: Model = { email: '', lastname: '', firstname: '', password: '', recaptcha: '' }
|
const defaultModel: Model = { email: '', lastname: '', firstname: '', password: '', recaptcha: '' };
|
||||||
const RegistrationForm = () => {
|
const RegistrationForm = () => {
|
||||||
const [model, setModel] = useState<Model>(defaultModel)
|
const [model, setModel] = useState<Model>(defaultModel);
|
||||||
const [error, setError] = useState<ErrorInfo>()
|
const [error, setError] = useState<ErrorInfo>();
|
||||||
const history = useHistory()
|
const history = useHistory();
|
||||||
const intl = useIntl()
|
const intl = useIntl();
|
||||||
|
|
||||||
const Client: Client = useSelector(activeInstance)
|
const Client: Client = useSelector(activeInstance);
|
||||||
const mutation = useMutation<void, ErrorInfo, Model>(
|
const mutation = useMutation<void, ErrorInfo, Model>(
|
||||||
(model: Model) => Client.registerNewUser({ ...model }),
|
(model: Model) => Client.registerNewUser({ ...model }),
|
||||||
{
|
{
|
||||||
onSuccess: () => history.push('/c/registration-success'),
|
onSuccess: () => history.push('/c/registration-success'),
|
||||||
onError: (error) => {
|
onError: (error) => {
|
||||||
setError(error)
|
setError(error);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
)
|
);
|
||||||
|
|
||||||
const handleOnSubmit = (event: React.FormEvent<HTMLFormElement>): void => {
|
const handleOnSubmit = (event: React.FormEvent<HTMLFormElement>): void => {
|
||||||
event.preventDefault()
|
event.preventDefault();
|
||||||
mutation.mutate(model)
|
mutation.mutate(model);
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleOnChange = (event: React.ChangeEvent<HTMLInputElement>): void => {
|
const handleOnChange = (event: React.ChangeEvent<HTMLInputElement>): void => {
|
||||||
event.preventDefault()
|
event.preventDefault();
|
||||||
|
|
||||||
const name = event.target.name
|
const name = event.target.name;
|
||||||
const value = event.target.value
|
const value = event.target.value;
|
||||||
setModel({ ...model, [name as keyof Model]: value })
|
setModel({ ...model, [name as keyof Model]: value });
|
||||||
}
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FormContainer>
|
<FormContainer>
|
||||||
@ -125,8 +125,8 @@ const RegistrationForm = () => {
|
|||||||
<ReCAPTCHA
|
<ReCAPTCHA
|
||||||
sitekey="6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI"
|
sitekey="6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI"
|
||||||
onChange={(value: string) => {
|
onChange={(value: string) => {
|
||||||
model.recaptcha = value
|
model.recaptcha = value;
|
||||||
setModel(model)
|
setModel(model);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -147,13 +147,13 @@ const RegistrationForm = () => {
|
|||||||
</form>
|
</form>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
</FormContainer>
|
</FormContainer>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
const RegistationPage = (): React.ReactElement => {
|
const RegistationPage = (): React.ReactElement => {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
document.title = 'Registration | WiseMapping'
|
document.title = 'Registration | WiseMapping';
|
||||||
})
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@ -161,7 +161,7 @@ const RegistationPage = (): React.ReactElement => {
|
|||||||
<RegistrationForm />
|
<RegistrationForm />
|
||||||
<Footer />
|
<Footer />
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
export default RegistationPage
|
export default RegistationPage;
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
import React, { useEffect } from 'react'
|
import React, { useEffect } from 'react';
|
||||||
import { FormattedMessage } from 'react-intl'
|
import { FormattedMessage } from 'react-intl';
|
||||||
import FormContainer from '../layout/form-container'
|
import FormContainer from '../layout/form-container';
|
||||||
import Header from '../layout/header'
|
import Header from '../layout/header';
|
||||||
import Footer from '../layout/footer'
|
import Footer from '../layout/footer';
|
||||||
import { Link as RouterLink } from 'react-router-dom'
|
import { Link as RouterLink } from 'react-router-dom';
|
||||||
import Typography from '@material-ui/core/Typography'
|
import Typography from '@material-ui/core/Typography';
|
||||||
import Button from '@material-ui/core/Button'
|
import Button from '@material-ui/core/Button';
|
||||||
|
|
||||||
const RegistrationSuccessPage = (): React.ReactElement => {
|
const RegistrationSuccessPage = (): React.ReactElement => {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
document.title = 'Reset Password | WiseMapping'
|
document.title = 'Reset Password | WiseMapping';
|
||||||
})
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@ -43,7 +43,7 @@ const RegistrationSuccessPage = (): React.ReactElement => {
|
|||||||
</FormContainer>
|
</FormContainer>
|
||||||
<Footer />
|
<Footer />
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
export default RegistrationSuccessPage
|
export default RegistrationSuccessPage;
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import React from 'react'
|
import React from 'react';
|
||||||
import ReactDOM from 'react-dom'
|
import ReactDOM from 'react-dom';
|
||||||
import App from './app'
|
import App from './app';
|
||||||
|
|
||||||
async function bootstrapApplication() {
|
async function bootstrapApplication() {
|
||||||
ReactDOM.render(<App />, document.getElementById('root') as HTMLElement)
|
ReactDOM.render(<App />, document.getElementById('root') as HTMLElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
bootstrapApplication()
|
bootstrapApplication();
|
||||||
|
@ -1,53 +1,53 @@
|
|||||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||||
import { createSlice } from '@reduxjs/toolkit'
|
import { createSlice } from '@reduxjs/toolkit';
|
||||||
import { useQuery } from 'react-query'
|
import { useQuery } from 'react-query';
|
||||||
import Client, { AccountInfo, ErrorInfo, MapInfo } from '../classes/client'
|
import Client, { AccountInfo, ErrorInfo, MapInfo } from '../classes/client';
|
||||||
import MockClient from '../classes/client/mock-client'
|
import MockClient from '../classes/client/mock-client';
|
||||||
import RestClient from '../classes/client/rest-client'
|
import RestClient from '../classes/client/rest-client';
|
||||||
import { useSelector } from 'react-redux'
|
import { useSelector } from 'react-redux';
|
||||||
|
|
||||||
interface ConfigInfo {
|
interface ConfigInfo {
|
||||||
apiBaseUrl: string
|
apiBaseUrl: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
class RutimeConfig {
|
class RutimeConfig {
|
||||||
private config: ConfigInfo
|
private config: ConfigInfo;
|
||||||
load() {
|
load() {
|
||||||
// Config can be inserted in the html page to define the global properties ...
|
// Config can be inserted in the html page to define the global properties ...
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
this.config = (window as any).serverconfig
|
this.config = (window as any).serverconfig;
|
||||||
return this
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
buildClient(): Client {
|
buildClient(): Client {
|
||||||
let result: Client
|
let result: Client;
|
||||||
if (this.config) {
|
if (this.config) {
|
||||||
result = new RestClient(this.config.apiBaseUrl, () => {
|
result = new RestClient(this.config.apiBaseUrl, () => {
|
||||||
sessionExpired()
|
sessionExpired();
|
||||||
})
|
});
|
||||||
console.log('Service using rest client. ' + JSON.stringify(this.config))
|
console.log('Service using rest client. ' + JSON.stringify(this.config));
|
||||||
} else {
|
} else {
|
||||||
console.log('Warning:Service using mockservice client')
|
console.log('Warning:Service using mockservice client');
|
||||||
result = new MockClient()
|
result = new MockClient();
|
||||||
}
|
}
|
||||||
return result
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ClientStatus {
|
export interface ClientStatus {
|
||||||
state: 'healthy' | 'session-expired'
|
state: 'healthy' | 'session-expired';
|
||||||
msg?: string
|
msg?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ClientState {
|
export interface ClientState {
|
||||||
instance: Client
|
instance: Client;
|
||||||
status: ClientStatus
|
status: ClientStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
const initialState: ClientState = {
|
const initialState: ClientState = {
|
||||||
instance: new RutimeConfig().load().buildClient(),
|
instance: new RutimeConfig().load().buildClient(),
|
||||||
status: { state: 'healthy' },
|
status: { state: 'healthy' },
|
||||||
}
|
};
|
||||||
|
|
||||||
export const clientSlice = createSlice({
|
export const clientSlice = createSlice({
|
||||||
name: 'client',
|
name: 'client',
|
||||||
@ -57,45 +57,45 @@ export const clientSlice = createSlice({
|
|||||||
state.status = {
|
state.status = {
|
||||||
state: 'session-expired',
|
state: 'session-expired',
|
||||||
msg: 'Sessions has expired. You need to login again',
|
msg: 'Sessions has expired. You need to login again',
|
||||||
}
|
};
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
});
|
||||||
|
|
||||||
type MapLoadResult = {
|
type MapLoadResult = {
|
||||||
isLoading: boolean
|
isLoading: boolean;
|
||||||
error: ErrorInfo | null
|
error: ErrorInfo | null;
|
||||||
map: MapInfo | null
|
map: MapInfo | null;
|
||||||
}
|
};
|
||||||
|
|
||||||
export const fetchMapById = (id: number): MapLoadResult => {
|
export const fetchMapById = (id: number): MapLoadResult => {
|
||||||
const client: Client = useSelector(activeInstance)
|
const client: Client = useSelector(activeInstance);
|
||||||
const { isLoading, error, data } = useQuery<unknown, ErrorInfo, MapInfo[]>('maps', () => {
|
const { isLoading, error, data } = useQuery<unknown, ErrorInfo, MapInfo[]>('maps', () => {
|
||||||
return client.fetchAllMaps()
|
return client.fetchAllMaps();
|
||||||
})
|
});
|
||||||
|
|
||||||
const result = data?.find((m) => m.id == id)
|
const result = data?.find((m) => m.id == id);
|
||||||
const map = result || null
|
const map = result || null;
|
||||||
return { isLoading: isLoading, error: error, map: map }
|
return { isLoading: isLoading, error: error, map: map };
|
||||||
}
|
};
|
||||||
|
|
||||||
export const fetchAccount = (): AccountInfo | undefined => {
|
export const fetchAccount = (): AccountInfo | undefined => {
|
||||||
const client: Client = useSelector(activeInstance)
|
const client: Client = useSelector(activeInstance);
|
||||||
const { data } = useQuery<unknown, ErrorInfo, AccountInfo>('account', () => {
|
const { data } = useQuery<unknown, ErrorInfo, AccountInfo>('account', () => {
|
||||||
return client.fetchAccountInfo()
|
return client.fetchAccountInfo();
|
||||||
})
|
});
|
||||||
return data
|
return data;
|
||||||
}
|
};
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
export const activeInstance = (state: any): Client => {
|
export const activeInstance = (state: any): Client => {
|
||||||
return state.client.instance
|
return state.client.instance;
|
||||||
}
|
};
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
export const activeInstanceStatus = (state: any): ClientStatus => {
|
export const activeInstanceStatus = (state: any): ClientStatus => {
|
||||||
return state.client.status
|
return state.client.status;
|
||||||
}
|
};
|
||||||
|
|
||||||
export const { sessionExpired } = clientSlice.actions
|
export const { sessionExpired } = clientSlice.actions;
|
||||||
export default clientSlice.reducer
|
export default clientSlice.reducer;
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import { configureStore } from '@reduxjs/toolkit'
|
import { configureStore } from '@reduxjs/toolkit';
|
||||||
import clientReducer from './clientSlice'
|
import clientReducer from './clientSlice';
|
||||||
|
|
||||||
// Create Service object...
|
// Create Service object...
|
||||||
const store = configureStore({
|
const store = configureStore({
|
||||||
reducer: {
|
reducer: {
|
||||||
client: clientReducer,
|
client: clientReducer,
|
||||||
},
|
},
|
||||||
})
|
});
|
||||||
|
|
||||||
export default store
|
export default store;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import createMuiTheme from '@material-ui/core/styles/createMuiTheme'
|
import createMuiTheme from '@material-ui/core/styles/createMuiTheme';
|
||||||
|
|
||||||
const theme = createMuiTheme({
|
const theme = createMuiTheme({
|
||||||
overrides: {
|
overrides: {
|
||||||
@ -71,6 +71,6 @@ const theme = createMuiTheme({
|
|||||||
contrastText: '#FFFFFF',
|
contrastText: '#FFFFFF',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
});
|
||||||
|
|
||||||
export { theme }
|
export { theme };
|
||||||
|
Loading…
Reference in New Issue
Block a user