diff --git a/src/common/utils.js b/src/common/utils.js new file mode 100644 index 000000000..57f1103bd --- /dev/null +++ b/src/common/utils.js @@ -0,0 +1,11 @@ +import { verificationStates } from './variables'; + +export const getVerificationStatus = (active, approved) => { + if (active === true && approved === false) { + return verificationStates.AWAITING; + } else if (active === true && approved === true) { + return verificationStates.APPROVED; + } else if (active === false && approved === false) { + return verificationStates.REJECTED; + } +}; \ No newline at end of file diff --git a/src/components/CaptureTable.js b/src/components/CaptureTable.js index 31b24a0ce..84eabd33b 100644 --- a/src/components/CaptureTable.js +++ b/src/components/CaptureTable.js @@ -1,6 +1,7 @@ import React, { useEffect, useState, useContext, createRef } from 'react'; import { makeStyles } from '@material-ui/core/styles'; import { + Button, Grid, Table, TableHead, @@ -11,12 +12,16 @@ import { TableSortLabel, Typography, } from '@material-ui/core'; - +import IconFilter from '@material-ui/icons/FilterList'; import { getDateTimeStringLocale } from '../common/locale'; -import Filter, { FILTER_WIDTH } from './Filter'; -import CaptureDetails from './CaptureDetails.js'; +import { getVerificationStatus } from '../common/utils'; import LinkToWebmap from './common/LinkToWebmap'; import { CapturesContext } from '../context/CapturesContext'; +import CaptureDetailDialog from './CaptureDetailDialog'; +import Navbar from './Navbar'; +import FilterTop from './FilterTop'; +import { tokenizationStates } from '../common/variables'; +import api from '../api/treeTrackerApi'; // change 88 to unit spacing, const useStyle = makeStyles((theme) => ({ @@ -25,10 +30,9 @@ const useStyle = makeStyles((theme) => ({ paddingLeft: theme.spacing(16), overflowX: 'auto', }, - tableContainer: { - width: `calc(100vw - ${FILTER_WIDTH + theme.spacing(4)}px)`, - overflowY: 'auto', - height: '100%', + tableGrid: { + width: '100%', + overflow: 'hidden', }, tableRow: { cursor: 'pointer', @@ -67,26 +71,30 @@ const columns = [ label: 'Planter ID', }, { - attr: 'payment', - label: 'Payment', - noSort: true, - renderer: () => 'pending', + attr: 'deviceIdentifier', + label: 'Device Identifier', + noSort: false, }, { - attr: 'country', - label: 'Country', + attr: 'planterIdentifier', + label: 'Planter Identifier', + noSort: false, + }, + { + attr: 'verificationStatus', + label: 'Verification Status', noSort: true, - renderer: () => 'pending', }, { attr: 'speciesId', label: 'Species', noSort: true, - renderer: () => 'pending', }, { - attr: 'status', - label: 'Status', + attr: 'tokenId', + label: 'Token Status', + renderer: (val) => + val ? tokenizationStates.TOKENIZED : tokenizationStates.NOT_TOKENIZED, }, { attr: 'timeCreated', @@ -99,13 +107,25 @@ const CaptureTable = () => { const capturesContext = useContext(CapturesContext); const capturesArray = capturesContext.captures; const [isDetailsPaneOpen, setIsDetailsPaneOpen] = useState(false); + const [isFilterShown, setFilterShown] = useState(true); + const [speciesState, setSpeciesState] = useState({}); const scrollRef = createRef(); const classes = useStyle(); useEffect(() => { + loadSpecies(); loadCaptures(); }, []); + const loadSpecies = async () => { + const speciesList = await api.getSpecies(true); + let species = {}; + speciesList.map((s) => { + species[s.id] = s.name; + }); + setSpeciesState(species); + } + const loadCaptures = (payload) => { capturesContext.getCapturesAsync(payload).then(() => { scrollRef.current && scrollRef.current.scrollTo(0, 0); @@ -150,6 +170,10 @@ const CaptureTable = () => { }); }; + const handleFilterClick = () => { + setFilterShown(!isFilterShown); + } + const createSortHandler = (attr) => { return () => { const order = @@ -176,78 +200,103 @@ const CaptureTable = () => { }; return ( -
- - - Captures - - {tablePagination()} - - - - - {columns.map(({ attr, label, noSort }) => ( - + + + } + key={1} > - - {label} - - - ))} - - - - {capturesArray.map((capture) => ( - , + ]} + > + {isFilterShown && ( + + )} + + + +
+ - {columns.map(({ attr, renderer }) => ( - - {formatCell(capture, attr, renderer)} - - ))} - - ))} - -
- {tablePagination()} - - -
+ + Captures + + {tablePagination()} + + + + + {columns.map(({ attr, label, noSort }) => ( + + + {label} + + + ))} + + + + {capturesArray.map((capture) => ( + + {columns.map(({ attr, renderer }) => ( + + {formatCell(capture, speciesState, attr, renderer)} + + ))} + + ))} + +
+ {tablePagination()} + + + + + ); }; -const formatCell = (capture, attr, renderer) => { +const formatCell = (capture, speciesState, attr, renderer) => { if (attr === 'id' || attr === 'planterId') { return ( { type={attr === 'id' ? 'tree' : 'user'} /> ); + } else if (attr === 'speciesId') { + return capture[attr] === null ? '--' : speciesState[capture[attr]]; + } else if (attr === 'verificationStatus') { + return capture['active'] === null || capture['approved'] === null + ? '--' + : getVerificationStatus(capture['active'], capture['approved']); } else { return renderer ? renderer(capture[attr]) : capture[attr]; } diff --git a/src/components/Filter.js b/src/components/Filter.js index 692b49e47..aecd0f841 100644 --- a/src/components/Filter.js +++ b/src/components/Filter.js @@ -22,7 +22,7 @@ import { convertDateToDefaultSqlDate, } from '../common/locale'; import { datePickerDefaultMinDate } from '../common/variables'; - +import { getVerificationStatus } from '../common/utils'; import { verificationStates, tokenizationStates } from '../common/variables'; export const FILTER_WIDTH = 330; @@ -297,14 +297,4 @@ function Filter(props) { ); } -const getVerificationStatus = (active, approved) => { - if (active === true && approved === false) { - return verificationStates.AWAITING; - } else if (active === true && approved === true) { - return verificationStates.APPROVED; - } else if (active === false && approved === false) { - return verificationStates.REJECTED; - } -}; - export default withStyles(styles)(Filter); diff --git a/src/components/FilterTop.js b/src/components/FilterTop.js index 5be85328b..dc011e96b 100644 --- a/src/components/FilterTop.js +++ b/src/components/FilterTop.js @@ -27,6 +27,7 @@ import { tokenizationStates, datePickerDefaultMinDate, } from '../common/variables'; +import { getVerificationStatus } from '../common/utils'; import { AppContext } from '../context/AppContext'; import { SpeciesContext } from '../context/SpeciesContext'; import { TagsContext } from '../context/TagsContext'; @@ -177,7 +178,7 @@ function Filter(props) { id: ORGANIZATION_NOT_SET, name: 'Not set', }, - ]; + ]; return ( <> @@ -443,14 +444,4 @@ function Filter(props) { ); } -const getVerificationStatus = (active, approved) => { - if (active === true && approved === false) { - return verificationStates.AWAITING; - } else if (active === true && approved === true) { - return verificationStates.APPROVED; - } else if (active === false && approved === false) { - return verificationStates.REJECTED; - } -}; - export default withStyles(styles)(Filter); diff --git a/src/components/tests/captures.test.js b/src/components/tests/captures.test.js index ab25a6461..7754dd17c 100644 --- a/src/components/tests/captures.test.js +++ b/src/components/tests/captures.test.js @@ -431,9 +431,14 @@ describe.skip('Captures', () => { id: true, timeCreated: true, status: true, + active: true, approved: true, planterId: true, treeTags: true, + planterIdentifier: true, + deviceIdentifier: true, + speciesId: true, + tokenId: true, }, }); diff --git a/src/context/CapturesContext.js b/src/context/CapturesContext.js index d1a9f5869..de8ae79c1 100644 --- a/src/context/CapturesContext.js +++ b/src/context/CapturesContext.js @@ -164,9 +164,14 @@ export function CapturesProvider(props) { id: true, timeCreated: true, status: true, + active: true, approved: true, planterId: true, treeTags: true, + planterIdentifier: true, + deviceIdentifier: true, + speciesId: true, + tokenId: true, }, }; diff --git a/src/views/CapturesView.js b/src/views/CapturesView.js index 54da3633b..f938dba86 100644 --- a/src/views/CapturesView.js +++ b/src/views/CapturesView.js @@ -8,7 +8,6 @@ handling the comms between the captures view components and the store/models) import React, { useEffect } from 'react'; import { documentTitle } from '../common/variables'; import { Grid } from '@material-ui/core'; -import Navbar from '../components/Navbar'; import CaptureTable from '../components/CaptureTable'; import { CapturesProvider } from '../context/CapturesContext'; @@ -23,9 +22,6 @@ function CapturesView() { direction="column" style={{ flexWrap: 'nowrap', height: '100%' }} > - - -