From 37dd8129f8e07d00eb93262210bf1ecd4ce95532 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 20 Sep 2020 22:39:04 -0700 Subject: Refactor collection editing --- modern/src/DeviceList.js | 111 +++++++++++---------------------------- modern/src/DevicePage.js | 6 +-- modern/src/EditCollectionView.js | 73 +++++++++++++++++++++++++ modern/src/EditItemView.js | 80 ++++++++++++++++++++++++++++ modern/src/EditPage.js | 80 ---------------------------- modern/src/RemoveDialog.js | 21 ++++---- modern/src/UserPage.js | 6 +-- 7 files changed, 200 insertions(+), 177 deletions(-) create mode 100644 modern/src/EditCollectionView.js create mode 100644 modern/src/EditItemView.js delete mode 100644 modern/src/EditPage.js (limited to 'modern') diff --git a/modern/src/DeviceList.js b/modern/src/DeviceList.js index 66b9406..b7c15dc 100644 --- a/modern/src/DeviceList.js +++ b/modern/src/DeviceList.js @@ -1,109 +1,60 @@ -import React, { Fragment, useState } from 'react'; +import React, { Fragment } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { makeStyles } from '@material-ui/core/styles'; -import { useHistory } from 'react-router-dom'; import Avatar from '@material-ui/core/Avatar'; import Divider from '@material-ui/core/Divider'; import IconButton from '@material-ui/core/IconButton'; import List from '@material-ui/core/List'; import ListItem from '@material-ui/core/ListItem'; import ListItemAvatar from '@material-ui/core/ListItemAvatar'; -import Menu from '@material-ui/core/Menu'; -import MenuItem from '@material-ui/core/MenuItem'; import ListItemSecondaryAction from '@material-ui/core/ListItemSecondaryAction'; import ListItemText from '@material-ui/core/ListItemText'; import LocationOnIcon from '@material-ui/icons/LocationOn'; import MoreVertIcon from '@material-ui/icons/MoreVert'; -import Fab from '@material-ui/core/Fab'; -import AddIcon from '@material-ui/icons/Add'; import { devicesActions } from './store'; -import t from './common/localization'; -import RemoveDialog from './RemoveDialog'; +import EditCollectionView from './EditCollectionView'; -const useStyles = makeStyles(theme => ({ +const useStyles = makeStyles(() => ({ list: { maxHeight: '100%', overflow: 'auto', }, - fab: { - position: 'absolute', - bottom: theme.spacing(2), - right: theme.spacing(2), - }, })); -const DeviceList = () => { - const [menuDeviceId, setMenuDeviceId] = useState(null); - const [menuAnchorEl, setMenuAnchorEl] = useState(null); - const [removeDialogOpen, setRemoveDialogOpen] = useState(false); - const devices = useSelector(state => Object.values(state.devices.items)); - const dispatch = useDispatch(); +const DeviceView = ({ onMenuClick }) => { const classes = useStyles(); - const history = useHistory(); - - const handleMenuClick = (event, deviceId) => { - setMenuDeviceId(deviceId); - setMenuAnchorEl(event.currentTarget); - } - - const handleMenuClose = () => { - setMenuAnchorEl(null); - } - - const handleMenuEdit = () => { - history.push(`/device/${menuDeviceId}`); - handleMenuClose(); - } - - const handleMenuRemove = () => { - setRemoveDialogOpen(true); - handleMenuClose(); - } + const dispatch = useDispatch(); - const handleAdd = () => { - history.push('/device'); - handleMenuClose(); - } + const items = useSelector(state => Object.values(state.devices.items)); - const handleRemoveResult = (removed) => { - setRemoveDialogOpen(false); - if (removed) { - dispatch(devicesActions.remove(menuDeviceId)); - } - } + return ( + + {items.map((item, index, list) => ( + + dispatch(devicesActions.select(item))}> + + + + + + + + onMenuClick(event.currentTarget, item.id)}> + + + + + {index < list.length - 1 ? : null} + + ))} + + ); +} +const DeviceList = () => { return ( - <> - - {devices.map((device, index, list) => ( - - dispatch(devicesActions.select(device))}> - - - - - - - - handleMenuClick(event, device.id)}> - - - - - {index < list.length - 1 ? : null} - - ))} - - - - - - {t('sharedEdit')} - {t('sharedRemove')} - - - + ); } diff --git a/modern/src/DevicePage.js b/modern/src/DevicePage.js index 14e978e..7c963b0 100644 --- a/modern/src/DevicePage.js +++ b/modern/src/DevicePage.js @@ -2,7 +2,7 @@ import React, { useState } from 'react'; import TextField from '@material-ui/core/TextField'; import t from './common/localization'; -import EditPage from './EditPage'; +import EditItemView from './EditItemView'; const DevicePage = () => { const [item, setItem] = useState(); @@ -18,7 +18,7 @@ const DevicePage = () => { }; return ( - + {item && <> { variant="filled" /> } - + ); } diff --git a/modern/src/EditCollectionView.js b/modern/src/EditCollectionView.js new file mode 100644 index 0000000..59ea2db --- /dev/null +++ b/modern/src/EditCollectionView.js @@ -0,0 +1,73 @@ +import React, { useState } from 'react'; +import { makeStyles } from '@material-ui/core/styles'; +import { useHistory } from 'react-router-dom'; +import Menu from '@material-ui/core/Menu'; +import MenuItem from '@material-ui/core/MenuItem'; +import Fab from '@material-ui/core/Fab'; +import AddIcon from '@material-ui/icons/Add'; + +import t from './common/localization'; +import RemoveDialog from './RemoveDialog'; + +const useStyles = makeStyles(theme => ({ + fab: { + position: 'absolute', + bottom: theme.spacing(2), + right: theme.spacing(2), + }, +})); + +const EditCollectionView = ({ content, editPath, endpoint }) => { + const classes = useStyles(); + const history = useHistory(); + + const [selectedId, setSelectedId] = useState(null); + const [selectedAnchorEl, setSelectedAnchorEl] = useState(null); + const [removeDialogShown, setRemoveDialogShown] = useState(false); + + const menuShow = (anchorId, itemId) => { + setSelectedAnchorEl(anchorId); + setSelectedId(itemId); + } + + const menuHide = () => { + setSelectedAnchorEl(null); + } + + const handleAdd = () => { + history.push(editPath); + menuHide(); + } + + const handleEdit = () => { + history.push(`${editPath}/${selectedId}`); + menuHide(); + } + + const handleRemove = () => { + setRemoveDialogShown(true); + menuHide(); + } + + const handleRemoveResult = () => { + setRemoveDialogShown(false); + } + + const Content = content; + + return ( + <> + + + + + + {t('sharedEdit')} + {t('sharedRemove')} + + + + ); +} + +export default EditCollectionView; diff --git a/modern/src/EditItemView.js b/modern/src/EditItemView.js new file mode 100644 index 0000000..db8cd0d --- /dev/null +++ b/modern/src/EditItemView.js @@ -0,0 +1,80 @@ +import React from 'react'; +import MainToobar from './MainToolbar'; +import { useHistory, useParams } from 'react-router-dom'; +import { makeStyles } from '@material-ui/core/styles'; +import Container from '@material-ui/core/Container'; +import Button from '@material-ui/core/Button'; +import FormControl from '@material-ui/core/FormControl'; + +import t from './common/localization'; +import { useEffectAsync } from './reactHelper'; + +const useStyles = makeStyles(theme => ({ + container: { + marginTop: theme.spacing(2), + }, + buttons: { + display: 'flex', + justifyContent: 'space-evenly', + '& > *': { + flexBasis: '33%', + }, + }, +})); + +const EditItemView = ({ children, endpoint, setItem, getItem }) => { + const history = useHistory(); + const classes = useStyles(); + const { id } = useParams(); + + useEffectAsync(async () => { + if (id) { + const response = await fetch(`/api/${endpoint}/${id}`); + if (response.ok) { + setItem(await response.json()); + } + } else { + setItem({}); + } + }, [id]); + + const handleSave = async () => { + let url = `/api/${endpoint}`; + if (id) { + url += `/${id}`; + } + + const response = await fetch(url, { + method: !id ? 'POST' : 'PUT', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(getItem()), + }); + + if (response.ok) { + history.goBack(); + } + }; + + return ( + <> + + +
+ {children} + +
+ + +
+
+
+
+ + ); +} + +export default EditItemView; diff --git a/modern/src/EditPage.js b/modern/src/EditPage.js deleted file mode 100644 index 23e8c07..0000000 --- a/modern/src/EditPage.js +++ /dev/null @@ -1,80 +0,0 @@ -import React from 'react'; -import MainToobar from './MainToolbar'; -import { useHistory, useParams } from 'react-router-dom'; -import { makeStyles } from '@material-ui/core/styles'; -import Container from '@material-ui/core/Container'; -import Button from '@material-ui/core/Button'; -import FormControl from '@material-ui/core/FormControl'; - -import t from './common/localization'; -import { useEffectAsync } from './reactHelper'; - -const useStyles = makeStyles(theme => ({ - container: { - marginTop: theme.spacing(2), - }, - buttons: { - display: 'flex', - justifyContent: 'space-evenly', - '& > *': { - flexBasis: '33%', - }, - }, -})); - -const EditPage = ({ children, endpoint, setItem, getItem }) => { - const history = useHistory(); - const classes = useStyles(); - const { id } = useParams(); - - useEffectAsync(async () => { - if (id) { - const response = await fetch(`/api/${endpoint}/${id}`); - if (response.ok) { - setItem(await response.json()); - } - } else { - setItem({}); - } - }, [id]); - - const handleSave = async () => { - let url = `/api/${endpoint}`; - if (id) { - url += `/${id}`; - } - - const response = await fetch(url, { - method: !id ? 'POST' : 'PUT', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify(getItem()), - }); - - if (response.ok) { - history.goBack(); - } - }; - - return ( - <> - - -
- {children} - -
- - -
-
-
-
- - ); -} - -export default EditPage; diff --git a/modern/src/RemoveDialog.js b/modern/src/RemoveDialog.js index bca936f..57be787 100644 --- a/modern/src/RemoveDialog.js +++ b/modern/src/RemoveDialog.js @@ -6,26 +6,25 @@ import DialogActions from '@material-ui/core/DialogActions'; import DialogContent from '@material-ui/core/DialogContent'; import DialogContentText from '@material-ui/core/DialogContentText'; -const RemoveDialog = (props) => { - const handleRemove = () => { - fetch(`/api/devices/${props.deviceId}`, { method: 'DELETE' }).then(response => { - if (response.ok) { - props.onResult(true); - } - }); - } +const RemoveDialog = ({ open, endpoint, itemId, onResult }) => { + const handleRemove = async () => { + const response = fetch(`/api/${endpoint}/${itemId}`, { method: 'DELETE' }) + if (response.ok) { + onResult(true); + } + }; return ( <> { props.onResult(false) }}> + open={open} + onClose={() => { onResult(false) }}> {t('sharedRemoveConfirm')} - + diff --git a/modern/src/UserPage.js b/modern/src/UserPage.js index da8ba1b..4b58ba8 100644 --- a/modern/src/UserPage.js +++ b/modern/src/UserPage.js @@ -2,7 +2,7 @@ import React, { useState } from 'react'; import TextField from '@material-ui/core/TextField'; import t from './common/localization'; -import EditPage from './EditPage'; +import EditItemView from './EditItemView'; const UserPage = () => { const [item, setItem] = useState(); @@ -20,7 +20,7 @@ const UserPage = () => { }; return ( - + {item && <> { variant="filled" /> } - + ); } -- cgit v1.2.3