diff --git a/package-lock.json b/package-lock.json index 014ff1f6e..f3b588952 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "treetracker-admin-client", - "version": "1.42.1", + "version": "1.47.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "treetracker-admin-client", - "version": "1.42.1", + "version": "1.47.0", "dependencies": { "@date-io/date-fns": "^1.3.13", "@material-ui/core": "^4.9.10", @@ -29,6 +29,7 @@ "env-cmd": "^10.1.0", "generate-password": "^1.5.1", "geocoder": "*", + "geolib": "^3.3.3", "i": "*", "import": "*", "install": "*", @@ -18145,6 +18146,11 @@ "xml2js": "0.2.0" } }, + "node_modules/geolib": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/geolib/-/geolib-3.3.3.tgz", + "integrity": "sha512-YO704pzdB/8QQekQuDmFD5uv5RAwAf4rOUPdcMhdEOz+HoPWD0sC7Qqdwb+LAvwIjXVRawx0QgZlocKYh8PFOQ==" + }, "node_modules/get-assigned-identifiers": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/get-assigned-identifiers/-/get-assigned-identifiers-1.2.0.tgz", @@ -27369,11 +27375,6 @@ "safer-buffer": "^2.0.2", "tweetnacl": "~0.14.0" }, - "bin": { - "sshpk-conv": "bin/sshpk-conv", - "sshpk-sign": "bin/sshpk-sign", - "sshpk-verify": "bin/sshpk-verify" - }, "engines": { "node": ">=0.10.0" } @@ -52121,6 +52122,11 @@ "xml2js": "0.2.0" } }, + "geolib": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/geolib/-/geolib-3.3.3.tgz", + "integrity": "sha512-YO704pzdB/8QQekQuDmFD5uv5RAwAf4rOUPdcMhdEOz+HoPWD0sC7Qqdwb+LAvwIjXVRawx0QgZlocKYh8PFOQ==" + }, "get-assigned-identifiers": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/get-assigned-identifiers/-/get-assigned-identifiers-1.2.0.tgz", diff --git a/package.json b/package.json index 71b3f5470..799da58c7 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "env-cmd": "^10.1.0", "generate-password": "^1.5.1", "geocoder": "*", + "geolib": "^3.3.3", "i": "*", "import": "*", "install": "*", diff --git a/src/components/CaptureMatching/CandidateImages.js b/src/components/CaptureMatching/CandidateImages.js index b57651f14..e42188752 100644 --- a/src/components/CaptureMatching/CandidateImages.js +++ b/src/components/CaptureMatching/CandidateImages.js @@ -1,18 +1,29 @@ import React, { useState, useEffect } from 'react'; -import { Typography, Box, Button, Grid, Paper } from '@material-ui/core'; +import { + Typography, + Box, + Button, + Grid, + Paper, + Tooltip, +} from '@material-ui/core'; import { makeStyles } from '@material-ui/core/styles'; import CheckIcon from '@material-ui/icons/Check'; import ClearIcon from '@material-ui/icons/Clear'; +import AccessTimeIcon from '@material-ui/icons/AccessTime'; +import LocationOnOutlinedIcon from '@material-ui/icons/LocationOnOutlined'; import theme from '../common/theme'; +import { getDateStringLocale } from 'common/locale'; +import { getDistance } from 'geolib'; const useStyles = makeStyles({ containerBox: { marginTop: 0, marginBottom: theme.spacing(5), - paddingBottom: theme.spacing(2), background: '#fff', borderRadius: '4px', + overflow: 'hidden', }, headerBox: { @@ -21,26 +32,19 @@ const useStyles = makeStyles({ imgContainer: { height: '100%', - padding: '5px', objectFit: 'cover', - paddingBottom: '10px', - overFlow: 'hidden', }, gridList: { - padding: '10px', + padding: theme.spacing(0, 4), display: 'flex', flexDirection: 'row', overflowX: 'auto', overflowY: 'hidden', - }, - - imageScroll: { - // height: '76vh', - // overflow: 'scroll', + gap: theme.spacing(2), }, candidateImgBtn: { - padding: theme.spacing(5, 4), + padding: theme.spacing(4), display: 'flex', gap: theme.spacing(2), }, @@ -48,28 +52,80 @@ const useStyles = makeStyles({ fontSize: '16px', }, box2: { + display: 'flex', flexDirection: 'row', justifyContent: 'space-between', alignItems: 'baseline', - padding: '8px 16px', + padding: theme.spacing(2), }, box3: { display: 'flex', justifyContent: 'center', alignItems: 'center', + gap: theme.spacing(2), }, box1: { width: '24px', height: '24px', - backgroundColor: '#75B926', + lineHeight: '24px', + color: theme.palette.primary.main, + border: `solid 1px ${theme.palette.primary.main}`, + borderRadius: '50%', + textAlign: 'center', + }, + candidateCaptureContainer: { + height: '300px', + position: 'relative', + }, + captureInfo: { + position: 'absolute', + bottom: 0, + width: '100%', display: 'flex', - justifyContent: 'center', - alignItems: 'center', - color: 'white', + flexDirection: 'row', + background: 'rgba(0,0,0,0.7)', + color: theme.palette.primary.main, + }, + captureInfoDetail: { + display: 'flex', + flexDirection: 'row', + padding: theme.spacing(2), + gap: theme.spacing(1), + }, + candidateTreeContent: { + transition: 'max-height 250ms ease-in-out', }, }); -function CandidateImages({ candidateImgData, sameTreeHandler }) { +function DistanceTo({ lat1, lon1, lat2, lon2 }) { + const [content, setContent] = useState(''); + if ( + lat1 === 'undefined' || + lon1 === 'undefined' || + lat2 === 'undefined' || + lon2 === 'undefined' + ) { + setContent(''); + } + + useEffect(() => { + const distance = getDistance( + { + latitude: lat1, + longitude: lon1, + }, + { + latitude: lat2, + longitude: lon2, + } + ); + setContent(`${distance}m away`); + }, []); + + return {content}; +} + +function CandidateImages({ capture, candidateImgData, sameTreeHandler }) { const classes = useStyles(); const [showBox, setShowBox] = useState([]); @@ -106,73 +162,90 @@ function CandidateImages({ candidateImgData, sameTreeHandler }) { > - {++i} + {i + 1} - - Tree {tree.tree_id} - + + + Tree {(tree.id + '').substring(0, 10) + '...'} + + {/* button */} - {showBox.includes(tree.id) ? ( - - {tree.captures.length ? ( - - {tree.captures.map((capture) => { - return ( - - {`Candidate + + + {(tree.captures.length ? tree.captures : [tree]).map( + (candidateCapture) => { + return ( + + {`Candidate + + + + + {getDateStringLocale( + candidateCapture.created_at + )} + + + + + + {capture && ( + + )} + + - ); - })} - - ) : ( - - {`Candidate - + + ); + } )} + - - - - + + + - ) : null} + ); })} diff --git a/src/components/CaptureMatching/CaptureHeader.js b/src/components/CaptureMatching/CaptureHeader.js index 510bb1c47..e524de2d5 100644 --- a/src/components/CaptureMatching/CaptureHeader.js +++ b/src/components/CaptureMatching/CaptureHeader.js @@ -7,7 +7,6 @@ import PhotoCameraOutlinedIcon from '@material-ui/icons/PhotoCameraOutlined'; import { makeStyles } from '@material-ui/core/styles'; import Pagination from '@material-ui/lab/Pagination'; import FilterListIcon from '@material-ui/icons/FilterList'; -import Chip from '@material-ui/core/Chip'; const useStyles = makeStyles((t) => ({ containerBox: { @@ -40,7 +39,6 @@ const useStyles = makeStyles((t) => ({ function CaptureHeader(props) { const classes = useStyles(); - const { currentPage, handleChange, imgCount, noOfPages } = props; const iconImgLogo = ( @@ -57,13 +55,6 @@ function CaptureHeader(props) { imgCount={imgCount} /> - - console.warn('delete')} - label={'My Organization'} - /> - console.warn('delete')} label={'Mongo'} /> - ({ }, imgBox: { - // height: '52vh', flexGrow: 1, overflow: 'auto', + display: 'flex', + justifyContent: 'center', + padding: theme.spacing(2), }, imgContainer: { - width: '100%', + objectFit: 'contain', + }, + captureInfo: { + display: 'flex', + flexDirection: 'row', + gap: theme.spacing(2), }, box1: { height: '100%', @@ -83,8 +90,7 @@ const useStyles = makeStyles((theme) => ({ }, }, button: { - width: 71, - height: 31, + height: '100%', }, })); @@ -128,30 +134,30 @@ function CaptureImage(props) { Capture {(capture.id + '').substring(0, 10) + '...'} - - - - {getDateTimeStringLocale(capture.created_at)} - - - - - - - - + + + + + {getDateTimeStringLocale(capture.created_at)} + + + + + + + + - {/* */}