From 1a3e299c713e6daf6d8d89e56194de3ab787f08b Mon Sep 17 00:00:00 2001 From: Ezequiel Bergamaschi Date: Mon, 1 Mar 2021 23:59:38 -0500 Subject: [PATCH] feat: labels ui --- .nvmrc | 2 +- packages/webapp/src/classes/client/index.ts | 3 +- .../src/classes/client/mock-client/index.ts | 29 ++++++-- .../webapp/src/components/maps-page/index.tsx | 26 ++++--- .../maps-list/add-label-button/index.tsx | 71 +++++++++++++++++++ .../components/maps-page/maps-list/index.tsx | 34 +++------ .../maps-list/label-selector/index.tsx | 58 +++++++++++++++ .../maps-list/label-selector/styled.ts | 6 ++ .../maps-page/maps-list/label/index.tsx | 13 ++++ .../maps-page/maps-list/label/styled.ts | 23 ++++++ .../maps-page/maps-list/labels-cell/index.tsx | 27 +++++++ packages/webapp/src/theme/index.ts | 6 +- 12 files changed, 247 insertions(+), 51 deletions(-) create mode 100644 packages/webapp/src/components/maps-page/maps-list/add-label-button/index.tsx create mode 100644 packages/webapp/src/components/maps-page/maps-list/label-selector/index.tsx create mode 100644 packages/webapp/src/components/maps-page/maps-list/label-selector/styled.ts create mode 100644 packages/webapp/src/components/maps-page/maps-list/label/index.tsx create mode 100644 packages/webapp/src/components/maps-page/maps-list/label/styled.ts create mode 100644 packages/webapp/src/components/maps-page/maps-list/labels-cell/index.tsx diff --git a/.nvmrc b/.nvmrc index ab155ce1..9a0c3d3f 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -v14.15.5 +v14.15.4 diff --git a/packages/webapp/src/classes/client/index.ts b/packages/webapp/src/classes/client/index.ts index a683fbd4..555c368b 100644 --- a/packages/webapp/src/classes/client/index.ts +++ b/packages/webapp/src/classes/client/index.ts @@ -19,7 +19,6 @@ export type Label = { id: number; title: string; color: string; - iconName: string; }; export type Role = 'owner' | 'editor' | 'viewer'; @@ -28,7 +27,7 @@ export type MapInfo = { id: number; starred: boolean; title: string; - labels: number[]; + labels: Label[]; createdBy: string; creationTime: string; lastModificationBy: string; diff --git a/packages/webapp/src/classes/client/mock-client/index.ts b/packages/webapp/src/classes/client/mock-client/index.ts index 8a32bc79..3b0c2368 100644 --- a/packages/webapp/src/classes/client/mock-client/index.ts +++ b/packages/webapp/src/classes/client/mock-client/index.ts @@ -10,6 +10,24 @@ import Client, { } from '..'; import { LocaleCode, localeFromStr } from '../../app-i18n'; +const label1: Label = { + id: 1, + title: 'label 1', + color: 'black', +} + +const label2: Label = { + id: 2, + title: 'label 2', + color: 'green', +} + +const label3: Label = { + id: 3, + title: 'label 3', + color: 'red', +} + class MockClient implements Client { private maps: MapInfo[] = []; private labels: Label[] = []; @@ -21,7 +39,7 @@ class MockClient implements Client { id: number, starred: boolean, title: string, - labels: number[], + labels: Label[], creator: string, creationTime: string, modifiedByUser: string, @@ -63,7 +81,7 @@ class MockClient implements Client { 11, false, 'El Mapa3', - [1, 2, 3], + [label1, label2], 'Paulo3', '2008-06-02T00:00:00Z', 'Berna', @@ -76,7 +94,7 @@ class MockClient implements Client { 12, false, 'El Mapa3', - [1, 2, 3], + [label2, label3], 'Paulo3', '2008-06-02T00:00:00Z', 'Berna', @@ -87,10 +105,7 @@ class MockClient implements Client { ), ]; - this.labels = [ - { id: 1, title: 'Red Label', iconName: '', color: 'red' }, - { id: 2, title: 'Blue Label', iconName: '', color: 'blue' }, - ]; + this.labels = [label1, label2, label3]; } deleteMapPermission(id: number, email: string): Promise { let perm = this.permissionsByMap.get(id) || []; diff --git a/packages/webapp/src/components/maps-page/index.tsx b/packages/webapp/src/components/maps-page/index.tsx index a36e9117..4ef4557c 100644 --- a/packages/webapp/src/components/maps-page/index.tsx +++ b/packages/webapp/src/components/maps-page/index.tsx @@ -219,20 +219,18 @@ const MapsPage = (): ReactElement => { - {filterButtons.map((buttonInfo) => { - return ( - - ); - })} + {filterButtons.map(buttonInfo => { + return () + } + )}
void; +}; + +export function AddLabelButton({ onChange }: AddLabelButtonTypes): React.ReactElement { + console.log(onChange); + const intl = useIntl(); + + const [anchorEl, setAnchorEl] = React.useState(null); + + const handleClick = (event: React.MouseEvent) => { + setAnchorEl(event.currentTarget); + }; + + const handleClose = () => { + setAnchorEl(null); + }; + + const open = Boolean(anchorEl); + const id = open ? 'add-label-popover' : undefined; + + return ( + + <> + + + + + + + ); +} diff --git a/packages/webapp/src/components/maps-page/maps-list/index.tsx b/packages/webapp/src/components/maps-page/maps-list/index.tsx index e7ea7043..68b6114d 100644 --- a/packages/webapp/src/components/maps-page/maps-list/index.tsx +++ b/packages/webapp/src/components/maps-page/maps-list/index.tsx @@ -4,7 +4,7 @@ import { useStyles } from './styled'; import { useSelector } from 'react-redux'; import { activeInstance, fetchAccount } from '../../../redux/clientSlice'; import { useMutation, useQuery, useQueryClient } from 'react-query'; -import Client, { ErrorInfo, MapInfo } from '../../../classes/client'; +import Client, {ErrorInfo, Label, MapInfo} from '../../../classes/client'; import ActionChooser, { ActionType } from '../action-chooser'; import ActionDispatcher from '../action-dispatcher'; import dayjs from 'dayjs'; @@ -28,14 +28,15 @@ import Button from '@material-ui/core/Button'; import InputBase from '@material-ui/core/InputBase'; import Link from '@material-ui/core/Link'; -import LabelTwoTone from '@material-ui/icons/LabelTwoTone'; import DeleteOutlined from '@material-ui/icons/DeleteOutlined'; import MoreHorizIcon from '@material-ui/icons/MoreHoriz'; import StarRateRoundedIcon from '@material-ui/icons/StarRateRounded'; import SearchIcon from '@material-ui/icons/Search'; +import { AddLabelButton } from './add-label-button'; // Load fromNow pluggin import relativeTime from 'dayjs/plugin/relativeTime'; +import {LabelsCell} from './labels-cell'; dayjs.extend(relativeTime); function descendingComparator(a: T, b: T, orderBy: keyof T) { @@ -55,8 +56,8 @@ function getComparator( order: Order, orderBy: Key ): ( - a: { [key in Key]: number | string | boolean | number[] | undefined }, - b: { [key in Key]: number | string | number[] | boolean } + a: { [key in Key]: number | string | boolean | Label[] | undefined }, + b: { [key in Key]: number | string | Label[] | boolean } ) => number { return order === 'desc' ? (a, b) => descendingComparator(a, b, orderBy) @@ -220,7 +221,7 @@ const mapsFilter = (filter: Filter, search: string): ((mapInfo: MapInfo) => bool break; case 'label': result = - !mapInfo.labels || mapInfo.labels.includes((filter as LabelFilter).label.id); + !mapInfo.labels || mapInfo.labels.some((label) => label.id === (filter as LabelFilter).label.id) break; case 'public': result = mapInfo.isPublic; @@ -412,24 +413,7 @@ export const MapsList = (props: MapsListProps): React.ReactElement => { )} - {selected.length > 0 && ( - - - - )} + {selected.length > 0 && }
@@ -558,7 +542,9 @@ export const MapsList = (props: MapsListProps): React.ReactElement => { - + + + {row.createdBy} diff --git a/packages/webapp/src/components/maps-page/maps-list/label-selector/index.tsx b/packages/webapp/src/components/maps-page/maps-list/label-selector/index.tsx new file mode 100644 index 00000000..42a2780c --- /dev/null +++ b/packages/webapp/src/components/maps-page/maps-list/label-selector/index.tsx @@ -0,0 +1,58 @@ +import React from 'react'; +import FormGroup from '@material-ui/core/FormGroup'; +import FormControlLabel from '@material-ui/core/FormControlLabel'; +import Divider from '@material-ui/core/Divider'; +import AddIcon from '@material-ui/icons/Add'; +import Checkbox from '@material-ui/core/Checkbox'; +import Container from '@material-ui/core/Container'; +import { Label as LabelComponent } from '../label'; +import Client, { Label, ErrorInfo } from '../../../../classes/client'; +import { useQuery } from 'react-query'; +import { useSelector } from 'react-redux'; +import { activeInstance } from '../../../../redux/clientSlice'; +import { StyledButton } from './styled'; + +export function LabelSelector(): React.ReactElement { + const client: Client = useSelector(activeInstance); + + const { data: labels = [] } = useQuery('labels', async () => client.fetchLabels()); + + const [state, setState] = React.useState(labels.reduce((acc, label) => { + acc[label.id] = false //label.checked; + return acc; + }, {}),); + + const handleChange = (event: React.ChangeEvent) => { + setState({ ...state, [event.target.id]: event.target.checked }); + }; + + return ( + + + {labels.map(({ id, title, color}) => ( + + } + label={} + /> + ))} + + } + > + {/* i18n */} + Add new label + + + + ); +} diff --git a/packages/webapp/src/components/maps-page/maps-list/label-selector/styled.ts b/packages/webapp/src/components/maps-page/maps-list/label-selector/styled.ts new file mode 100644 index 00000000..519cf0f3 --- /dev/null +++ b/packages/webapp/src/components/maps-page/maps-list/label-selector/styled.ts @@ -0,0 +1,6 @@ +import styled from 'styled-components'; +import Button from '@material-ui/core/Button'; + +export const StyledButton = styled(Button)` + margin: 4px; +`; diff --git a/packages/webapp/src/components/maps-page/maps-list/label/index.tsx b/packages/webapp/src/components/maps-page/maps-list/label/index.tsx new file mode 100644 index 00000000..5ca36096 --- /dev/null +++ b/packages/webapp/src/components/maps-page/maps-list/label/index.tsx @@ -0,0 +1,13 @@ +import React from 'react'; +import { Color, StyledLabel, Name } from './styled'; + +type Props = { name: string, color: string }; + +export function Label({ name, color }: Props): React.ReactElement { + return ( + + + {name} + + ); +} diff --git a/packages/webapp/src/components/maps-page/maps-list/label/styled.ts b/packages/webapp/src/components/maps-page/maps-list/label/styled.ts new file mode 100644 index 00000000..4c48bfd9 --- /dev/null +++ b/packages/webapp/src/components/maps-page/maps-list/label/styled.ts @@ -0,0 +1,23 @@ +import styled, { css } from 'styled-components'; + +const SIZE = 20; + +export const Color = styled.div` + width: ${SIZE}px; + height: ${SIZE}px; + border-radius: ${SIZE * 0.25}px; + border: 1px solid black; + margin: 1px ${SIZE * 0.5}px 1px 0px; + ${props => props.color && css` + background-color: ${props.color}; + `} +`; + +export const StyledLabel = styled.div` + display: flex; + flex-direction: row; +`; + +export const Name = styled.div` + flex: 1; +`; diff --git a/packages/webapp/src/components/maps-page/maps-list/labels-cell/index.tsx b/packages/webapp/src/components/maps-page/maps-list/labels-cell/index.tsx new file mode 100644 index 00000000..e124ea72 --- /dev/null +++ b/packages/webapp/src/components/maps-page/maps-list/labels-cell/index.tsx @@ -0,0 +1,27 @@ +import React from 'react'; +import Chip from '@material-ui/core/Chip'; +import LabelIcon from '@material-ui/icons/Label'; + +import {Label} from '../../../../classes/client'; +type Props = { + labels: Label[], +}; + +export function LabelsCell({ labels }: Props): React.ReactElement { + return ( + <> + {labels.map(label => ( + } + label={label.title} + clickable + color="primary" + style={{ backgroundColor: label.color }} + onDelete={() => {return 1;}} + /> + ))} + + ); +} diff --git a/packages/webapp/src/theme/index.ts b/packages/webapp/src/theme/index.ts index bbfc5b28..44950279 100644 --- a/packages/webapp/src/theme/index.ts +++ b/packages/webapp/src/theme/index.ts @@ -69,9 +69,9 @@ const theme = createMuiTheme({ contrastText: '#FFFFFF', }, secondary: { - light: '#FFFFFF', - main: '#FFFFFF', - dark: '#FFFFFF', + light: '#a19f9f', + main: '#5a5a5a', + dark: '#000000', contrastText: '#FFFFFF', }, },