Complete deleat all

This commit is contained in:
Paulo Gustavo Veiga 2021-02-06 22:51:04 -08:00
parent fe9f40b73b
commit 7df6f3744b
17 changed files with 323 additions and 140 deletions

View File

@ -74,6 +74,9 @@
"create.title": { "create.title": {
"defaultMessage": "Create a new mindmap" "defaultMessage": "Create a new mindmap"
}, },
"deletem.title": {
"defaultMessage": "All selected maps will be deleted"
},
"duplicate.title": { "duplicate.title": {
"defaultMessage": "Duplicate" "defaultMessage": "Duplicate"
}, },
@ -143,6 +146,45 @@
"import.title": { "import.title": {
"defaultMessage": "Import existing mindmap" "defaultMessage": "Import existing mindmap"
}, },
"info.basic-info": {
"defaultMessage": "Basic Info"
},
"info.button": {
"defaultMessage": "Accept"
},
"info.creation-time": {
"defaultMessage": "Creation Date"
},
"info.creator": {
"defaultMessage": "Creator"
},
"info.description": {
"defaultMessage": "Description"
},
"info.description-msg": {
"defaultMessage": "By publishing the map you make it visible to everyone on the Internet."
},
"info.modified-time": {
"defaultMessage": "Last Modified Date"
},
"info.modified-tny": {
"defaultMessage": "Last Modified By"
},
"info.name": {
"defaultMessage": "Name"
},
"info.public-visibility": {
"defaultMessage": "Publicly Visible"
},
"info.sharing": {
"defaultMessage": "Sharing"
},
"info.starred": {
"defaultMessage": "Starred"
},
"info.title": {
"defaultMessage": "Info"
},
"login.desc": { "login.desc": {
"defaultMessage": "Log into your account" "defaultMessage": "Log into your account"
}, },
@ -189,6 +231,9 @@
"map.name": { "map.name": {
"defaultMessage": "Name" "defaultMessage": "Name"
}, },
"maps.create-tooltip": {
"defaultMessage": "Create a New Map"
},
"maps.empty-result": { "maps.empty-result": {
"defaultMessage": "No matching record found with the current filter criteria." "defaultMessage": "No matching record found with the current filter criteria."
}, },

View File

