Fix dialog missing msg.

This commit is contained in:
Paulo Gustavo Veiga 2021-01-27 17:27:19 -08:00
parent 2a6782f165
commit 1b7f172518
18 changed files with 456 additions and 267 deletions

View File

@ -2,6 +2,9 @@
"action.cancel-button": { "action.cancel-button": {
"defaultMessage": "Cancel" "defaultMessage": "Cancel"
}, },
"action.close-button": {
"defaultMessage": "Close"
},
"action.delete": { "action.delete": {
"defaultMessage": "Delete" "defaultMessage": "Delete"
}, },
@ -20,6 +23,9 @@
"action.info": { "action.info": {
"defaultMessage": "Info" "defaultMessage": "Info"
}, },
"action.info-title": {
"defaultMessage": "Info"
},
"action.open": { "action.open": {
"defaultMessage": "Open" "defaultMessage": "Open"
}, },
@ -38,6 +44,9 @@
"common.wait": { "common.wait": {
"defaultMessage": "Please wait ..." "defaultMessage": "Please wait ..."
}, },
"duplicate.title": {
"defaultMessage": "Duplicate"
},
"footer.aboutus": { "footer.aboutus": {
"defaultMessage": "About Us" "defaultMessage": "About Us"
}, },
@ -126,6 +135,12 @@
"registration.title": { "registration.title": {
"defaultMessage": "Become a member" "defaultMessage": "Become a member"
}, },
"rename.description": {
"defaultMessage": "Please, fill the new map name and description."
},
"rename.title": {
"defaultMessage": "Rename"
},
"resetpassword.success.title": { "resetpassword.success.title": {
"defaultMessage": "Your account has been created successfully" "defaultMessage": "Your account has been created successfully"
} }

View File

@ -42,7 +42,7 @@
"webpack-dev-server": "^3.11.0" "webpack-dev-server": "^3.11.0"
}, },
"dependencies": { "dependencies": {
"@material-ui/core": "^4.11.2", "@material-ui/core": "^4.11.1",
"@material-ui/icons": "^4.11.2", "@material-ui/icons": "^4.11.2",
"@material-ui/lab": "^4.0.0-alpha.57", "@material-ui/lab": "^4.0.0-alpha.57",
"@reduxjs/toolkit": "^1.5.0", "@reduxjs/toolkit": "^1.5.0",
@ -57,4 +57,4 @@
"react-router-dom": "^5.2.0", "react-router-dom": "^5.2.0",
"styled-components": "^5.1.7" "styled-components": "^5.1.7"
} }
} }

View File

