Skip to content

Commit

Permalink
feat: better capture details & filters (#101)
Browse files Browse the repository at this point in the history
* feat: restructure capture details fields

* feat: logical status dropdown in capture filters

* chore: refactor verification status checks

* chore: move species tag and check tokenid
  • Loading branch information
VLuisa authored May 31, 2021
1 parent 8a3aaff commit f0d2c9b
Show file tree
Hide file tree
Showing 5 changed files with 194 additions and 120 deletions.
5 changes: 5 additions & 0 deletions src/common/variables.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,8 @@ export const drawerWidth = 240;
//export const API_ROOT = 'http://localhost:3000/'
export const selectedHighlightColor = '#0af';
export const documentTitle = 'Treetracker Admin by Greenstand';
export const verificationStates = {
APPROVED: 'Approved',
AWAITING: 'Awaiting Verification',
REJECTED: 'Rejected',
};
158 changes: 116 additions & 42 deletions src/components/CaptureDetailDialog.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import FileCopy from '@material-ui/icons/FileCopy';
import CloseIcon from '@material-ui/icons/Close';
import OptimizedImage from './OptimizedImage';
import LinkToWebmap from './common/LinkToWebmap';
import { verificationStates } from '../common/variables';

const useStyles = makeStyles((theme) => ({
chipRoot: {
Expand All @@ -30,9 +31,32 @@ const useStyles = makeStyles((theme) => ({
margin: theme.spacing(0.5),
fontSize: '0.7rem',
},
rejectedChip: {
backgroundColor: theme.palette.stats.red.replace(/[^,]+(?=\))/, '0.2'), // Change opacity of rgba
color: theme.palette.stats.red,
fontWeight: 700,
fontSize: '0.8em',
},
awaitingChip: {
backgroundColor: theme.palette.stats.orange.replace(/[^,]+(?=\))/, '0.2'), // Change opacity of rgba
color: theme.palette.stats.orange,
fontWeight: 700,
fontSize: '0.8em',
},
approvedChip: {
backgroundColor: theme.palette.stats.green.replace(/[^,]+(?=\))/, '0.2'), // Change opacity of rgba
color: theme.palette.stats.green,
fontWeight: 700,
fontSize: '0.8em',
},
copyButton: {
margin: theme.spacing(-2, 0),
},
subtitle: {
...theme.typography.button,
fontSize: '0.8em',
color: 'rgba(0,0,0,0.5)',
},
}));

function CaptureDetailDialog(props) {
Expand Down Expand Up @@ -116,49 +140,82 @@ function CaptureDetailDialog(props) {
</Typography>
</Grid>
<Divider />
{[
{
label: 'Planter ID',
value: capture.planterId,
copy: true,
link: true,
},
{
label: 'Planter Identifier',
value: capture.planterIdentifier,
copy: true,
},
{
label: 'Device Identifier',
value: capture.deviceIdentifier,
copy: true,
},
{ label: 'Approved', value: capture.approved ? 'true' : 'false' },
{ label: 'Active', value: capture.active ? 'true' : 'false' },
{ label: 'Status', value: capture.status },
{ label: 'Species', value: species && species.name },
{ label: 'Created', value: dateCreated.toLocaleString() },
{ label: 'Note', value: renderCapture.note },
].map((item) => (
<Fragment key={item.label}>
<Grid item>
<Typography variant="subtitle1">{item.label}</Typography>
<Typography variant="body1">
{item.link ? (
<LinkToWebmap value={item.value} type="user" />
) : (
item.value || '---'
)}
{item.value && item.copy && (
<CopyButton label={item.label} value={item.value} />
)}
</Typography>
</Grid>
<Divider />
</Fragment>
))}
<Grid item>
<Typography variant="subtitle1">Tags</Typography>
<Typography className={classes.subtitle}>Capture Data</Typography>
{[
{
label: 'Planter ID',
value: capture.planterId,
copy: true,
link: true,
},
{
label: 'Planter Identifier',
value: capture.planterIdentifier,
copy: true,
},
{
label: 'Device Identifier',
value: capture.deviceIdentifier,
copy: true,
},
{ label: 'Created', value: dateCreated.toLocaleString() },
{ label: 'Note', value: renderCapture.note },
].map((item) => (
<Fragment key={item.label}>
<Grid item>
<Typography variant="subtitle1">{item.label}</Typography>
<Typography variant="body1">
{item.link ? (
<LinkToWebmap value={item.value} type="user" />
) : (
item.value || '---'
)}
{item.value && item.copy && (
<CopyButton label={item.label} value={item.value} />
)}
</Typography>
</Grid>
</Fragment>
))}
</Grid>
<Divider />
<Grid item>
<Typography className={classes.subtitle}>
Verification Status
</Typography>
{!capture.approved && capture.active ? (
<Chip
label={verificationStates.AWAITING}
className={classes.awaitingChip}
/>
) : capture.active && capture.approved ? (
<Chip
label={verificationStates.APPROVED}
className={classes.approvedChip}
/>
) : (
<Chip
label={verificationStates.REJECTED}
className={classes.rejectedChip}
/>
)}
</Grid>
<Divider />
<Grid item>
<Typography className={classes.subtitle}>Tags</Typography>
<Typography variant="subtitle1">Species</Typography>
{species && species.name ? (
<Chip
key={species && species.name}
label={species && species.name}
className={classes.chip}
/>
) : (
<Typography variant="body1">---</Typography>
)}

<Typography variant="subtitle1">Other</Typography>
{allTags.length === 0 ? (
<Typography variant="body1">---</Typography>
) : (
Expand All @@ -169,6 +226,13 @@ function CaptureDetailDialog(props) {
</div>
)}
</Grid>
<Divider />
<Grid item>
<Typography className={classes.subtitle}>Capture Token</Typography>
<Typography variant="body1">
{getTokenStatus(capture.tokenId)}
</Typography>
</Grid>
<Snackbar
anchorOrigin={{
vertical: 'top',
Expand Down Expand Up @@ -242,4 +306,14 @@ const mapDispatch = (dispatch) => ({
captureDetailDispatch: dispatch.captureDetail,
});

const getTokenStatus = (tokenId) => {
if (tokenId === undefined) {
return 'Impact token status unknown';
} else if (tokenId === null) {
return 'Impact token not issued';
} else {
return 'Impact token issued';
}
};

export default compose(connect(mapState, mapDispatch))(CaptureDetailDialog);
70 changes: 35 additions & 35 deletions src/components/Filter.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import {
convertDateToDefaultSqlDate,
} from '../common/locale';

import { verificationStates } from '../common/variables';

export const FILTER_WIDTH = 330;

const styles = (theme) => {
Expand Down Expand Up @@ -52,6 +54,7 @@ const styles = (theme) => {

function Filter(props) {
const { classes, filter } = props;
const filterOptionAll = 'All';
const dateStartDefault = null;
const dateEndDefault = null;
const [captureId, setCaptureId] = useState(filter.captureId);
Expand Down Expand Up @@ -210,51 +213,39 @@ function Filter(props) {
))}
</TextField>
*/}
<GSInputLabel text="Approved" />
<GSInputLabel text="Verification Status" />
<TextField
select
value={
approved === undefined ? 'All' : approved === true ? 'true' : 'false'
active === undefined && approved === undefined
? filterOptionAll
: getVerificationStatus(active, approved)
}
InputLabelProps={{
shrink: true,
}}
onChange={(e) =>
onChange={(e) => {
setApproved(
e.target.value === 'All'
e.target.value === filterOptionAll
? undefined
: e.target.value === verificationStates.AWAITING ||
e.target.value === verificationStates.REJECTED
? false
: true,
);
setActive(
e.target.value === filterOptionAll
? undefined
: e.target.value === 'true'
: e.target.value === verificationStates.AWAITING ||
e.target.value === verificationStates.APPROVED
? true
: false,
)
}
>
{['All', 'true', 'false'].map((name) => (
<MenuItem key={name} value={name}>
{name}
</MenuItem>
))}
</TextField>
<GSInputLabel text="Rejected" />
<TextField
select
value={
active === undefined ? 'All' : active === true ? 'false' : 'true'
}
InputLabelProps={{
shrink: true,
);
}}
onChange={(e) =>
setActive(
e.target.value === 'All'
? undefined
: e.target.value === 'true'
? false
: true,
)
}
>
{['All', 'false', 'true'].map((name) => (
{[
filterOptionAll,
verificationStates.APPROVED,
verificationStates.AWAITING,
verificationStates.REJECTED,
].map((name) => (
<MenuItem key={name} value={name}>
{name}
</MenuItem>
Expand Down Expand Up @@ -298,6 +289,15 @@ 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 compose(
// withStyles(styles, { withTheme: true, name: 'Filter' })
//)(Filter)
Expand Down
Loading

0 comments on commit f0d2c9b

Please sign in to comment.