@ -51,11 +51,12 @@ export type ErrorInfo = {
interface Client { interface Client {
createMap(map: BasicMapInfo): Promise<number>; createMap(map: BasicMapInfo): Promise<number>;
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[]>;
duplicateMap(id: number, basicInfo: BasicMapInfo): Promise<number>; duplicateMap(id: number, basicInfo: BasicMapInfo): Promise<number>;
fetchMapInfo(id: number): Promise<BasicMapInfo>;
changeStarred(id: number, starred: boolean): Promise<void>; changeStarred(id: number, starred: boolean): Promise<void>;
updateMapToPublic(id: number, starred: boolean): Promise<void>; updateMapToPublic(id: number, starred: boolean): Promise<void>;

View File

@ -25,7 +25,7 @@ class MockClient implements Client {
this.maps = [ this.maps = [
createMapInfo(1, true, "El Mapa", [], "Paulo", "2008-06-02T00:00:00Z", "Berna", "2008-06-02T00:00:00Z", "", true, 'owner'), createMapInfo(1, true, "El Mapa", [], "Paulo", "2008-06-02T00:00:00Z", "Berna", "2008-06-02T00:00:00Z", "", true, 'owner'),
createMapInfo(11, false, "El Mapa3", [1, 2, 3], "Paulo3", "2008-06-02T00:00:00Z", "Berna", "2008-06-02T00:00:00Z", "", false, 'editor'), createMapInfo(11, false, "El Mapa3", [1, 2, 3], "Paulo3", "2008-06-02T00:00:00Z", "Berna", "2008-06-02T00:00:00Z", "", false, 'editor'),
createMapInfo(12, false, "El Mapa3", [1, 2, 3], "Paulo3", "2008-06-02T00:00:00Z", "Berna", "2008-06-02T00:00:00Z","", false, 'editor') createMapInfo(12, false, "El Mapa3", [1, 2, 3], "Paulo3", "2008-06-02T00:00:00Z", "Berna", "2008-06-02T00:00:00Z", "", false, 'editor')
]; ];
this.labels = [ this.labels = [
@ -34,6 +34,10 @@ class MockClient implements Client {
]; ];
} }
deleteMaps(ids: number[]): Promise<void> {
ids.forEach(id => this.deleteMap(id));
return Promise.resolve();
}
revertHistory(id: number, cid: number): Promise<void> { revertHistory(id: number, cid: number): Promise<void> {
return Promise.resolve(); return Promise.resolve();
} }
@ -65,10 +69,6 @@ class MockClient implements Client {
return Promise.resolve(); return Promise.resolve();
} }
fetchMapInfo(id: number): Promise<BasicMapInfo> {
return Promise.resolve({ title: 'My Map', description: 'My Description' });
}
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;
@ -171,7 +171,7 @@ class MockClient implements Client {
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();
@ -181,7 +181,7 @@ class MockClient implements Client {
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);
} }

View File

@ -6,30 +6,32 @@ 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;
} }
updateMapToPublic(id: number, isPublic: boolean): Promise<void> { deleteMaps(ids: number[]): Promise<void> {
/* const handler = (success: () => void, reject: (error: ErrorInfo) => void) => {
jQuery.ajax("c/restful/maps/${mindmap.id}/publish", { axios.delete(this.baseUrl + `/c/restful/maps/batch?ids=${ids.join()}`,
async:false, { headers: { 'Content-Type': 'text/plain' } }
dataType:'json', ).then(() => {
data:$('#dialogMainForm #enablePublicView')[0].checked ? 'true' : 'false', success();
type:'PUT', }).catch(error => {
contentType:"text/plain", const response = error.response;
success:function (data, textStatus, jqXHR) { const errorInfo = this.parseResponseOnError(response);
$('#publish-dialog-modal').modal('hide'); reject(errorInfo);
}, });
*/ }
return new Promise(handler);
}
updateMapToPublic(id: number, isPublic: boolean): Promise<void> {
const handler = (success: () => void, reject: (error: ErrorInfo) => void) => { const handler = (success: () => void, reject: (error: ErrorInfo) => void) => {
axios.put(`${this.baseUrl}/c/restful/maps/${id}/publish`, axios.put(`${this.baseUrl}/c/restful/maps/${id}/publish`,
isPublic, isPublic,
{ headers: { 'Content-Type': 'text/plain' } } { headers: { 'Content-Type': 'text/plain' } }
).then(response => { ).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 => {
@ -45,60 +47,11 @@ export default class RestClient implements Client {
throw new Error('Method not implemented.'); throw new Error('Method not implemented.');
} }
fetchHistory(id: number): Promise<ChangeHistory[]> { fetchHistory(id: number): Promise<ChangeHistory[]> {
throw new Error('Method not implemented.'); throw new Error('Method not implemented.');
} }
fetchMapInfo(id: number): Promise<BasicMapInfo> {
throw new Error('Method not implemented.');
}
private parseResponseOnError = (response: any): ErrorInfo => {
const intl = useIntl();
let result: ErrorInfo | undefined;
if (response) {
const status: number = response.status;
const data = response.data;
console.log(data);
switch (status) {
case 401:
case 302:
this.sessionExpired();
result = { msg: intl.formatMessage({ id: "expired.description", defaultMessage: "Your current session has expired. Please, sign in and try again." }) }
break;
default:
if (data) {
// Set global errors ...
result = {};
let globalErrors = data.globalErrors;
if (globalErrors && globalErrors.length > 0) {
result.msg = globalErrors[0];
}
// Set field errors ...
if (data.fieldErrors && Object.keys(data.fieldErrors).length > 0) {
result.fields = data.fieldErrors;
if (!result.msg) {
const key = Object.keys(data.fieldErrors)[0];
result.msg = data.fieldErrors[key];
}
}
} else {
result = { msg: response.statusText };
}
}
}
// Network related problem ...
if (!result) {
result = { msg: 'Unexpected error. Please, try latter' };
}
return result;
}
renameMap(id: number, basicInfo: BasicMapInfo): Promise<void> { renameMap(id: number, basicInfo: BasicMapInfo): Promise<void> {
throw "Method not implemented yet"; throw "Method not implemented yet";
@ -283,5 +236,53 @@ export default class RestClient implements Client {
} }
return new Promise(handler); return new Promise(handler);
} }
private parseResponseOnError = (response: any): ErrorInfo => {
const intl = useIntl();
let result: ErrorInfo | undefined;
if (response) {
const status: number = response.status;
const data = response.data;
console.log(data);
switch (status) {
case 401:
case 302:
this.sessionExpired();
result = { msg: intl.formatMessage({ id: "expired.description", defaultMessage: "Your current session has expired. Please, sign in and try again." }) }
break;
default:
if (data) {
// Set global errors ...
result = {};
let globalErrors = data.globalErrors;
if (globalErrors && globalErrors.length > 0) {
result.msg = globalErrors[0];
}
// Set field errors ...
if (data.fieldErrors && Object.keys(data.fieldErrors).length > 0) {
result.fields = data.fieldErrors;
if (!result.msg) {
const key = Object.keys(data.fieldErrors)[0];
result.msg = data.fieldErrors[key];
}
}
} else {
result = { msg: response.statusText };
}
}
}
// Network related problem ...
if (!result) {
result = { msg: 'Unexpected error. Please, try latter' };
}
return result;
}
} }

View File

@ -149,6 +149,12 @@
"value": "Create a new mindmap" "value": "Create a new mindmap"
} }
], ],
"deletem.title": [
{
"type": 0,
"value": "All selected maps will be deleted"
}
],
"duplicate.title": [ "duplicate.title": [
{ {
"type": 0, "type": 0,
@ -287,6 +293,84 @@
"value": "Import existing mindmap" "value": "Import existing mindmap"
} }
], ],
"info.basic-info": [
{
"type": 0,
"value": "Basic Info"
}
],
"info.button": [
{
"type": 0,
"value": "Accept"
}
],
"info.creation-time": [
{
"type": 0,
"value": "Creation Date"
}
],
"info.creator": [
{
"type": 0,
"value": "Creator"
}
],
"info.description": [
{
"type": 0,
"value": "Description"
}
],
"info.description-msg": [
{
"type": 0,
"value": "By publishing the map you make it visible to everyone on the Internet."
}
],
"info.modified-time": [
{
"type": 0,
"value": "Last Modified Date"
}
],
"info.modified-tny": [
{
"type": 0,
"value": "Last Modified By"
}
],
"info.name": [
{
"type": 0,
"value": "Name"
}
],
"info.public-visibility": [
{
"type": 0,
"value": "Publicly Visible"
}
],
"info.sharing": [
{
"type": 0,
"value": "Sharing"
}
],
"info.starred": [
{
"type": 0,
"value": "Starred"
}
],
"info.title": [
{
"type": 0,
"value": "Info"
}
],
"login.desc": [ "login.desc": [
{ {
"type": 0, "type": 0,
@ -377,6 +461,12 @@
"value": "Name" "value": "Name"
} }
], ],
"maps.create-tooltip": [
{
"type": 0,
"value": "Create a New Map"
}
],
"maps.empty-result": [ "maps.empty-result": [
{ {
"type": 0, "type": 0,

View File

@ -16,7 +16,6 @@ export type CreateModel = {
} }
export type CreateProps = { export type CreateProps = {
open: boolean,
onClose: () => void onClose: () => void
} }

View File

@ -5,24 +5,24 @@ import { useMutation, useQueryClient } from "react-query";
import { useSelector } from "react-redux"; import { useSelector } from "react-redux";
import Client from "../../../../client"; import Client from "../../../../client";
import { activeInstance } from '../../../../redux/clientSlice'; import { activeInstance } from '../../../../redux/clientSlice';
import { DialogProps, fetchMapById, handleOnMutationSuccess } from ".."; import { SimpleDialogProps, fetchMapById, handleOnMutationSuccess } from "..";
import BaseDialog from "../base-dialog"; import BaseDialog from "../base-dialog";
const DeleteDialog = (props: DialogProps) => { const DeleteDialog = (props: SimpleDialogProps) => {
const intl = useIntl(); const intl = useIntl();
const { mapId, onClose } = props;
const service: Client = useSelector(activeInstance); const client: Client = useSelector(activeInstance);
const queryClient = useQueryClient(); const queryClient = useQueryClient();
const mutation = useMutation((id: number) => service.deleteMap(id), const mutation = useMutation((id: number) => client.deleteMap(id),
{ {
onSuccess: () => handleOnMutationSuccess(props.onClose, queryClient) onSuccess: () => handleOnMutationSuccess(onClose, queryClient)
} }
); );
const mapId = props.mapId;
const handleOnClose = (): void => { const handleOnClose = (): void => {
props.onClose(); onClose();
}; };
const handleOnSubmit = (): void => { const handleOnSubmit = (): void => {
@ -37,10 +37,12 @@ const DeleteDialog = (props: DialogProps) => {
onClose={handleOnClose} onSubmit={handleOnSubmit} onClose={handleOnClose} onSubmit={handleOnSubmit}
title={intl.formatMessage({ id: "action.delete-title", defaultMessage: "Delete" })} title={intl.formatMessage({ id: "action.delete-title", defaultMessage: "Delete" })}
submitButton={intl.formatMessage({ id: "action.delete-title", defaultMessage: "Delete" })} > submitButton={intl.formatMessage({ id: "action.delete-title", defaultMessage: "Delete" })} >
<Alert severity="warning"> <Alert severity="warning">
<AlertTitle>Delete '{map?.title}'</AlertTitle> <AlertTitle>Delete '{map?.title}'</AlertTitle>
<FormattedMessage id="action.delete-description" defaultMessage="Deleted mindmap can not be recovered. Do you want to continue ?." /> <FormattedMessage id="action.delete-description" defaultMessage="Deleted mindmap can not be recovered. Do you want to continue ?." />
</Alert> </Alert>
</BaseDialog> </BaseDialog>
</div> </div>
); );

View File

@ -0,0 +1,52 @@
import { Alert, AlertTitle } from "@material-ui/lab";
import React from "react";
import { FormattedMessage, useIntl } from "react-intl";
import { useMutation, useQueryClient } from "react-query";
import { useSelector } from "react-redux";
import Client from "../../../../client";
import { activeInstance } from '../../../../redux/clientSlice';
import { handleOnMutationSuccess } from "..";
import BaseDialog from "../base-dialog";
export type DeleteMultiselectDialogProps = {
mapsId: number[],
onClose: () => void
}
const DeleteMultiselectDialog = (props: DeleteMultiselectDialogProps) => {
const { onClose, mapsId } = props;
const intl = useIntl();
const client: Client = useSelector(activeInstance);
const queryClient = useQueryClient();
const mutation = useMutation((ids: number[]) => client.deleteMaps(ids),
{
onSuccess: () => handleOnMutationSuccess(props.onClose, queryClient)
}
);
const handleOnClose = (): void => {
onClose();
};
const handleOnSubmit = (): void => {
mutation.mutate(mapsId);
}
return (
<div>
<BaseDialog
onClose={handleOnClose} onSubmit={handleOnSubmit}
title={intl.formatMessage({ id: "action.delete-title", defaultMessage: "Delete" })}
submitButton={intl.formatMessage({ id: "action.delete-title", defaultMessage: "Delete" })} >
<Alert severity="warning">
<AlertTitle><FormattedMessage id="deletem.title" defaultMessage="All selected maps will be deleted" /></AlertTitle>
<FormattedMessage id="action.delete-description" defaultMessage="Deleted mindmap can not be recovered. Do you want to continue ?." />
</Alert>
</BaseDialog>
</div>
);
}
export default DeleteMultiselectDialog;

View File

@ -7,7 +7,7 @@ import { useSelector } from "react-redux";
import Client, { BasicMapInfo, ErrorInfo } from "../../../../client"; import Client, { BasicMapInfo, ErrorInfo } from "../../../../client";
import { activeInstance } from '../../../../redux/clientSlice'; import { activeInstance } from '../../../../redux/clientSlice';
import Input from "../../../form/input"; import Input from "../../../form/input";
import { DialogProps, fetchMapById } from ".."; import { SimpleDialogProps, fetchMapById } from "..";
import BaseDialog from "../base-dialog"; import BaseDialog from "../base-dialog";
export type DuplicateModel = { export type DuplicateModel = {
@ -17,14 +17,13 @@ export type DuplicateModel = {
} }
const defaultModel: DuplicateModel = { title: '', description: '', id: -1 }; const defaultModel: DuplicateModel = { title: '', description: '', id: -1 };
const DuplicateDialog = (props: DialogProps) => { const DuplicateDialog = (props: SimpleDialogProps) => {
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 { mapId, open } = props; const { mapId, onClose } = props;
const intl = useIntl(); const intl = useIntl();
const queryClient = useQueryClient();
const mutation = useMutation<number, ErrorInfo, DuplicateModel>((model: DuplicateModel) => { const mutation = useMutation<number, ErrorInfo, DuplicateModel>((model: DuplicateModel) => {
const { id, ...rest } = model; const { id, ...rest } = model;
@ -41,9 +40,7 @@ const DuplicateDialog = (props: DialogProps) => {
); );
const handleOnClose = (): void => { const handleOnClose = (): void => {
props.onClose(); onClose();
setModel(defaultModel);
setError(undefined);
}; };
const handleOnSubmit = (event: React.FormEvent<HTMLFormElement>): void => { const handleOnSubmit = (event: React.FormEvent<HTMLFormElement>): void => {

View File

@ -4,13 +4,13 @@ import { useQuery } from "react-query";
import { useSelector } from "react-redux"; import { useSelector } from "react-redux";
import Client, { ChangeHistory } from "../../../../client"; import Client, { ChangeHistory } from "../../../../client";
import { activeInstance } from '../../../../redux/clientSlice'; import { activeInstance } from '../../../../redux/clientSlice';
import { DialogProps } from ".."; import { SimpleDialogProps } from "..";
import BaseDialog from "../base-dialog"; import BaseDialog from "../base-dialog";
import { Link, Paper, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, Tooltip } from "@material-ui/core"; import { Link, Paper, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, Tooltip } from "@material-ui/core";
import moment from "moment"; import moment from "moment";
const HistoryDialog = (props: DialogProps) => { const HistoryDialog = (props: SimpleDialogProps) => {
const intl = useIntl(); const intl = useIntl();
const mapId = props.mapId; const mapId = props.mapId;

View File

@ -16,7 +16,6 @@ export type ImportModel = {
} }
export type CreateProps = { export type CreateProps = {
open: boolean,
onClose: () => void onClose: () => void
} }

View File

@ -8,12 +8,12 @@ import { useSelector } from "react-redux";
import { QueryClient, useQuery } from 'react-query'; import { QueryClient, useQuery } from 'react-query';
import { activeInstance } from '../../../redux/clientSlice'; import { activeInstance } from '../../../redux/clientSlice';
import DuplicateDialog from './duplicate-dialog'; import DuplicateDialog from './duplicate-dialog';
import { useHistory } from 'react-router-dom';
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';
export type BasicMapInfo = { export type BasicMapInfo = {
name: string; name: string;
@ -22,13 +22,12 @@ export type BasicMapInfo = {
type ActionDialogProps = { type ActionDialogProps = {
action?: ActionType, action?: ActionType,
mapId: number, mapsId: number[],
onClose: () => void onClose: () => void
} }
const ActionDispatcher = (props: ActionDialogProps) => { const ActionDispatcher = (props: ActionDialogProps) => {
const history = useHistory(); const mapsId = props.mapsId;
const mapId = props.mapId;
const action = props.action; const action = props.action;
const handleOnClose = (): void => { const handleOnClose = (): void => {
@ -37,24 +36,26 @@ const ActionDispatcher = (props: ActionDialogProps) => {
switch (action) { switch (action) {
case 'open': case 'open':
window.location.href = `/c/maps/${mapId}/edit`; window.location.href = `/c/maps/${mapsId}/edit`;
break; break;
case 'print': case 'print':
window.open(`/c/maps/${mapId}/print`, 'print'); window.open(`/c/maps/${mapsId}/print`, 'print');
break; break;
} }
return ( return (
<span> <span>
{action === 'create' && <CreateDialog open={true} onClose={handleOnClose} /> } {action === 'create' && <CreateDialog onClose={handleOnClose} />}
{action === 'delete' &&<DeleteDialog open={true} onClose={handleOnClose} mapId={mapId} />} {(action === 'delete' && mapsId.length == 1) && <DeleteDialog onClose={handleOnClose} mapId={mapsId[0]} />}
{action === 'rename' && <RenameDialog open={true} onClose={handleOnClose} mapId={mapId} />} {(action === 'delete' && mapsId.length > 1) && <DeleteMultiselectDialog onClose={handleOnClose} mapsId={mapsId} />}
{action === 'duplicate' && <DuplicateDialog open={true} onClose={handleOnClose} mapId={mapId} />} {action === 'rename' && <RenameDialog onClose={handleOnClose} mapId={mapsId[0]} />}
{action === 'history' && <HistoryDialog open={true} onClose={handleOnClose} mapId={mapId} />} {action === 'duplicate' && <DuplicateDialog onClose={handleOnClose} mapId={mapsId[0]} />}
{action === 'import' && <ImportDialog open={true} onClose={handleOnClose} />} {action === 'history' && <HistoryDialog onClose={handleOnClose} mapId={mapsId[0]} />}
{action === 'publish' && <PublishDialog onClose={handleOnClose} mapId={mapId}/>} {action === 'import' && <ImportDialog onClose={handleOnClose} />}
{action === 'info' && <InfoDialog onClose={handleOnClose} mapId={mapId}/>} {action === 'publish' && <PublishDialog onClose={handleOnClose} mapId={mapsId[0]} />}
{action === 'info' && <InfoDialog onClose={handleOnClose} mapId={mapsId[0]} />}
{action === 'create' && <CreateDialog onClose={handleOnClose} />}
</span > </span >
); );
@ -83,8 +84,7 @@ export const handleOnMutationSuccess = (onClose: () => void, queryClient: QueryC
onClose(); onClose();
} }
export type DialogProps = { export type SimpleDialogProps = {
open: boolean,
mapId: number, mapId: number,
onClose: () => void onClose: () => void
} }

View File

@ -1,6 +1,6 @@
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 { useQueryClient } from 'react-query';
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
import { Card, List, ListItem, Paper, Typography } from '@material-ui/core'; import { Card, List, ListItem, Paper, Typography } from '@material-ui/core';
@ -8,37 +8,28 @@ import { Card, List, ListItem, Paper, Typography } from '@material-ui/core';
import Client, { ErrorInfo } from '../../../../client'; import Client, { ErrorInfo } from '../../../../client';
import { activeInstance } from '../../../../redux/clientSlice'; import { activeInstance } from '../../../../redux/clientSlice';
import BaseDialog from '../base-dialog'; import BaseDialog from '../base-dialog';
import { fetchMapById, handleOnMutationSuccess } from '..'; import { fetchMapById, SimpleDialogProps } from '..';
import { useStyles } from './style'; import { useStyles } from './style';
import moment from 'moment'; import moment from 'moment';
export type InfoProps = { const InfoDialog = (props: SimpleDialogProps) => {
mapId: number,
onClose: () => void
}
const InfoDialog = (props: InfoProps) => {
const { mapId, onClose } = props; const { mapId, onClose } = props;
const { map } = fetchMapById(mapId); const { map } = fetchMapById(mapId);
const client: Client = useSelector(activeInstance);
const [model, setModel] = React.useState<boolean>(map ? map.isPublic : false);
const [error, setError] = React.useState<ErrorInfo>(); const [error, setError] = React.useState<ErrorInfo>();
const [] = React.useState('1'); const [] = React.useState('1');
const queryClient = useQueryClient();
const intl = useIntl();
const intl = useIntl();
const classes = useStyles(); const classes = useStyles();
const handleOnClose = (): void => { const handleOnClose = (): void => {
props.onClose(); onClose();
setError(undefined); setError(undefined);
}; };
return ( return (
<BaseDialog onClose={handleOnClose} error={error} <BaseDialog onClose={handleOnClose} error={error}
title={intl.formatMessage({ id: 'info.title', defaultMessage: 'Info' })} title={intl.formatMessage({ id: 'info.title', defaultMessage: 'Info' })}
description={intl.formatMessage({ id: 'info.description', defaultMessage: 'By publishing the map you make it visible to everyone on the Internet.' })} description={intl.formatMessage({ id: 'info.description-msg', defaultMessage: 'By publishing the map you make it visible to everyone on the Internet.' })}
submitButton={intl.formatMessage({ id: 'info.button', defaultMessage: 'Accept' })}> submitButton={intl.formatMessage({ id: 'info.button', defaultMessage: 'Accept' })}>
<Paper style={{ maxHeight: '200px' }}> <Paper style={{ maxHeight: '200px' }}>

View File

@ -9,15 +9,11 @@ import Client, { ErrorInfo } from '../../../../client';
import { activeInstance } from '../../../../redux/clientSlice'; import { activeInstance } from '../../../../redux/clientSlice';
import BaseDialog from '../base-dialog'; import BaseDialog from '../base-dialog';
import { TabContext, TabList, TabPanel } from '@material-ui/lab'; import { TabContext, TabList, TabPanel } from '@material-ui/lab';
import { fetchMapById, handleOnMutationSuccess } from '..'; import { fetchMapById, handleOnMutationSuccess, SimpleDialogProps } from '..';
import { useStyles } from './style'; import { useStyles } from './style';
export type PublishProps = {
mapId: number,
onClose: () => void
}
const PublishDialog = (props: PublishProps) => { const PublishDialog = (props: SimpleDialogProps) => {
const { mapId, onClose } = props; const { mapId, onClose } = props;
const { map } = fetchMapById(mapId); const { map } = fetchMapById(mapId);

View File

@ -4,7 +4,7 @@ import { useMutation, useQueryClient } from "react-query";
import { useSelector } from "react-redux"; import { useSelector } from "react-redux";
import Client, { BasicMapInfo, ErrorInfo } from "../../../../client"; import Client, { BasicMapInfo, ErrorInfo } from "../../../../client";
import { activeInstance } from '../../../../redux/clientSlice'; import { activeInstance } from '../../../../redux/clientSlice';
import { DialogProps, fetchMapById, handleOnMutationSuccess } from ".."; import { SimpleDialogProps, fetchMapById, handleOnMutationSuccess } from "..";
import Input from "../../../form/input"; import Input from "../../../form/input";
import { FormControl } from "@material-ui/core"; import { FormControl } from "@material-ui/core";
import BaseDialog from "../base-dialog"; import BaseDialog from "../base-dialog";
@ -16,11 +16,11 @@ export type RenameModel = {
} }
const defaultModel: RenameModel = { title: '', description: '', id: -1 }; const defaultModel: RenameModel = { title: '', description: '', id: -1 };
const RenameDialog = (props: DialogProps) => { const RenameDialog = (props: SimpleDialogProps) => {
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 { mapId, open } = props; const { mapId } = props;
const intl = useIntl(); const intl = useIntl();
const queryClient = useQueryClient(); const queryClient = useQueryClient();

View File

@ -11,7 +11,7 @@ import { useStyles } from './style';
import { AccountCircle, AcUnitTwoTone, AddCircleTwoTone, CloudUploadTwoTone, DeleteOutlineTwoTone, EmailOutlined, EmojiPeopleOutlined, ExitToAppOutlined, FeedbackOutlined, Help, LabelTwoTone, PeopleAltTwoTone, PersonAddTwoTone, PersonOutlineTwoTone, PersonTwoTone, PolicyOutlined, PublicTwoTone, SettingsApplicationsOutlined, ShareTwoTone, StarTwoTone } from '@material-ui/icons'; import { AccountCircle, AcUnitTwoTone, AddCircleTwoTone, CloudUploadTwoTone, DeleteOutlineTwoTone, EmailOutlined, EmojiPeopleOutlined, ExitToAppOutlined, FeedbackOutlined, Help, LabelTwoTone, PeopleAltTwoTone, PersonAddTwoTone, PersonOutlineTwoTone, PersonTwoTone, PolicyOutlined, PublicTwoTone, SettingsApplicationsOutlined, ShareTwoTone, StarTwoTone } from '@material-ui/icons';
import { Button, Dialog, DialogActions, DialogContent, DialogTitle, Link, ListItemSecondaryAction, ListItemText, Menu, MenuItem, Tooltip } from '@material-ui/core'; import { Button, Dialog, DialogActions, DialogContent, DialogTitle, Link, ListItemSecondaryAction, ListItemText, Menu, MenuItem, Tooltip } from '@material-ui/core';
import { MapsList } from './maps-list'; import { MapsList } from './maps-list';
import { FormattedMessage } from 'react-intl'; import { FormattedMessage, useIntl } from 'react-intl';
import { useQuery, useMutation, useQueryClient } from 'react-query'; import { useQuery, useMutation, useQueryClient } from 'react-query';
import { activeInstance, activeInstanceStatus, ClientStatus } from '../../redux/clientSlice'; import { activeInstance, activeInstanceStatus, ClientStatus } from '../../redux/clientSlice';
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
@ -46,6 +46,7 @@ const MapsPage = () => {
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();
useEffect(() => { useEffect(() => {
document.title = 'Maps | WiseMapping'; document.title = 'Maps | WiseMapping';
@ -59,7 +60,6 @@ const MapsPage = () => {
); );
const handleMenuClick = (filter: Filter) => { const handleMenuClick = (filter: Filter) => {
// Force reload ...
queryClient.invalidateQueries('maps'); queryClient.invalidateQueries('maps');
setFilter(filter); setFilter(filter);
}; };
@ -115,7 +115,7 @@ const MapsPage = () => {
elevation={0}> elevation={0}>
<Toolbar> <Toolbar>
<Tooltip title="Create a New Map"> <Tooltip title={intl.formatMessage({id:'maps.create-tooltip',defaultMessage:'Create a New Map'})}>
<Button color="primary" <Button color="primary"
size="medium" size="medium"
variant="contained" variant="contained"
@ -141,7 +141,7 @@ const MapsPage = () => {
<FormattedMessage id="action.import" defaultMessage="Import" /> <FormattedMessage id="action.import" defaultMessage="Import" />
</Button> </Button>
</Tooltip> </Tooltip>
<ActionDispatcher action={activeDialog} onClose={() => setActiveDialog(undefined)} mapId={-1} /> <ActionDispatcher action={activeDialog} onClose={() => setActiveDialog(undefined)} mapsId={[]} />
<div className={classes.rightButtonGroup}> <div className={classes.rightButtonGroup}>
<HelpToobarButton /> <HelpToobarButton />

View File

@ -203,6 +203,9 @@ export const MapsList = (props: MapsListProps) => {
const client: Client = useSelector(activeInstance); const client: Client = useSelector(activeInstance);
const intl = useIntl(); const intl = useIntl();
const queryClient = useQueryClient();
useEffect(() => { useEffect(() => {
setSelected([]); setSelected([]);
setPage(0); setPage(0);
@ -218,7 +221,7 @@ export const MapsList = (props: MapsListProps) => {
const [activeRowAction, setActiveRowAction] = React.useState<ActionPanelState | undefined>(undefined); const [activeRowAction, setActiveRowAction] = React.useState<ActionPanelState | undefined>(undefined);
type ActiveDialog = { type ActiveDialog = {
actionType: ActionType; actionType: ActionType;
mapId: number mapsId: number[];
}; };
const [activeDialog, setActiveDialog] = React.useState<ActiveDialog | undefined>(undefined); const [activeDialog, setActiveDialog] = React.useState<ActiveDialog | undefined>(undefined);
@ -278,7 +281,6 @@ export const MapsList = (props: MapsListProps) => {
}; };
}; };
const queryClient = useQueryClient();
const starredMultation = useMutation<void, ErrorInfo, number>((id: number) => { const starredMultation = useMutation<void, ErrorInfo, number>((id: number) => {
const map = mapsInfo.find(m => m.id == id); const map = mapsInfo.find(m => m.id == id);
@ -289,7 +291,6 @@ export const MapsList = (props: MapsListProps) => {
queryClient.invalidateQueries('maps'); queryClient.invalidateQueries('maps');
}, },
onError: (error) => { onError: (error) => {
// @todo ...
// setError(error); // setError(error);
} }
} }
@ -306,7 +307,7 @@ export const MapsList = (props: MapsListProps) => {
setActiveDialog({ setActiveDialog({
actionType: action as ActionType, actionType: action as ActionType,
mapId: mapId as number mapsId: [mapId] as number[]
}); });
} }
setActiveRowAction(undefined); setActiveRowAction(undefined);
@ -316,6 +317,13 @@ export const MapsList = (props: MapsListProps) => {
setSearchCondition(e.target.value); setSearchCondition(e.target.value);
} }
const handleDeleteClick = (event: React.MouseEvent<HTMLButtonElement>) => {
setActiveDialog({
actionType: 'delete',
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}>
@ -333,7 +341,9 @@ export const MapsList = (props: MapsListProps) => {
variant="outlined" variant="outlined"
type="button" type="button"
disableElevation={true} disableElevation={true}
startIcon={<DeleteOutlined />}> onClick={handleDeleteClick}
startIcon={<DeleteOutlined
/>}>
<FormattedMessage id="action.delete" defaultMessage="Delete" /> <FormattedMessage id="action.delete" defaultMessage="Delete" />
</Button> </Button>
</Tooltip> </Tooltip>
@ -481,7 +491,7 @@ export const MapsList = (props: MapsListProps) => {
</Paper> </Paper>
<ActionDispatcher action={activeDialog?.actionType} onClose={() => setActiveDialog(undefined)} mapId={activeDialog ? activeDialog.mapId : -1} /> <ActionDispatcher action={activeDialog?.actionType} onClose={() => setActiveDialog(undefined)} mapsId={activeDialog ? activeDialog.mapsId : []} />
</div > </div >
); );
} }