@ -5,6 +5,12 @@
"value": "Cancel" "value": "Cancel"
} }
], ],
"action.close-button": [
{
"type": 0,
"value": "Close"
}
],
"action.delete": [ "action.delete": [
{ {
"type": 0, "type": 0,
@ -41,6 +47,12 @@
"value": "Info" "value": "Info"
} }
], ],
"action.info-title": [
{
"type": 0,
"value": "Info"
}
],
"action.open": [ "action.open": [
{ {
"type": 0, "type": 0,
@ -77,6 +89,12 @@
"value": "Please wait ..." "value": "Please wait ..."
} }
], ],
"duplicate.title": [
{
"type": 0,
"value": "Duplicate"
}
],
"footer.aboutus": [ "footer.aboutus": [
{ {
"type": 0, "type": 0,
@ -251,6 +269,18 @@
"value": "Become a member" "value": "Become a member"
} }
], ],
"rename.description": [
{
"type": 0,
"value": "Please, fill the new map name and description."
}
],
"rename.title": [
{
"type": 0,
"value": "Rename"
}
],
"resetpassword.success.title": [ "resetpassword.success.title": [
{ {
"type": 0, "type": 0,

View File

@ -1,78 +1,116 @@
{ {
"footer.aboutus": [{ "footer.aboutus": [
"type": 0, {
"value": "Sobre Nosotros" "type": 0,
}], "value": "Sobre Nosotros"
"footer.contactus": [{ }
"type": 0, ],
"value": "Contáctenos" "footer.contactus": [
}], {
"footer.donations": [{ "type": 0,
"type": 0, "value": "Contáctenos"
"value": "Donaciones" }
}], ],
"footer.faq": [{ "footer.donations": [
"type": 0, {
"value": "Preguntas Frecuentes" "type": 0,
}], "value": "Donaciones"
"footer.feedback": [{ }
"type": 0, ],
"value": "Feedback" "footer.faq": [
}], {
"footer.opensource": [{ "type": 0,
"type": 0, "value": "Preguntas Frecuentes"
"value": "Open Source" }
}], ],
"footer.termsandconditions": [{ "footer.feedback": [
"type": 0, {
"value": "Terminos y Condiciones" "type": 0,
}], "value": "Feedback"
"header.donthaveaccount": [{ }
"type": 0, ],
"value": "No tienes una cuenta ?" "footer.opensource": [
}], {
"login.email": [{ "type": 0,
"type": 0, "value": "Open Source"
"value": "Email" }
}], ],
"login.error": [{ "footer.termsandconditions": [
"type": 0, {
"value": "El email o la contraseña no es valida." "type": 0,
}], "value": "Terminos y Condiciones"
"login.forgotpwd": [{ }
"type": 0, ],
"value": "Olvidaste la contraseña ?" "header.donthaveaccount": [
}], {
"login.hsqldbcofig": [{ "type": 0,
"type": 0, "value": "No tienes una cuenta ?"
"value": "Warning: Although HSQLDB is bundled with WiseMapping by default during the installation, we do not recommend this database for production use. Please consider using MySQL 5.7 instead. You can find more information how to configure MySQL" }
}], ],
"login.loginto": [{ "login.email": [
"type": 0, {
"value": "Ingresar a tu Cuenta" "type": 0,
}], "value": "Email"
"login.password": [{ }
"type": 0, ],
"value": "Contraseña" "login.error": [
}], {
"login.remberme": [{ "type": 0,
"type": 0, "value": "El email o la contraseña no es valida."
"value": "Recordarme" }
}], ],
"login.signin": [{ "login.forgotpwd": [
"type": 0, {
"value": "Ingresar" "type": 0,
}], "value": "Olvidaste la contraseña ?"
"login.signup": [{ }
"type": 0, ],
"value": "Registrarse" "login.hsqldbcofig": [
}], {
"login.userinactive": [{ "type": 0,
"type": 0, "value": "Warning: Although HSQLDB is bundled with WiseMapping by default during the installation, we do not recommend this database for production use. Please consider using MySQL 5.7 instead. You can find more information how to configure MySQL"
"value": "Sorry, your account has not been activated yet. You'll receive a notification email when it becomes active. Stay tuned!." }
}], ],
"login.welcome": [{ "login.loginto": [
"type": 0, {
"value": "Bienvenido" "type": 0,
}] "value": "Ingresar a tu Cuenta"
}
],
"login.password": [
{
"type": 0,
"value": "Contraseña"
}
],
"login.remberme": [
{
"type": 0,
"value": "Recordarme"
}
],
"login.signin": [
{
"type": 0,
"value": "Ingresar"
}
],
"login.signup": [
{
"type": 0,
"value": "Registrarse"
}
],
"login.userinactive": [
{
"type": 0,
"value": "Sorry, your account has not been activated yet. You'll receive a notification email when it becomes active. Stay tuned!."
}
],
"login.welcome": [
{
"type": 0,
"value": "Bienvenido"
}
]
} }

View File

@ -9,10 +9,10 @@ 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 { StyledMenuItem } from '../maps-list/styled'; import { StyledMenuItem } from './styled';
import { FormattedMessage } from 'react-intl'; import { FormattedMessage } from 'react-intl';
export type ActionType = 'open' | 'share' | 'delete' | 'info' | 'duplicate' | 'export' | 'rename' | 'print' | 'info' | 'publish' | undefined; export type ActionType = 'open' | 'share' | 'delete' | 'info' | 'duplicate' | 'export' | 'rename' | 'print' | 'info' | 'publish' | 'history'| undefined;
interface ActionProps { interface ActionProps {
onClose: (action: ActionType) => void; onClose: (action: ActionType) => void;
@ -36,6 +36,7 @@ const ActionChooser = (props: ActionProps) => {
keepMounted keepMounted
open={Boolean(anchor)} open={Boolean(anchor)}
onClose={handleOnClose(undefined)} onClose={handleOnClose(undefined)}
> >
<StyledMenuItem onClick={handleOnClose('open')}> <StyledMenuItem onClick={handleOnClose('open')}>
<DescriptionOutlinedIcon /><FormattedMessage id="action.open" defaultMessage="Open" /> <DescriptionOutlinedIcon /><FormattedMessage id="action.open" defaultMessage="Open" />
@ -70,6 +71,11 @@ const ActionChooser = (props: ActionProps) => {
<MenuItem onClick={handleOnClose('info')}> <MenuItem onClick={handleOnClose('info')}>
<InfoOutlinedIcon /><FormattedMessage id="action.info" defaultMessage="Info" /> <InfoOutlinedIcon /><FormattedMessage id="action.info" defaultMessage="Info" />
</MenuItem> </MenuItem>
<MenuItem onClick={handleOnClose('history')}>
<DeleteOutlinedIcon /><FormattedMessage id="action.delete" defaultMessage="History" />
</MenuItem>
</Menu>); </Menu>);
} }

View File

@ -0,0 +1,10 @@
import { MenuItem, withStyles } from "@material-ui/core";
export const StyledMenuItem = withStyles({
root: {
width: '300px',
padding: '10px 20px',
marging: '0px 20px'
}
})(MenuItem)

View File

@ -1,6 +1,6 @@
import React from "react"; import React from "react";
import { Button, DialogContentText, DialogTitle } from "@material-ui/core"; import { Button, DialogContentText } from "@material-ui/core";
import { FormattedMessage, MessageDescriptor, useIntl } from "react-intl"; import { FormattedMessage, useIntl } from "react-intl";
import { ErrorInfo } from "../../../../services/Service"; import { ErrorInfo } from "../../../../services/Service";
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";
@ -12,9 +12,9 @@ export type DialogProps = {
children: any; children: any;
error?: ErrorInfo; error?: ErrorInfo;
title: MessageDescriptor; title: string;
description?: MessageDescriptor; description?: string;
submitButton?: MessageDescriptor; submitButton?: string;
} }
const BaseDialog = (props: DialogProps) => { const BaseDialog = (props: DialogProps) => {
@ -23,7 +23,7 @@ const BaseDialog = (props: DialogProps) => {
const isOpen = props.open; const isOpen = props.open;
const handleOnSubmit = props.onSubmit; const handleOnSubmit = props.onSubmit;
const description = props.description ? (<DialogContentText>{intl.formatMessage(props.description)}</DialogContentText>) : null; const description = props.description ? (<DialogContentText>{props.description}</DialogContentText>) : null;
return ( return (
<div> <div>
@ -34,7 +34,7 @@ const BaseDialog = (props: DialogProps) => {
fullWidth={true}> fullWidth={true}>
<form autoComplete="off" onSubmit={handleOnSubmit}> <form autoComplete="off" onSubmit={handleOnSubmit}>
<StyledDialogTitle> <StyledDialogTitle>
{intl.formatMessage(props.title)} {props.title}
</StyledDialogTitle> </StyledDialogTitle>
<StyledDialogContent> <StyledDialogContent>
@ -49,7 +49,7 @@ const BaseDialog = (props: DialogProps) => {
</Button> </Button>
{handleOnSubmit ? ( {handleOnSubmit ? (
<Button color="primary" size="medium" variant="contained" type="submit" disableElevation={true}> <Button color="primary" size="medium" variant="contained" type="submit" disableElevation={true}>
{intl.formatMessage(props.title)} {props.title}
</Button>) : null </Button>) : null
} }
</StyledDialogActions> </StyledDialogActions>

View File

@ -10,6 +10,8 @@ import BaseDialog from "../action-dialog";
const DeleteDialog = (props: DialogProps) => { const DeleteDialog = (props: DialogProps) => {
const intl = useIntl();
const service: Service = useSelector(activeInstance); const service: Service = useSelector(activeInstance);
const queryClient = useQueryClient(); const queryClient = useQueryClient();
const mutation = useMutation((id: number) => service.deleteMap(id), const mutation = useMutation((id: number) => service.deleteMap(id),
@ -33,8 +35,8 @@ const DeleteDialog = (props: DialogProps) => {
<div> <div>
<BaseDialog <BaseDialog
open={props.open} onClose={handleOnClose} onSubmit={handleOnSubmit} open={props.open} onClose={handleOnClose} onSubmit={handleOnSubmit}
title={{ id: "action.delete-title", defaultMessage: "Delete" }} title={intl.formatMessage({ id: "action.delete-title", defaultMessage: "Delete" })}
submitButton={{ 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>
<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 ?." />

View File

@ -2,10 +2,11 @@ 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 { FormControl } from "@material-ui/core";
import { BasicMapInfo, ErrorInfo, Service } from "../../../../services/Service"; import { BasicMapInfo, ErrorInfo, Service } from "../../../../services/Service";
import { activeInstance } from '../../../../reducers/serviceSlice'; import { activeInstance } from '../../../../reducers/serviceSlice';
import Input from "../../../form/input"; import Input from "../../../form/input";
import { FormControl } from "@material-ui/core";
import { DialogProps, fetchMapById, handleOnMutationSuccess } from ".."; import { DialogProps, fetchMapById, handleOnMutationSuccess } from "..";
import BaseDialog from "../action-dialog"; import BaseDialog from "../action-dialog";
@ -71,10 +72,10 @@ const DuplicateDialog = (props: DialogProps) => {
return ( return (
<div> <div>
<BaseDialog open={open} onClose={handleOnClose} onSubmit={handleOnSubmit} error={error} <BaseDialog open={open} onClose={handleOnClose} onSubmit={handleOnSubmit} error={error}
title={{ id: 'duplicate.title', defaultMessage: 'Duplicate' }} title={intl.formatMessage({ id: 'duplicate.title', defaultMessage: 'Duplicate' })}
description={{ 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={{ 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} />

View File

@ -5,12 +5,14 @@ import { Service } from "../../../../services/Service";
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";
import { useIntl } from "react-intl";
const InfoDialog = (props: DialogProps) => { const InfoDialog = (props: DialogProps) => {
const service: Service = useSelector(activeInstance); const service: Service = useSelector(activeInstance);
const queryClient = useQueryClient(); const queryClient = useQueryClient();
const intl = useIntl();
const mapId = props.mapId; const mapId = props.mapId;
const handleOnClose = (): void => { const handleOnClose = (): void => {
@ -22,7 +24,7 @@ const InfoDialog = (props: DialogProps) => {
<div> <div>
<BaseDialog <BaseDialog
open={props.open} onClose={handleOnClose} open={props.open} onClose={handleOnClose}
title={{ 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'}}/>

View File

@ -71,9 +71,9 @@ const RenameDialog = (props: DialogProps) => {
return ( return (
<div> <div>
<BaseDialog open={open} onClose={handleOnClose} onSubmit={handleOnSubmit} error={error} <BaseDialog open={open} onClose={handleOnClose} onSubmit={handleOnSubmit} error={error}
title={{ id: 'rename.title', defaultMessage: 'Rename' }} title={intl.formatMessage({ id: 'rename.title', defaultMessage: 'Rename' })}
description={{ 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={{ id: 'rename.title', defaultMessage: 'Rename' }}> submitButton={intl.formatMessage({ id: 'rename.title', defaultMessage: 'Rename' })}>
<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" }}

View File

@ -10,11 +10,11 @@ import MenuIcon from '@material-ui/icons/Menu';
import ChevronLeftIcon from '@material-ui/icons/ChevronLeft'; import ChevronLeftIcon from '@material-ui/icons/ChevronLeft';
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 { MapsList } from './maps-list';
import { ListItemTextStyled, useStyles } from './style'; import { ListItemTextStyled, useStyles } from './style';
import { AddTwoTone, BlurCircular, DeleteOutlineTwoTone, LabelTwoTone, PublicTwoTone, ShareTwoTone, StarRateTwoTone } from '@material-ui/icons'; import { AccountCircle, AddTwoTone, BlurCircular, DeleteOutlineTwoTone, LabelTwoTone, PublicTwoTone, PublishTwoTone, ShareTwoTone, StarRateTwoTone, Translate, TranslateTwoTone } from '@material-ui/icons';
import InboxTwoToneIcon from '@material-ui/icons/InboxTwoTone'; import InboxTwoToneIcon from '@material-ui/icons/InboxTwoTone';
import { Button, ListItemSecondaryAction } from '@material-ui/core'; import { Button, ListItemSecondaryAction, Tooltip } from '@material-ui/core';
import { MapsList } from './maps-list';
type FilterType = 'public' | 'all' | 'starred' | 'shared' | 'label' | 'owned' type FilterType = 'public' | 'all' | 'starred' | 'shared' | 'label' | 'owned'
@ -44,107 +44,127 @@ const MapsPage = (props: any) => {
return ( return (
<div className={classes.root}> <div className={classes.root}>
<AppBar <AppBar
position="fixed" position="fixed"
className={clsx(classes.appBar, { className={clsx(classes.appBar, {
[classes.appBarShift]: open, [classes.appBarShift]: open,
})}> })}>
<Toolbar> <Toolbar variant="regular">
<IconButton <IconButton color="inherit" onClick={handleDrawerOpen} edge="start"
color="inherit" className={clsx(classes.menuButton, {
aria-label="open drawer" [classes.hide]: open,
onClick={handleDrawerOpen} })}>
edge="start" <MenuIcon />
className={clsx(classes.menuButton, { </IconButton>
[classes.hide]: open,
})}>
<MenuIcon />
</IconButton>
<Button color="primary" size="medium" variant="contained" type="button" <Tooltip title="Create a New Map">
disableElevation={true} startIcon={<AddTwoTone />}> <Button color="primary" size="medium" variant="contained" type="button"
disableElevation={true} startIcon={<AddTwoTone />} className={classes.newMapButton}>
New Map New Map
</Button> </Button>
</Toolbar> </Tooltip>
</AppBar>
<Drawer <Tooltip title="Import from other mindmap tools">
variant="permanent" <Button color="primary" size="medium" variant="outlined" type="button"
className={clsx(classes.drawer, { disableElevation={true} startIcon={<PublishTwoTone />} className={classes.importButton}>
[classes.drawerOpen]: open, Import
[classes.drawerClose]: !open, </Button>
})} </Tooltip>
classes={{
paper: clsx({
[classes.drawerOpen]: open, <div className={classes.rightButtonGroup}>
[classes.drawerClose]: !open, <IconButton
}), aria-label="account of current user"
}}> aria-controls="menu-appbar"
<div className={classes.toolbar}> aria-haspopup="true"
<IconButton onClick={handleDrawerClose}> // onClick={handleMenu}
{<ChevronLeftIcon />} >
<AccountCircle fontSize="large" />
</IconButton> </IconButton>
</div> </div>
<Divider />
<List component="nav">
<ListItem button >
<ListItemIcon>
<InboxTwoToneIcon color="secondary" />
</ListItemIcon>
<ListItemTextStyled primary="All" />
</ListItem>
<ListItem button > </Toolbar>
<ListItemIcon> </AppBar>
<BlurCircular color="secondary" />
</ListItemIcon>
<ListItemTextStyled primary="Owned" />
</ListItem>
<ListItem button > <Drawer
<ListItemIcon> variant="permanent"
<StarRateTwoTone color="secondary" /> className={clsx(classes.drawer, {
</ListItemIcon> [classes.drawerOpen]: open,
<ListItemTextStyled primary="Starred" /> [classes.drawerClose]: !open,
</ListItem> })}
classes={{
paper: clsx({
[classes.drawerOpen]: open,
[classes.drawerClose]: !open,
}),
}}>
<div className={classes.toolbar}>
<IconButton onClick={handleDrawerClose}>
{<ChevronLeftIcon />}
</IconButton>
</div>
<Divider />
<ListItem button > <List component="nav">
<ListItemIcon>
<ShareTwoTone color="secondary" />
</ListItemIcon>
<ListItemTextStyled primary="Shared With Me" />
</ListItem>
<ListItem button > <ListItem button >
<ListItemIcon> <ListItemIcon>
<PublicTwoTone color="secondary" /> <InboxTwoToneIcon color="secondary" />
</ListItemIcon> </ListItemIcon>
<ListItemTextStyled primary="Public" /> <ListItemTextStyled primary="All" />
</ListItem> </ListItem>
<ListItem button > <ListItem button >
<ListItemIcon> <ListItemIcon>
<LabelTwoTone color="secondary" /> <BlurCircular color="secondary" />
</ListItemIcon> </ListItemIcon>
<ListItemTextStyled primary="Some label>" /> <ListItemTextStyled primary="Owned" />
<ListItemSecondaryAction> </ListItem>
<IconButton edge="end" aria-label="delete">
<DeleteOutlineTwoTone color="secondary" />
</IconButton>
</ListItemSecondaryAction>
</ListItem>
</List> <ListItem button >
</Drawer> <ListItemIcon>
<main className={classes.content}> <StarRateTwoTone color="secondary" />
<div className={classes.toolbar} /> </ListItemIcon>
<MapsList /> <ListItemTextStyled primary="Starred" />
</main> </ListItem>
</div>
); <ListItem button >
<ListItemIcon>
<ShareTwoTone color="secondary" />
</ListItemIcon>
<ListItemTextStyled primary="Shared With Me" />
</ListItem>
<ListItem button >
<ListItemIcon>
<PublicTwoTone color="secondary" />
</ListItemIcon>
<ListItemTextStyled primary="Public" />
</ListItem>
<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>
</Drawer>
<main className={classes.content}>
<div className={classes.toolbar} />
<MapsList />
</main>
</div>
);
} }
export default MapsPage; export default MapsPage;

View File

@ -1,7 +1,7 @@
import React, { useEffect } from 'react' import React from 'react'
import { StyledTableCell } from './styled'; import { useStyles } from './styled';
import { createStyles, makeStyles, Theme, ThemeProvider } from '@material-ui/core/styles'; import { createStyles, makeStyles, Theme } from '@material-ui/core/styles';
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';
@ -23,10 +23,11 @@ import MoreHorizIcon from '@material-ui/icons/MoreHoriz';
import { CSSProperties } from 'react'; 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 { useQuery } from 'react-query'; import { useMutation, useQuery, useQueryClient } from 'react-query';
import { ErrorInfo, MapInfo, Service } from '../../../services/Service'; import { ErrorInfo, MapInfo, Service } from '../../../services/Service';
import ActionChooser, { ActionType } from '../action-chooser'; import ActionChooser, { ActionType } from '../action-chooser';
import ActionDispatcher from '../action-dispatcher'; import ActionDispatcher, { handleOnMutationSuccess } from '../action-dispatcher';
import { Link } from '@material-ui/core';
@ -64,7 +65,7 @@ function stableSort<T>(array: T[], comparator: (a: T, b: T) => number) {
interface HeadCell { interface HeadCell {
disablePadding: boolean; disablePadding: boolean;
id: keyof MapInfo; id: keyof MapInfo;
label: string; label?: string;
numeric: boolean; numeric: boolean;
style: CSSProperties; style: CSSProperties;
} }
@ -72,7 +73,7 @@ interface HeadCell {
const headCells: HeadCell[] = [ const headCells: HeadCell[] = [
{ id: 'starred', numeric: false, disablePadding: false, label: '', style: { width: '20px', padding: '0px' } }, { id: 'starred', numeric: false, disablePadding: false, label: '', style: { width: '20px', padding: '0px' } },
{ id: 'name', numeric: false, disablePadding: true, label: 'Name', style: {} }, { id: 'name', numeric: false, disablePadding: true, label: 'Name', style: {} },
{ id: 'labels', numeric: false, disablePadding: true, label: 'Labels', style: {} }, { id: 'labels', numeric: false, disablePadding: true, style: {} },
{ id: 'creator', numeric: false, disablePadding: false, label: 'Creator', style: {} }, { id: 'creator', numeric: false, disablePadding: false, label: 'Creator', style: {} },
{ id: 'modified', numeric: true, disablePadding: false, label: 'Modified', style: { width: '50px' } } { id: 'modified', numeric: true, disablePadding: false, label: 'Modified', style: { width: '50px' } }
]; ];
@ -96,9 +97,8 @@ function EnhancedTableHead(props: EnhancedTableProps) {
return ( return (
<TableHead> <TableHead>
<TableRow> <TableRow>
<TableCell padding='checkbox' key='select' style={{ width: '20px' }}> <TableCell padding='checkbox' key='select' style={{ width: '20px' }} className={classes.headerCell}>
<Checkbox <Checkbox
indeterminate={numSelected > 0 && numSelected < rowCount} indeterminate={numSelected > 0 && numSelected < rowCount}
checked={rowCount > 0 && numSelected === rowCount} checked={rowCount > 0 && numSelected === rowCount}
@ -108,11 +108,12 @@ function EnhancedTableHead(props: EnhancedTableProps) {
/> />
</TableCell> </TableCell>
{headCells.map((headCell) => ( {headCells.map((headCell) => {
<TableCell return headCell.label ? (<TableCell
key={headCell.id} key={headCell.id}
sortDirection={orderBy === headCell.id ? order : false} sortDirection={orderBy === headCell.id ? order : false}
style={headCell.style} style={headCell.style}
className={classes.headerCell}
> >
<TableSortLabel <TableSortLabel
active={orderBy === headCell.id} active={orderBy === headCell.id}
@ -125,11 +126,10 @@ function EnhancedTableHead(props: EnhancedTableProps) {
</span> </span>
) : null} ) : null}
</TableSortLabel> </TableSortLabel>
</TableCell> </TableCell>) : (<TableCell className={classes.headerCell} key={headCell.id}> </TableCell>)
))} }
<TableCell style={{ width: '20px', padding: '0px' }} key='actions'> )}
<TableSortLabel>""</TableSortLabel> <TableCell style={{ width: '20px', padding: '0px' }} key='actions' className={classes.headerCell}></TableCell>
</TableCell>
</TableRow> </TableRow>
</TableHead> </TableHead>
); );
@ -163,7 +163,7 @@ const EnhancedTableToolbar = (props: EnhancedTableToolbarProps) => {
</Typography> </Typography>
) : ( ) : (
<Typography className={classes.title} variant="h6" id="tableTitle" component="div"> <Typography className={classes.title} variant="h6" id="tableTitle" component="div">
Nutrition All
</Typography> </Typography>
)} )}
{numSelected > 0 ? ( {numSelected > 0 ? (
@ -183,32 +183,6 @@ const EnhancedTableToolbar = (props: EnhancedTableToolbarProps) => {
); );
}; };
const useStyles = makeStyles((theme: Theme) =>
createStyles({
root: {
width: '100%',
},
paper: {
width: '100%',
marginBottom: theme.spacing(2),
},
table: {
minWidth: 750,
border: 0,
},
visuallyHidden: {
border: 0,
clip: 'rect(0 0 0 0)',
height: 1,
margin: -1,
overflow: 'hidden',
padding: 0,
position: 'absolute',
top: 20,
width: 1,
},
}),
);
type ActionPanelState = { type ActionPanelState = {
el: HTMLElement | undefined, el: HTMLElement | undefined,
@ -295,16 +269,38 @@ export const MapsList = () => {
}; };
}; };
const queryClient = useQueryClient();
const starredMultation = useMutation<void, ErrorInfo, number>((id: number) => {
return service.changeStarred(id);
},
{
onSuccess: () => {
queryClient.invalidateQueries('maps');
},
onError: (error) => {
// setError(error);
}
}
);
const handleStarred = (event: React.MouseEvent<HTMLButtonElement, MouseEvent>, id: number) => {
event.stopPropagation();
event.preventDefault();
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;
setActiveRowAction(undefined);
setActiveDialog({ setActiveDialog({
actionType: action as ActionType, actionType: action as ActionType,
mapId: mapId as number mapId: mapId as number
}); });
} }
setActiveRowAction(undefined);
}; };
const isSelected = (id: number) => selected.indexOf(id) !== -1; const isSelected = (id: number) => selected.indexOf(id) !== -1;
@ -313,14 +309,14 @@ export const MapsList = () => {
return ( return (
<div className={classes.root}> <div className={classes.root}>
<Paper className={classes.paper}> <Paper className={classes.paper} elevation={0}>
<EnhancedTableToolbar numSelected={selected.length} /> <EnhancedTableToolbar numSelected={selected.length} />
<TableContainer> <TableContainer>
<Table <Table
className={classes.table} className={classes.table}
aria-labelledby="tableTitle" aria-labelledby="tableTitle"
size={'small'} size="small"
aria-label="sticky table"
stickyHeader stickyHeader
> >
<EnhancedTableHead <EnhancedTableHead
@ -332,6 +328,7 @@ export const MapsList = () => {
onRequestSort={handleRequestSort} onRequestSort={handleRequestSort}
rowCount={mapsInfo.length} rowCount={mapsInfo.length}
/> />
<TableBody> <TableBody>
{isLoading ? (<TableRow></TableRow>) : stableSort(mapsInfo, getComparator(order, orderBy)) {isLoading ? (<TableRow></TableRow>) : stableSort(mapsInfo, getComparator(order, orderBy))
.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage) .slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
@ -350,35 +347,41 @@ export const MapsList = () => {
selected={isItemSelected} selected={isItemSelected}
> >
<StyledTableCell padding="checkbox"> <TableCell padding="checkbox">
<Checkbox <Checkbox
checked={isItemSelected} checked={isItemSelected}
inputProps={{ 'aria-labelledby': String(labelId) }} inputProps={{ 'aria-labelledby': String(labelId) }}
size="small" size="small" />
/> </TableCell>
</StyledTableCell>
<StyledTableCell> <TableCell>
<Tooltip title="Starred"> <Tooltip title="Starred">
<IconButton aria-label="Starred" size="small" onClick={(e) => { alert("") }}> <IconButton aria-label="Starred" size="small" onClick={(e) => handleStarred(e, row.id)}>
<StarRateRoundedIcon color="action" style={{ color: row.starred ? 'yellow' : 'gray' }} /> <StarRateRoundedIcon color="action" style={{ color: row.starred ? 'yellow' : 'gray' }} />
</IconButton> </IconButton>
</Tooltip> </Tooltip>
</StyledTableCell> </TableCell>
<StyledTableCell>{row.name}</StyledTableCell> <Tooltip title="Open for edition" placement="bottom-start">
<StyledTableCell>{row.labels}</StyledTableCell> <TableCell>
<StyledTableCell>{row.creator}</StyledTableCell> <Link href={`c/maps/${row.id}/edit`} color="textPrimary" underline="always">
<StyledTableCell>{row.modified}</StyledTableCell> {row.name}
</Link>
</TableCell>
</Tooltip>
<StyledTableCell> <TableCell>{row.labels}</TableCell>
<TableCell>{row.creator}</TableCell>
<TableCell>{row.modified}</TableCell>
<TableCell>
<Tooltip title="Others"> <Tooltip title="Others">
<IconButton aria-label="Others" size="small" onClick={handleActionClick(row.id)}> <IconButton aria-label="Others" size="small" onClick={handleActionClick(row.id)}>
<MoreHorizIcon color="action" /> <MoreHorizIcon color="action" />
</IconButton> </IconButton>
</Tooltip> </Tooltip>
<ActionChooser anchor={activeRowAction?.el} onClose={handleActionMenuClose} /> <ActionChooser anchor={activeRowAction?.el} onClose={handleActionMenuClose} />
</StyledTableCell> </TableCell>
</TableRow> </TableRow>
); );
})} })}
@ -403,6 +406,6 @@ export const MapsList = () => {
{/* Action Dialog */} {/* Action Dialog */}
<ActionDispatcher action={activeDialog?.actionType} onClose={() => setActiveDialog(undefined)} mapId={activeDialog ? activeDialog.mapId : -1} /> <ActionDispatcher action={activeDialog?.actionType} onClose={() => setActiveDialog(undefined)} mapId={activeDialog ? activeDialog.mapId : -1} />
</div> </div >
); );
} }

View File

@ -1,18 +1,50 @@
import { MenuItem, TableCell } from '@material-ui/core'; import { MenuItem, TableCell } from '@material-ui/core';
import { withStyles } from '@material-ui/core/styles'; import { createStyles, makeStyles, Theme, withStyles } from '@material-ui/core/styles';
export const StyledTableCell = withStyles({ export const useStyles = makeStyles((theme: Theme) =>
createStyles({
root: { root: {
color: 'black', width: '100%',
padding: '0px', },
cursor: 'pointer' paper: {
} width: '100%',
})(TableCell); marginBottom: theme.spacing(2),
},
table: {
minWidth: 750,
border: 0,
'& tr:nth-child(even)': {
background: 'white'
},
'& tr:nth-child(odd)':
{
background: 'rgba(221, 221, 221, 0.35)'
}
},
headerCell: {
background: 'white',
fontWeight: 'bold',
color: 'rgba(0, 0, 0, 0.44)'
},
visuallyHidden: {
border: 0,
clip: 'rect(0 0 0 0)',
height: 1,
margin: -1,
overflow: 'hidden',
padding: 0,
position: 'absolute',
top: 20,
width: 1,
},
}),
);
export const StyledMenuItem = withStyles({ // export const StyledTableCell = withStyles({
root: { // root: {
width: '300px', // color: 'black',
padding: '10px 20px', // padding: '0px',
marging: '0px 20px' // cursor: 'pointer',
} // border: '0'
})(MenuItem) // }
// })(TableCell);

View File

@ -28,6 +28,17 @@ export const useStyles = makeStyles((theme: Theme) =>
menuButton: { menuButton: {
marginRight: 36, marginRight: 36,
}, },
newMapButton: {
marginRight: 10,
},
importButton: {
marginRight: 10,
},
rightButtonGroup: {
marginRight: 10,
flexGrow: 10,
textAlign: 'right'
},
hide: { hide: {
display: 'none', display: 'none',
}, },
@ -66,12 +77,11 @@ export const useStyles = makeStyles((theme: Theme) =>
content: { content: {
flexGrow: 1, flexGrow: 1,
padding: theme.spacing(3), padding: theme.spacing(3),
},
listItemText: {
} }
}), }),
); );
export const ListItemTextStyled = withStyles({ export const ListItemTextStyled = withStyles({
root: root:
{ {

View File

@ -42,6 +42,7 @@ interface Service {
renameMap(id: number, basicInfo: BasicMapInfo): Promise<void>; renameMap(id: number, basicInfo: BasicMapInfo): Promise<void>;
duplicateMap(id: number, basicInfo: BasicMapInfo): Promise<void>; duplicateMap(id: number, basicInfo: BasicMapInfo): Promise<void>;
loadMapInfo(id: number): Promise<BasicMapInfo>; loadMapInfo(id: number): Promise<BasicMapInfo>;
changeStarred(id: number): Promise<void>;
} }
class MockService implements Service { class MockService implements Service {
@ -71,6 +72,17 @@ class MockService implements Service {
]; ];
} }
changeStarred(id: number): Promise<void> {
const mapInfo = this.maps.find(m => m.id == id);
if (!mapInfo) {
console.log(`Could not find the map iwth id ${id}`);
return Promise.reject();
}
const newStarredValue = !mapInfo?.starred;
mapInfo.starred = newStarredValue;
return Promise.resolve();
}
loadMapInfo(id: number): Promise<BasicMapInfo> { loadMapInfo(id: number): Promise<BasicMapInfo> {
return Promise.resolve({ name: 'My Map', description: 'My Description' }); return Promise.resolve({ name: 'My Map', description: 'My Description' });
@ -100,6 +112,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;

View File

@ -12,6 +12,13 @@ const GlobalStyle = createGlobalStyle`
const theme = createMuiTheme({ const theme = createMuiTheme({
overrides: { overrides: {
MuiCssBaseline: {
'@global': {
body: {
backgroundColor: 'white',
},
},
},
MuiOutlinedInput: { MuiOutlinedInput: {
root: { root: {
height: '53px', height: '53px',