mirror of
https://bitbucket.org/wisemapping/wisemapping-frontend.git
synced 2024-11-22 06:37:56 +01:00
Complete menu navigation
This commit is contained in:
parent
db934afed8
commit
a1867168ec
@ -6,7 +6,7 @@
|
|||||||
"defaultMessage": "Close"
|
"defaultMessage": "Close"
|
||||||
},
|
},
|
||||||
"action.delete": {
|
"action.delete": {
|
||||||
"defaultMessage": "Delete"
|
"defaultMessage": "History"
|
||||||
},
|
},
|
||||||
"action.delete-description": {
|
"action.delete-description": {
|
||||||
"defaultMessage": "Deleted mindmap can not be recovered. Do you want to continue ?."
|
"defaultMessage": "Deleted mindmap can not be recovered. Do you want to continue ?."
|
||||||
@ -26,6 +26,9 @@
|
|||||||
"action.info-title": {
|
"action.info-title": {
|
||||||
"defaultMessage": "Info"
|
"defaultMessage": "Info"
|
||||||
},
|
},
|
||||||
|
"action.label": {
|
||||||
|
"defaultMessage": "Add Label"
|
||||||
|
},
|
||||||
"action.open": {
|
"action.open": {
|
||||||
"defaultMessage": "Open"
|
"defaultMessage": "Open"
|
||||||
},
|
},
|
||||||
@ -120,6 +123,12 @@
|
|||||||
"login.userinactive": {
|
"login.userinactive": {
|
||||||
"defaultMessage": "Sorry, your account has not been activated yet. You'll receive a notification email when it becomes active. Stay tuned!."
|
"defaultMessage": "Sorry, your account has not been activated yet. You'll receive a notification email when it becomes active. Stay tuned!."
|
||||||
},
|
},
|
||||||
|
"menu.account": {
|
||||||
|
"defaultMessage": "Account"
|
||||||
|
},
|
||||||
|
"menu.signout": {
|
||||||
|
"defaultMessage": "Sign Out"
|
||||||
|
},
|
||||||
"registration.desc": {
|
"registration.desc": {
|
||||||
"defaultMessage": "Signing up is free and just take a moment"
|
"defaultMessage": "Signing up is free and just take a moment"
|
||||||
},
|
},
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
"action.delete": [
|
"action.delete": [
|
||||||
{
|
{
|
||||||
"type": 0,
|
"type": 0,
|
||||||
"value": "Delete"
|
"value": "History"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"action.delete-description": [
|
"action.delete-description": [
|
||||||
@ -53,6 +53,12 @@
|
|||||||
"value": "Info"
|
"value": "Info"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"action.label": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "Add Label"
|
||||||
|
}
|
||||||
|
],
|
||||||
"action.open": [
|
"action.open": [
|
||||||
{
|
{
|
||||||
"type": 0,
|
"type": 0,
|
||||||
@ -239,6 +245,18 @@
|
|||||||
"value": "Sorry, your account has not been activated yet. You'll receive a notification email when it becomes active. Stay tuned!."
|
"value": "Sorry, your account has not been activated yet. You'll receive a notification email when it becomes active. Stay tuned!."
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"menu.account": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "Account"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"menu.signout": [
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "Sign Out"
|
||||||
|
}
|
||||||
|
],
|
||||||
"registration.desc": [
|
"registration.desc": [
|
||||||
{
|
{
|
||||||
"type": 0,
|
"type": 0,
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
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 { Service, ErrorInfo } from '../../services/Service'
|
import Service, { ErrorInfo } from '../../services'
|
||||||
|
|
||||||
import Header from '../layout/header'
|
import Header from '../layout/header'
|
||||||
import Footer from '../layout/footer'
|
import Footer from '../layout/footer'
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { ErrorInfo } from "../../../services/Service"
|
import { ErrorInfo } from "../../../services"
|
||||||
import StyledAlert from "./styled";
|
import StyledAlert from "./styled";
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { TextField } from "@material-ui/core";
|
import { TextField } from "@material-ui/core";
|
||||||
import React, { ChangeEvent } from "react";
|
import React, { ChangeEvent } from "react";
|
||||||
import { MessageDescriptor, useIntl } from "react-intl";
|
import { MessageDescriptor, useIntl } from "react-intl";
|
||||||
import { ErrorInfo } from "../../../services/Service";
|
import { ErrorInfo } from "../../../services";
|
||||||
|
|
||||||
type InputProps = {
|
type InputProps = {
|
||||||
name: string;
|
name: string;
|
||||||
|
@ -36,6 +36,7 @@ const ActionChooser = (props: ActionProps) => {
|
|||||||
keepMounted
|
keepMounted
|
||||||
open={Boolean(anchor)}
|
open={Boolean(anchor)}
|
||||||
onClose={handleOnClose(undefined)}
|
onClose={handleOnClose(undefined)}
|
||||||
|
elevation={1}
|
||||||
>
|
>
|
||||||
<MenuItem onClick={handleOnClose('open')} style={{width:"220px"}}>
|
<MenuItem onClick={handleOnClose('open')} style={{width:"220px"}}>
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { Button, DialogContentText } from "@material-ui/core";
|
import { Button, DialogContentText } from "@material-ui/core";
|
||||||
import { FormattedMessage, useIntl } from "react-intl";
|
import { FormattedMessage, useIntl } from "react-intl";
|
||||||
import { ErrorInfo } from "../../../../services/Service";
|
import { ErrorInfo } from "../../../../services";
|
||||||
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";
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ 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 { Service } from "../../../../services/Service";
|
import Service from "../../../../services";
|
||||||
import { activeInstance } from '../../../../reducers/serviceSlice';
|
import { activeInstance } from '../../../../reducers/serviceSlice';
|
||||||
import { DialogProps, fetchMapById, handleOnMutationSuccess } from "..";
|
import { DialogProps, fetchMapById, handleOnMutationSuccess } from "..";
|
||||||
import BaseDialog from "../action-dialog";
|
import BaseDialog from "../action-dialog";
|
||||||
@ -35,7 +35,7 @@ const DeleteDialog = (props: DialogProps) => {
|
|||||||
<div>
|
<div>
|
||||||
<BaseDialog
|
<BaseDialog
|
||||||
open={props.open} onClose={handleOnClose} onSubmit={handleOnSubmit}
|
open={props.open} 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?.name}'</AlertTitle>
|
<AlertTitle>Delete '{map?.name}'</AlertTitle>
|
||||||
|
@ -4,7 +4,7 @@ import { useMutation, useQueryClient } from "react-query";
|
|||||||
import { useSelector } from "react-redux";
|
import { useSelector } from "react-redux";
|
||||||
import { FormControl } from "@material-ui/core";
|
import { FormControl } from "@material-ui/core";
|
||||||
|
|
||||||
import { BasicMapInfo, ErrorInfo, Service } from "../../../../services/Service";
|
import Service, { BasicMapInfo, ErrorInfo } from "../../../../services";
|
||||||
import { activeInstance } from '../../../../reducers/serviceSlice';
|
import { activeInstance } from '../../../../reducers/serviceSlice';
|
||||||
import Input from "../../../form/input";
|
import Input from "../../../form/input";
|
||||||
import { DialogProps, fetchMapById, handleOnMutationSuccess } from "..";
|
import { DialogProps, fetchMapById, handleOnMutationSuccess } from "..";
|
||||||
@ -75,7 +75,7 @@ const DuplicateDialog = (props: DialogProps) => {
|
|||||||
title={intl.formatMessage({ id: 'duplicate.title', defaultMessage: 'Duplicate' })}
|
title={intl.formatMessage({ id: 'duplicate.title', defaultMessage: 'Duplicate' })}
|
||||||
description={intl.formatMessage({ id: 'rename.description', defaultMessage: 'Please, fill the new map name and description.' })}
|
description={intl.formatMessage({ id: 'rename.description', defaultMessage: 'Please, fill the new map name and description.' })}
|
||||||
submitButton={intl.formatMessage({ id: 'duplicate.title', defaultMessage: 'Duplicate' })}>
|
submitButton={intl.formatMessage({ id: 'duplicate.title', defaultMessage: 'Duplicate' })}>
|
||||||
|
|
||||||
<FormControl fullWidth={true}>
|
<FormControl fullWidth={true}>
|
||||||
<Input name="name" type="text" label={{ id: "action.rename-name-placeholder", defaultMessage: "Name" }}
|
<Input name="name" type="text" label={{ id: "action.rename-name-placeholder", defaultMessage: "Name" }}
|
||||||
value={model.name} onChange={handleOnChange} error={error} fullWidth={true} />
|
value={model.name} onChange={handleOnChange} error={error} fullWidth={true} />
|
||||||
@ -84,7 +84,7 @@ const DuplicateDialog = (props: DialogProps) => {
|
|||||||
value={model.description} onChange={handleOnChange} required={false} fullWidth={true} />
|
value={model.description} onChange={handleOnChange} required={false} fullWidth={true} />
|
||||||
</FormControl>
|
</FormControl>
|
||||||
</BaseDialog>
|
</BaseDialog>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,8 @@ import React from 'react';
|
|||||||
import RenameDialog from './rename';
|
import RenameDialog from './rename';
|
||||||
import DeleteDialog from './delete';
|
import DeleteDialog from './delete';
|
||||||
import { ActionType } from '../action-chooser';
|
import { ActionType } from '../action-chooser';
|
||||||
import { ErrorInfo, MapInfo, Service } from '../../../services/Service';
|
import { ErrorInfo, MapInfo } from '../../../services';
|
||||||
|
import Service from '../../../services';
|
||||||
import { useSelector } from 'react-redux';
|
import { useSelector } from 'react-redux';
|
||||||
import { QueryClient, useQuery } from 'react-query';
|
import { QueryClient, useQuery } from 'react-query';
|
||||||
import { activeInstance } from '../../../reducers/serviceSlice';
|
import { activeInstance } from '../../../reducers/serviceSlice';
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { useQueryClient } from "react-query";
|
import { useQueryClient } from "react-query";
|
||||||
import { useSelector } from "react-redux";
|
import { useSelector } from "react-redux";
|
||||||
import { Service } from "../../../../services/Service";
|
import Service from "../../../../services";
|
||||||
import { activeInstance } from '../../../../reducers/serviceSlice';
|
import { activeInstance } from '../../../../reducers/serviceSlice';
|
||||||
import { DialogProps, fetchMapById } from "..";
|
import { DialogProps, fetchMapById } from "..";
|
||||||
import BaseDialog from "../action-dialog";
|
import BaseDialog from "../action-dialog";
|
||||||
@ -26,7 +26,7 @@ const InfoDialog = (props: DialogProps) => {
|
|||||||
open={props.open} onClose={handleOnClose}
|
open={props.open} onClose={handleOnClose}
|
||||||
title={intl.formatMessage({ id: "action.info-title", defaultMessage: "Info" })}>
|
title={intl.formatMessage({ id: "action.info-title", defaultMessage: "Info" })}>
|
||||||
|
|
||||||
<iframe src="http://www.clarin.com" style={{width:'100%',height:'400px'}}/>
|
<iframe src="http://www.clarin.com" style={{ width: '100%', height: '400px' }} />
|
||||||
|
|
||||||
</BaseDialog>
|
</BaseDialog>
|
||||||
</div>
|
</div>
|
||||||
|
@ -2,7 +2,7 @@ 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 { BasicMapInfo, ErrorInfo, Service } from "../../../../services/Service";
|
import Service, { BasicMapInfo, ErrorInfo } from "../../../../services";
|
||||||
import { activeInstance } from '../../../../reducers/serviceSlice';
|
import { activeInstance } from '../../../../reducers/serviceSlice';
|
||||||
import { DialogProps, fetchMapById, handleOnMutationSuccess } from "..";
|
import { DialogProps, fetchMapById, handleOnMutationSuccess } from "..";
|
||||||
import Input from "../../../form/input";
|
import Input from "../../../form/input";
|
||||||
|
@ -7,31 +7,40 @@ import List from '@material-ui/core/List';
|
|||||||
import IconButton from '@material-ui/core/IconButton';
|
import IconButton from '@material-ui/core/IconButton';
|
||||||
import ListItem from '@material-ui/core/ListItem';
|
import ListItem from '@material-ui/core/ListItem';
|
||||||
import ListItemIcon from '@material-ui/core/ListItemIcon';
|
import ListItemIcon from '@material-ui/core/ListItemIcon';
|
||||||
import { ListItemTextStyled, useStyles } from './style';
|
import { useStyles } from './style';
|
||||||
import { AccountCircle, AddCircleTwoTone, BlurCircular, CloudUploadTwoTone, DeleteOutlineTwoTone, EmailOutlined, EmojiPeopleOutlined, ExitToAppOutlined, FeedbackOutlined, Help, LabelTwoTone, PolicyOutlined, PublicTwoTone, SettingsApplicationsOutlined, ShareTwoTone, StarRateTwoTone, Translate, TranslateTwoTone } from '@material-ui/icons';
|
import { AccountCircle, AddCircleTwoTone, BlurCircular, CloudUploadTwoTone, EmailOutlined, EmojiPeopleOutlined, ExitToAppOutlined, FeedbackOutlined, Help, LabelTwoTone, PolicyOutlined, PublicTwoTone, SettingsApplicationsOutlined, ShareTwoTone, StarRateTwoTone, Translate, TranslateTwoTone } from '@material-ui/icons';
|
||||||
import InboxTwoToneIcon from '@material-ui/icons/InboxTwoTone';
|
import InboxTwoToneIcon from '@material-ui/icons/InboxTwoTone';
|
||||||
import { Button, Link, ListItemSecondaryAction, Menu, MenuItem, Tooltip } from '@material-ui/core';
|
import { Button, 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 } from 'react-intl';
|
||||||
|
import { useQueryClient } from 'react-query';
|
||||||
const logoIcon = require('../../images/logo-small.svg')
|
const logoIcon = require('../../images/logo-small.svg')
|
||||||
const poweredByIcon = require('../../images/pwrdby-white.svg')
|
const poweredByIcon = require('../../images/pwrdby-white.svg')
|
||||||
|
|
||||||
type FilterType = 'public' | 'all' | 'starred' | 'shared' | 'label' | 'owned'
|
export type Filter = GenericFilter | LabelFilter;
|
||||||
|
|
||||||
interface Filter {
|
interface GenericFilter {
|
||||||
type: FilterType
|
type: 'public' | 'all' | 'starred' | 'shared' | 'label' | 'owned';
|
||||||
}
|
}
|
||||||
|
|
||||||
interface LabelFinter extends Filter {
|
interface LabelFilter {
|
||||||
|
type: 'label',
|
||||||
label: string
|
label: string
|
||||||
}
|
}
|
||||||
|
|
||||||
const MapsPage = (props: any) => {
|
const MapsPage = (props: any) => {
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
|
const [filter, setFilter] = React.useState<Filter>({ type: 'all' });
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
document.title = 'Maps | WiseMapping';
|
document.title = 'Maps | WiseMapping';
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const handleMenuClick = (filter: Filter) => {
|
||||||
|
setFilter(filter);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classes.root}>
|
<div className={classes.root}>
|
||||||
<AppBar
|
<AppBar
|
||||||
@ -88,53 +97,43 @@ const MapsPage = (props: any) => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<List component="nav">
|
<List component="nav">
|
||||||
<ListItem button >
|
<StyleListItem
|
||||||
<ListItemIcon>
|
icon={<InboxTwoToneIcon color="secondary" />}
|
||||||
<InboxTwoToneIcon color="secondary" />
|
label={"All"}
|
||||||
</ListItemIcon>
|
filter={{ type: 'all' }}
|
||||||
<ListItemTextStyled primary="All" />
|
active={filter}
|
||||||
</ListItem>
|
onClick={handleMenuClick}
|
||||||
|
/>
|
||||||
<ListItem button >
|
<StyleListItem
|
||||||
<ListItemIcon>
|
icon={<BlurCircular color="secondary" />}
|
||||||
<BlurCircular color="secondary" />
|
label={"Owned"}
|
||||||
</ListItemIcon>
|
filter={{ type: 'owned' }}
|
||||||
<ListItemTextStyled primary="Owned" />
|
active={filter}
|
||||||
</ListItem>
|
onClick={handleMenuClick}
|
||||||
|
/>
|
||||||
<ListItem button >
|
<StyleListItem
|
||||||
<ListItemIcon>
|
icon={<StarRateTwoTone color="secondary" />}
|
||||||
<StarRateTwoTone color="secondary" />
|
label={"Starred"}
|
||||||
</ListItemIcon>
|
filter={{ type: 'starred' }}
|
||||||
<ListItemTextStyled primary="Starred" />
|
active={filter}
|
||||||
</ListItem>
|
onClick={handleMenuClick}
|
||||||
|
/>
|
||||||
<ListItem button >
|
<StyleListItem
|
||||||
<ListItemIcon>
|
icon={<ShareTwoTone color="secondary" />}
|
||||||
<ShareTwoTone color="secondary" />
|
label={"Shared With Me"}
|
||||||
</ListItemIcon>
|
filter={{ type: 'shared' }}
|
||||||
<ListItemTextStyled primary="Shared With Me" />
|
active={filter}
|
||||||
</ListItem>
|
onClick={handleMenuClick}
|
||||||
|
/>
|
||||||
<ListItem button >
|
<StyleListItem
|
||||||
<ListItemIcon>
|
icon={<PublicTwoTone color="secondary" />}
|
||||||
<PublicTwoTone color="secondary" />
|
label={"Public"}
|
||||||
</ListItemIcon>
|
filter={{ type: 'public' }}
|
||||||
<ListItemTextStyled primary="Public" />
|
active={filter}
|
||||||
</ListItem>
|
onClick={handleMenuClick}
|
||||||
|
/>
|
||||||
<ListItem button >
|
|
||||||
<ListItemIcon>
|
|
||||||
<LabelTwoTone color="secondary" />
|
|
||||||
</ListItemIcon>
|
|
||||||
<ListItemTextStyled primary="Some label>" />
|
|
||||||
<ListItemSecondaryAction>
|
|
||||||
<IconButton edge="end" aria-label="delete">
|
|
||||||
<DeleteOutlineTwoTone color="secondary" />
|
|
||||||
</IconButton>
|
|
||||||
</ListItemSecondaryAction>
|
|
||||||
</ListItem>
|
|
||||||
</List>
|
</List>
|
||||||
|
|
||||||
<div style={{ position: 'absolute', bottom: '10px', left: '20px' }}>
|
<div style={{ position: 'absolute', bottom: '10px', left: '20px' }}>
|
||||||
<Link href="http://www.wisemapping.org/">
|
<Link href="http://www.wisemapping.org/">
|
||||||
<img src={poweredByIcon} alt="Powered By WiseMapping" />
|
<img src={poweredByIcon} alt="Powered By WiseMapping" />
|
||||||
@ -143,12 +142,50 @@ const MapsPage = (props: any) => {
|
|||||||
</Drawer>
|
</Drawer>
|
||||||
<main className={classes.content}>
|
<main className={classes.content}>
|
||||||
<div className={classes.toolbar} />
|
<div className={classes.toolbar} />
|
||||||
<MapsList />
|
<MapsList filter={filter} />
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface ListItemProps {
|
||||||
|
icon: any,
|
||||||
|
label: string,
|
||||||
|
filter: Filter,
|
||||||
|
active?: Filter
|
||||||
|
onClick: (filter: Filter) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const StyleListItem = (props: ListItemProps) => {
|
||||||
|
const icon = props.icon;
|
||||||
|
const label = props.label;
|
||||||
|
const filter = props.filter;
|
||||||
|
const activeType = props.active?.type;
|
||||||
|
const onClick = props.onClick;
|
||||||
|
|
||||||
|
const handleOnClick = (event: any, filter: Filter) => {
|
||||||
|
// Invalidate cache to provide a fresh load ...
|
||||||
|
event.stopPropagation();
|
||||||
|
onClick(filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ListItem button selected={activeType == filter.type} onClick={e => { handleOnClick(e, filter) }}>
|
||||||
|
<ListItemIcon>
|
||||||
|
{icon}
|
||||||
|
</ListItemIcon>
|
||||||
|
<ListItemText style={{ color: 'white' }} primary={label} />
|
||||||
|
|
||||||
|
{/* <ListItemSecondaryAction>
|
||||||
|
<IconButton edge="end" aria-label="delete">
|
||||||
|
<DeleteOutlineTwoTone color="secondary" />
|
||||||
|
</IconButton>
|
||||||
|
</ListItemSecondaryAction> */}
|
||||||
|
|
||||||
|
</ListItem>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const ProfileToobarButton = () => {
|
const ProfileToobarButton = () => {
|
||||||
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
|
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
|
||||||
const open = Boolean(anchorEl);
|
const open = Boolean(anchorEl);
|
||||||
@ -163,11 +200,14 @@ const ProfileToobarButton = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<span>
|
<span>
|
||||||
<IconButton
|
<Tooltip title="Paulo Veiga <pveiga@gmail.com>">
|
||||||
aria-haspopup="true"
|
<Button
|
||||||
onClick={handleMenu}>
|
aria-haspopup="true"
|
||||||
<AccountCircle fontSize="large" />
|
onClick={handleMenu}>
|
||||||
</IconButton >
|
<AccountCircle fontSize="large" />
|
||||||
|
Paulo Veiga
|
||||||
|
</Button >
|
||||||
|
</Tooltip>
|
||||||
<Menu id="appbar-profile"
|
<Menu id="appbar-profile"
|
||||||
anchorEl={anchorEl}
|
anchorEl={anchorEl}
|
||||||
keepMounted
|
keepMounted
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React from 'react'
|
import React, { useEffect } from 'react'
|
||||||
import { useStyles } from './styled';
|
import { useStyles } from './styled';
|
||||||
|
|
||||||
import Table from '@material-ui/core/Table';
|
import Table from '@material-ui/core/Table';
|
||||||
@ -21,12 +21,14 @@ import { CSSProperties } from 'react';
|
|||||||
import { useSelector } from 'react-redux';
|
import { useSelector } from 'react-redux';
|
||||||
import { activeInstance } from '../../../reducers/serviceSlice';
|
import { activeInstance } from '../../../reducers/serviceSlice';
|
||||||
import { useMutation, useQuery, useQueryClient } from 'react-query';
|
import { useMutation, useQuery, useQueryClient } from 'react-query';
|
||||||
import { ErrorInfo, MapInfo, Service } from '../../../services/Service';
|
import { ErrorInfo, MapInfo } from '../../../services';
|
||||||
|
import Service from '../../../services';
|
||||||
import ActionChooser, { ActionType } from '../action-chooser';
|
import ActionChooser, { ActionType } from '../action-chooser';
|
||||||
import ActionDispatcher from '../action-dispatcher';
|
import ActionDispatcher from '../action-dispatcher';
|
||||||
import { InputBase, Link } from '@material-ui/core';
|
import { InputBase, Link } from '@material-ui/core';
|
||||||
import SearchIcon from '@material-ui/icons/Search';
|
import SearchIcon from '@material-ui/icons/Search';
|
||||||
import moment from 'moment'
|
import moment from 'moment'
|
||||||
|
import { Filter } from '..';
|
||||||
|
|
||||||
|
|
||||||
function descendingComparator<T>(a: T, b: T, orderBy: keyof T) {
|
function descendingComparator<T>(a: T, b: T, orderBy: keyof T) {
|
||||||
@ -139,21 +141,66 @@ type ActionPanelState = {
|
|||||||
mapId: number
|
mapId: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export const MapsList = () => {
|
interface MapsListProps {
|
||||||
|
filter: Filter
|
||||||
|
}
|
||||||
|
|
||||||
|
const mapsFilter = (filter: Filter, search: string): ((mapInfo: MapInfo) => boolean) => {
|
||||||
|
return (mapInfo: MapInfo) => {
|
||||||
|
|
||||||
|
// Check for filter condition
|
||||||
|
let result = false;
|
||||||
|
switch (filter.type) {
|
||||||
|
case 'all':
|
||||||
|
result = true;
|
||||||
|
break;
|
||||||
|
case 'public':
|
||||||
|
result = mapInfo.isPublic;
|
||||||
|
break;
|
||||||
|
case 'starred':
|
||||||
|
result = mapInfo.starred;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Does it match search filter criteria...
|
||||||
|
if (search && result) {
|
||||||
|
result = mapInfo.name.toLowerCase().indexOf(search.toLowerCase()) != -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const MapsList = (props: MapsListProps) => {
|
||||||
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 [orderBy, setOrderBy] = React.useState<keyof MapInfo>('modified');
|
const [orderBy, setOrderBy] = React.useState<keyof MapInfo>('modified');
|
||||||
const [selected, setSelected] = React.useState<number[]>([]);
|
const [selected, setSelected] = React.useState<number[]>([]);
|
||||||
|
const [searchCondition, setSearchCondition] = React.useState<string>('');
|
||||||
|
|
||||||
const [page, setPage] = React.useState(0);
|
const [page, setPage] = React.useState(0);
|
||||||
const [rowsPerPage, setRowsPerPage] = React.useState(5);
|
const [rowsPerPage, setRowsPerPage] = React.useState(10);
|
||||||
const service: Service = useSelector(activeInstance);
|
const service: Service = useSelector(activeInstance);
|
||||||
|
|
||||||
const { isLoading, error, data } = useQuery<unknown, ErrorInfo, MapInfo[]>('maps', async () => {
|
useEffect(() => {
|
||||||
|
console.log("Update maps state.")
|
||||||
|
setSelected([]);
|
||||||
|
setSearchCondition('');
|
||||||
|
setPage(0);
|
||||||
|
setFilter(props.filter)
|
||||||
|
queryClient.invalidateQueries('maps');
|
||||||
|
|
||||||
const result = await service.fetchAllMaps();
|
}, [props.filter.type]);
|
||||||
return result;
|
|
||||||
|
|
||||||
|
const { isLoading, error, data } = useQuery<unknown, ErrorInfo, MapInfo[]>('maps', async () => {
|
||||||
|
return await service.fetchAllMaps();
|
||||||
});
|
});
|
||||||
const mapsInfo: MapInfo[] = data ? data : [];
|
const mapsInfo: MapInfo[] = data ? data.filter(mapsFilter(filter, searchCondition)) : [];
|
||||||
|
|
||||||
|
|
||||||
const [activeRowAction, setActiveRowAction] = React.useState<ActionPanelState | undefined>(undefined);
|
const [activeRowAction, setActiveRowAction] = React.useState<ActionPanelState | undefined>(undefined);
|
||||||
@ -236,8 +283,6 @@ export const MapsList = () => {
|
|||||||
|
|
||||||
const handleStarred = (event: React.MouseEvent<HTMLButtonElement, MouseEvent>, id: number) => {
|
const handleStarred = (event: React.MouseEvent<HTMLButtonElement, MouseEvent>, id: number) => {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
|
|
||||||
event.preventDefault();
|
|
||||||
starredMultation.mutate(id);
|
starredMultation.mutate(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -253,9 +298,11 @@ export const MapsList = () => {
|
|||||||
setActiveRowAction(undefined);
|
setActiveRowAction(undefined);
|
||||||
};
|
};
|
||||||
|
|
||||||
const isSelected = (id: number) => selected.indexOf(id) !== -1;
|
const handleOnSearchChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
const emptyRows = rowsPerPage - Math.min(rowsPerPage, mapsInfo.length - page * rowsPerPage);
|
setSearchCondition(e.target.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
const isSelected = (id: number) => selected.indexOf(id) !== -1;
|
||||||
return (
|
return (
|
||||||
<div className={classes.root}>
|
<div className={classes.root}>
|
||||||
<Paper className={classes.paper} elevation={0}>
|
<Paper className={classes.paper} elevation={0}>
|
||||||
@ -276,7 +323,6 @@ export const MapsList = () => {
|
|||||||
<div className={classes.toolbarListActions}>
|
<div className={classes.toolbarListActions}>
|
||||||
<TablePagination
|
<TablePagination
|
||||||
style={{ float: 'right', border: "0", paddingBottom: "5px" }}
|
style={{ float: 'right', border: "0", paddingBottom: "5px" }}
|
||||||
rowsPerPageOptions={[50]}
|
|
||||||
count={mapsInfo.length}
|
count={mapsInfo.length}
|
||||||
rowsPerPage={rowsPerPage}
|
rowsPerPage={rowsPerPage}
|
||||||
page={page}
|
page={page}
|
||||||
@ -295,6 +341,7 @@ export const MapsList = () => {
|
|||||||
input: classes.searchInputInput,
|
input: classes.searchInputInput,
|
||||||
}}
|
}}
|
||||||
inputProps={{ 'aria-label': 'search' }}
|
inputProps={{ 'aria-label': 'search' }}
|
||||||
|
onChange={handleOnSearchChange}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -17,7 +17,10 @@ export const useStyles = makeStyles((theme: Theme) =>
|
|||||||
'& tr:nth-child(odd)':
|
'& tr:nth-child(odd)':
|
||||||
{
|
{
|
||||||
background: 'rgba(221, 221, 221, 0.35)'
|
background: 'rgba(221, 221, 221, 0.35)'
|
||||||
}
|
},
|
||||||
|
// '&:hover tr': {
|
||||||
|
// backgroundColor: 'rgba(150, 150, 150, 0.7)',
|
||||||
|
// }
|
||||||
},
|
},
|
||||||
headerCell: {
|
headerCell: {
|
||||||
background: 'white',
|
background: 'white',
|
||||||
@ -26,7 +29,7 @@ export const useStyles = makeStyles((theme: Theme) =>
|
|||||||
border: 0
|
border: 0
|
||||||
},
|
},
|
||||||
bodyCell: {
|
bodyCell: {
|
||||||
border: 0
|
border: '0px'
|
||||||
},
|
},
|
||||||
visuallyHidden: {
|
visuallyHidden: {
|
||||||
border: 0,
|
border: 0,
|
||||||
@ -66,7 +69,7 @@ export const useStyles = makeStyles((theme: Theme) =>
|
|||||||
float: 'right'
|
float: 'right'
|
||||||
},
|
},
|
||||||
searchIcon: {
|
searchIcon: {
|
||||||
padding: '5px 0 0 5px',
|
padding: '6px 0 0 5px',
|
||||||
height: '100%',
|
height: '100%',
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
pointerEvents: 'none',
|
pointerEvents: 'none',
|
||||||
|
@ -66,20 +66,11 @@ export const useStyles = makeStyles((theme: Theme) =>
|
|||||||
toolbar: {
|
toolbar: {
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
justifyContent: 'flex-end',
|
justifyContent: 'flex-end',
|
||||||
// necessary for content to be below app bar
|
minHeight: '44px'
|
||||||
...theme.mixins.toolbar,
|
|
||||||
},
|
},
|
||||||
content: {
|
content: {
|
||||||
flexGrow: 1,
|
flexGrow: 1,
|
||||||
padding: theme.spacing(3),
|
padding: theme.spacing(3),
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
export const ListItemTextStyled = withStyles({
|
|
||||||
root:
|
|
||||||
{
|
|
||||||
color: 'white',
|
|
||||||
}
|
|
||||||
})(ListItemText);
|
|
@ -2,7 +2,7 @@ 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 { ErrorInfo, Service } from '../../services/Service';
|
import Service , { ErrorInfo} from '../../services';
|
||||||
import FormContainer from '../layout/form-container';
|
import FormContainer from '../layout/form-container';
|
||||||
|
|
||||||
import Header from '../layout/header';
|
import Header from '../layout/header';
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { createSlice, PayloadAction } from '@reduxjs/toolkit'
|
import { createSlice, PayloadAction } from '@reduxjs/toolkit'
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { ErrorInfo } from 'react';
|
import Service from '../services';
|
||||||
import { RestService, Service } from '../services/Service';
|
import MockService from '../services/mock-service';
|
||||||
|
|
||||||
type RutimeConfig = {
|
type RutimeConfig = {
|
||||||
apiBaseUrl: string;
|
apiBaseUrl: string;
|
||||||
@ -38,7 +38,7 @@ interface ServiceState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const initialState: ServiceState = {
|
const initialState: ServiceState = {
|
||||||
instance: new RestService("", () => { console.log("401 error") })
|
instance: new MockService("", () => { console.log("401 error") })
|
||||||
};
|
};
|
||||||
|
|
||||||
export const serviceSlice = createSlice({
|
export const serviceSlice = createSlice({
|
||||||
@ -46,7 +46,7 @@ export const serviceSlice = createSlice({
|
|||||||
initialState: initialState,
|
initialState: initialState,
|
||||||
reducers: {
|
reducers: {
|
||||||
initialize(state, action: PayloadAction<void[]>) {
|
initialize(state, action: PayloadAction<void[]>) {
|
||||||
state.instance = new RestService("", () => { console.log("401 error") });
|
state.instance = new MockService("", () => { console.log("401 error") });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
48
packages/webapp/src/services/index.ts
Normal file
48
packages/webapp/src/services/index.ts
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
export type NewUser = {
|
||||||
|
email: string;
|
||||||
|
firstname: string;
|
||||||
|
lastname: string;
|
||||||
|
password: string;
|
||||||
|
recaptcha: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type MapInfo = {
|
||||||
|
id: number;
|
||||||
|
starred: boolean;
|
||||||
|
name: string;
|
||||||
|
labels: string[];
|
||||||
|
creator: string;
|
||||||
|
modified: number;
|
||||||
|
description: string;
|
||||||
|
isPublic: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type BasicMapInfo = {
|
||||||
|
name: string;
|
||||||
|
description?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type FieldError = {
|
||||||
|
id: string,
|
||||||
|
msg: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ErrorInfo = {
|
||||||
|
msg?: string;
|
||||||
|
fields?: Map<String, String>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Service {
|
||||||
|
registerNewUser(user: NewUser): Promise<void>;
|
||||||
|
resetPassword(email: string): Promise<void>;
|
||||||
|
fetchAllMaps(): Promise<MapInfo[]>;
|
||||||
|
|
||||||
|
deleteMap(id: number): Promise<void>;
|
||||||
|
renameMap(id: number, basicInfo: BasicMapInfo): Promise<void>;
|
||||||
|
duplicateMap(id: number, basicInfo: BasicMapInfo): Promise<void>;
|
||||||
|
loadMapInfo(id: number): Promise<BasicMapInfo>;
|
||||||
|
changeStarred(id: number): Promise<void>;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export default Service;
|
@ -1,49 +1,6 @@
|
|||||||
import axios from 'axios'
|
import { BasicMapInfo, ErrorInfo, MapInfo, NewUser } from "..";
|
||||||
|
import Service from "..";
|
||||||
export type NewUser = {
|
import axios from "axios";
|
||||||
email: string;
|
|
||||||
firstname: string;
|
|
||||||
lastname: string;
|
|
||||||
password: string;
|
|
||||||
recaptcha: string | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type MapInfo = {
|
|
||||||
id: number;
|
|
||||||
starred: boolean;
|
|
||||||
name: string;
|
|
||||||
labels: string[];
|
|
||||||
creator: string;
|
|
||||||
modified: number;
|
|
||||||
description: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type BasicMapInfo = {
|
|
||||||
name: string;
|
|
||||||
description?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type FieldError = {
|
|
||||||
id: string,
|
|
||||||
msg: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export type ErrorInfo = {
|
|
||||||
msg?: string;
|
|
||||||
fields?: Map<String, String>;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Service {
|
|
||||||
registerNewUser(user: NewUser): Promise<void>;
|
|
||||||
resetPassword(email: string): Promise<void>;
|
|
||||||
fetchAllMaps(): Promise<MapInfo[]>;
|
|
||||||
|
|
||||||
deleteMap(id: number): Promise<void>;
|
|
||||||
renameMap(id: number, basicInfo: BasicMapInfo): Promise<void>;
|
|
||||||
duplicateMap(id: number, basicInfo: BasicMapInfo): Promise<void>;
|
|
||||||
loadMapInfo(id: number): Promise<BasicMapInfo>;
|
|
||||||
changeStarred(id: number): Promise<void>;
|
|
||||||
}
|
|
||||||
|
|
||||||
class MockService implements Service {
|
class MockService implements Service {
|
||||||
private baseUrl: string;
|
private baseUrl: string;
|
||||||
@ -61,14 +18,24 @@ class MockService implements Service {
|
|||||||
labels: string[],
|
labels: string[],
|
||||||
creator: string,
|
creator: string,
|
||||||
modified: number,
|
modified: number,
|
||||||
description: string
|
description: string,
|
||||||
|
isPublic: boolean
|
||||||
): MapInfo {
|
): MapInfo {
|
||||||
return { id, name, labels, creator, modified, starred, description };
|
return { id, name, labels, creator, modified, starred, description, isPublic };
|
||||||
}
|
}
|
||||||
this.maps = [
|
this.maps = [
|
||||||
createMapInfo(1, true, "El Mapa", [""], "Paulo", 67, ""),
|
createMapInfo(1, true, "El Mapa", [""], "Paulo", 67, "", true),
|
||||||
createMapInfo(2, false, "El Mapa2", [""], "Paulo2", 67, ""),
|
createMapInfo(2, false, "El Mapa2", [""], "Paulo2", 67, "", false),
|
||||||
createMapInfo(3, false, "El Mapa3", [""], "Paulo3", 67, "")
|
createMapInfo(3, false, "El Mapa3", [""], "Paulo3", 67, "", false),
|
||||||
|
createMapInfo(4, false, "El Mapa3", [""], "Paulo3", 67, "", false),
|
||||||
|
createMapInfo(5, false, "El Mapa3", [""], "Paulo3", 67, "", false),
|
||||||
|
createMapInfo(6, false, "El Mapa3", [""], "Paulo3", 67, "", false),
|
||||||
|
createMapInfo(7, false, "El Mapa3", [""], "Paulo3", 67, "", false),
|
||||||
|
createMapInfo(8, false, "El Mapa3", [""], "Paulo3", 67, "", false),
|
||||||
|
createMapInfo(9, false, "El Mapa3", [""], "Paulo3", 67, "", false),
|
||||||
|
createMapInfo(10, false, "El Mapa3", [""], "Paulo3", 67, "", false),
|
||||||
|
createMapInfo(11, false, "El Mapa3", [""], "Paulo3", 67, "", false),
|
||||||
|
createMapInfo(12, false, "El Mapa3", [""], "Paulo3", 67, "", false)
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,7 +79,7 @@ class MockService implements Service {
|
|||||||
})
|
})
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
duplicateMap(id: number, basicInfo: BasicMapInfo): Promise<void> {
|
duplicateMap(id: number, basicInfo: BasicMapInfo): Promise<void> {
|
||||||
|
|
||||||
const exists = this.maps.find(m => m.name == basicInfo.name) != undefined;
|
const exists = this.maps.find(m => m.name == basicInfo.name) != undefined;
|
||||||
@ -125,7 +92,8 @@ class MockService implements Service {
|
|||||||
starred: false,
|
starred: false,
|
||||||
creator: "current user",
|
creator: "current user",
|
||||||
labels: [],
|
labels: [],
|
||||||
modified: -1
|
modified: -1,
|
||||||
|
isPublic: false
|
||||||
};
|
};
|
||||||
this.maps.push(newMap);
|
this.maps.push(newMap);
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
@ -164,6 +132,7 @@ class MockService implements Service {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fetchAllMaps(): Promise<MapInfo[]> {
|
fetchAllMaps(): Promise<MapInfo[]> {
|
||||||
|
console.log("Fetch maps from server")
|
||||||
return Promise.resolve(this.maps);
|
return Promise.resolve(this.maps);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -229,6 +198,6 @@ class MockService implements Service {
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
export { Service, MockService as RestService }
|
|
||||||
|
export default MockService;
|
Loading…
Reference in New Issue
Block a user