From 438c667422d9ba12e6f8d97acf8a45ddbf476263 Mon Sep 17 00:00:00 2001 From: Joshua Krautwurst Date: Wed, 4 May 2022 09:59:01 -0700 Subject: [PATCH 01/18] large-scale refactor of subject control buttons for uniformity. --- src/GpsFormatToggle/index.js | 9 +- src/HeatmapToggleButton/index.js | 24 ++--- src/HeatmapToggleButton/styles.module.scss | 94 ++----------------- src/SubjectControls/_mixins.scss | 61 ++++++++++++ src/SubjectControls/button.js | 33 +++++++ src/SubjectControls/index.js | 24 ++++- src/SubjectControls/index.test.js | 24 +++++ src/SubjectControls/styles.module.scss | 3 +- src/SubjectGroupList/SubjectListItem.js | 2 +- src/SubjectHistoricalDataModal/index.js | 29 ++++-- src/SubjectHistoricalDataModal/index.test.js | 3 +- .../PatrolAwareTrackToggleButton.js | 69 ++++++++++++++ src/SubjectHistoryButton/index.js | 29 ++++++ src/SubjectHistoryButton/index.test.js | 32 +++++++ src/SubjectHistoryButton/styles.module.scss | 61 ++++++++++++ src/SubjectPopup/index.js | 46 ++++----- src/SubjectPopup/index.test.js | 15 --- src/SubjectPopup/styles.module.scss | 6 ++ src/TrackToggleButton/index.js | 32 +++++-- src/TrackToggleButton/styles.module.scss | 70 ++------------ src/common/images/icons/historical-data.svg | 3 + src/common/images/icons/marker-feed.svg | 2 +- src/common/styles/vars/_colors.scss | 2 + 23 files changed, 442 insertions(+), 231 deletions(-) create mode 100644 src/SubjectControls/_mixins.scss create mode 100644 src/SubjectControls/button.js create mode 100644 src/SubjectControls/index.test.js create mode 100644 src/SubjectHistoryButton/PatrolAwareTrackToggleButton.js create mode 100644 src/SubjectHistoryButton/index.js create mode 100644 src/SubjectHistoryButton/index.test.js create mode 100644 src/SubjectHistoryButton/styles.module.scss create mode 100644 src/common/images/icons/historical-data.svg diff --git a/src/GpsFormatToggle/index.js b/src/GpsFormatToggle/index.js index 9935174b9..0f116626f 100644 --- a/src/GpsFormatToggle/index.js +++ b/src/GpsFormatToggle/index.js @@ -23,8 +23,7 @@ const GpsFormatToggle = (props) => { }); }; - const gpsString = showGpsString && calcGpsDisplayString(lat, lng, currentFormat); - const displayGpsString = gpsString || null; + const gpsString = showGpsString ? calcGpsDisplayString(lat, lng, currentFormat) : null; return (
@@ -34,9 +33,9 @@ const GpsFormatToggle = (props) => { onClick={() => onGpsFormatClick(gpsFormat)}>{gpsFormat} )} - {displayGpsString &&
- {displayGpsString} - {showCopyControl && } + {gpsString &&
+ {gpsString} + {showCopyControl && }
}
diff --git a/src/HeatmapToggleButton/index.js b/src/HeatmapToggleButton/index.js index 0b044fecf..c61e4fc40 100644 --- a/src/HeatmapToggleButton/index.js +++ b/src/HeatmapToggleButton/index.js @@ -1,19 +1,21 @@ -import React, { memo } from 'react'; +import React, { memo, useMemo } from 'react'; import noop from 'lodash/noop'; import PropTypes from 'prop-types'; import styles from './styles.module.scss'; -import LoadingOverlay from '../LoadingOverlay'; + +import SubjectControlButton from '../SubjectControls/button'; const HeatmapToggleButton = (props) => { - const { className: externalClass, heatmapVisible, heatmapPartiallyVisible, onButtonClick, showLabel, loading } = props; - const className = heatmapVisible ? 'visible' : heatmapPartiallyVisible ? 'partial' : ''; - const labelText = className ? 'Heatmap on' : 'Heatmap off'; - - return
- {loading && } - - {showLabel && {labelText}} -
; + const { className: externalClass, heatmapVisible, heatmapPartiallyVisible, onButtonClick, ...rest } = props; + + const stateClassName = heatmapVisible ? 'visible' : heatmapPartiallyVisible ? 'partial' : ''; + + const containerClassName = `${styles.container} ${stateClassName}`; + const buttonClassName = `${styles.button} ${styles[stateClassName]} ${externalClass || ''}`; + + const labelText = stateClassName ? 'Heatmap on' : 'Heatmap off'; + + return ; }; export default memo(HeatmapToggleButton); diff --git a/src/HeatmapToggleButton/styles.module.scss b/src/HeatmapToggleButton/styles.module.scss index 0613adcb9..df4354d5f 100644 --- a/src/HeatmapToggleButton/styles.module.scss +++ b/src/HeatmapToggleButton/styles.module.scss @@ -1,92 +1,16 @@ @import '../common/styles/buttons'; - -$background_image_url: '../common/images/icons/'; - -@mixin button($image: 'heatmap') { - background: url('#{$background-image_url+$image}.svg'); - background-size: cover; - border: none; - display: block; - filter: saturate(50%) grayscale(100%); - height: $square-button-dimension; - outline: none; - width: $square-button-dimension; - - &:focus { - outline: none; - } -} - -.button { - @include button; - &.visible { - filter: unset; - } -} +@import '../SubjectControls/mixins'; .container { - align-items: center; - display: flex; - flex-flow: row; - position: relative; - - &.hasLabel { - background-color: rgba($secondary-light-gray, .25); - border: 0.06rem solid $secondary-medium-light-gray; - border-radius: .12rem; - max-width: 5.75rem; - max-height: 1.85rem; - border-radius: 0.2rem; - cursor: pointer; - - [class*=spinner] { - position: relative; - top: -16%; + @include control; + .button { + @include buttonBackground('heatmap'); + filter: saturate(50%) grayscale(100%); + &.visible { + filter: unset; } - - button { - min-height: 1.80rem; - height: 1.80rem; - min-width: 1.80rem; - width: 1.80rem; - } - - span { - font-size: 0.68rem; - line-height: normal; - padding: .1rem .7rem; - margin: 0 -.2rem; - } - - &[class*=visible] { - border: 0.06px solid $bright-blue; - background-color: rgba($bright-blue, 0.1); - } - - &[class*=pinned] { - border: 0.06px solid $green; - background-color: rgba($green, 0.1); + &.partial { + filter: opacity(50%); } } - -} - -.visible { - @include button; } - -.partial { - filter: opacity(50%); -} - -div.loadingOverlay { - background: none; - z-index: 10; - [class*=spinner] { - height: 1rem; - width: 1rem; - &::after { - background: none; - } - } -} \ No newline at end of file diff --git a/src/SubjectControls/_mixins.scss b/src/SubjectControls/_mixins.scss new file mode 100644 index 000000000..e0ea85a1b --- /dev/null +++ b/src/SubjectControls/_mixins.scss @@ -0,0 +1,61 @@ +@mixin buttonBackground($image: 'tracks_off') { + $background_image_url: '../common/images/icons/'; + background: url('#{$background_image_url+$image}.svg'); + background-size: cover; +} + +@mixin control { + align-items: center; + display: flex; + flex-flow: row; + position: relative; + + &.hasLabel { + background-color: rgba($secondary-light-gray, .25); + border: 0.06rem solid $secondary-medium-light-gray; + border-radius: .12rem; + max-width: 5.75rem; + max-height: 1.85rem; + border-radius: 0.2rem; + cursor: pointer; + + [class*=spinner] { + position: relative; + top: -16%; + } + + button { + min-height: 1.80rem; + height: 1.80rem; + min-width: 1.80rem; + width: 1.80rem; + } + + span { + font-size: 0.68rem; + line-height: normal; + padding: .1rem .7rem; + margin: 0 -.2rem; + } + + } + + .button { + @include buttonBackground(); + background-color: $subject-control-btn-bg; + border: none; + display: block; + filter: saturate(50%) grayscale(100%); + height: $square-button-dimension; + outline: none; + width: $square-button-dimension; + + &:focus { + outline: none; + } + + &.visible { + filter: unset; + } + } +} \ No newline at end of file diff --git a/src/SubjectControls/button.js b/src/SubjectControls/button.js new file mode 100644 index 000000000..3e70245af --- /dev/null +++ b/src/SubjectControls/button.js @@ -0,0 +1,33 @@ +import React, { forwardRef, memo } from 'react'; +import noop from 'lodash/noop'; +import PropTypes from 'prop-types'; +import LoadingOverlay from '../LoadingOverlay'; +import styles from './styles.module.scss'; + +const SubjectControlButton = (props, ref) => { + const { buttonClassName = '', containerClassName = '', disabled = false, labelText, onClick, showLabel, loading, ...rest } = props; + + return
+ {loading && } + + {showLabel && labelText && {labelText}} +
; +}; + +export default memo(forwardRef(SubjectControlButton)); + +SubjectControlButton.defaultProps = { + onClick: noop, + showLabel: true, + loading: false, +}; + +SubjectControlButton.propTypes = { + buttonClassName: PropTypes.string, + containerClassName: PropTypes.string, + disabled: PropTypes.bool, + labelText: PropTypes.string, + onClick: PropTypes.func.isRequired, + showLabel: PropTypes.bool, + loading: PropTypes.bool, +}; \ No newline at end of file diff --git a/src/SubjectControls/index.js b/src/SubjectControls/index.js index ab2c51408..acb628b05 100644 --- a/src/SubjectControls/index.js +++ b/src/SubjectControls/index.js @@ -1,8 +1,9 @@ -import React, { memo, useState } from 'react'; +import React, { lazy, memo, useCallback, useState } from 'react'; import PropTypes from 'prop-types'; import { connect } from 'react-redux'; import { usePermissions } from '../hooks'; +import { addModal } from '../ducks/modals'; import { PERMISSION_KEYS, PERMISSIONS } from '../constants'; @@ -11,24 +12,32 @@ import { addHeatmapSubjects, removeHeatmapSubjects, toggleTrackState } from '../ import TrackToggleButton from '../TrackToggleButton'; import HeatmapToggleButton from '../HeatmapToggleButton'; import SubjectMessagesPopover from '../SubjectMessagesPopover'; +import SubjectHistoryButton from '../SubjectHistoryButton'; import LocationJumpButton from '../LocationJumpButton'; import { trackEventFactory, MAP_LAYERS_CATEGORY } from '../utils/analytics'; +import { subjectIsStatic } from '../utils/subjects'; + + import { getSubjectControlState } from './selectors'; import { fetchTracksIfNecessary } from '../utils/tracks'; import styles from './styles.module.scss'; +const SubjectHistoricalDataModal = lazy(() => import('../SubjectHistoricalDataModal')); + const mapLayerTracker = trackEventFactory(MAP_LAYERS_CATEGORY); const SubjectControls = (props) => { const { subject, + addModal, children, showHeatmapButton, showTrackButton, showJumpButton, showMessageButton, + showHistoryButton, showTitles, showLabels, className, @@ -49,8 +58,11 @@ const SubjectControls = (props) => { const isMessageable = !!canViewMessages && !!showMessageButton && !!subject?.messaging?.length; + const hasAdditionalDeviceProps = !!subject?.device_status_properties?.length; const canShowTrack = canShowTrackForSubject(subject); + const canShowHistoryButton = showHistoryButton && (subjectIsStatic(subject) ? !!hasAdditionalDeviceProps : true); + const fetchSubjectTracks = () => { if (tracksLoaded) return new Promise(resolve => resolve()); return fetchTracksIfNecessary([id]); @@ -89,6 +101,10 @@ const SubjectControls = (props) => { } }; + const onHistoricalDataClick = useCallback(() => { + addModal({ content: SubjectHistoricalDataModal, subjectId: subject.id, subjectIsStatic: subjectIsStatic(subject), title: `Historical Data: ${subject.name}` }); + }, [addModal, subject]); + if (!showHeatmapButton && !showTrackButton && !showJumpButton) return null; return
{ heatmapVisible={subjectIsInHeatmap} />} + {canShowHistoryButton && } + {showJumpButton && coordinates && getSubjectControlState(state, props); -export default connect(mapStateToProps, { toggleTrackState, addHeatmapSubjects, removeHeatmapSubjects })(memo(SubjectControls)); +export default connect(mapStateToProps, { addModal, toggleTrackState, addHeatmapSubjects, removeHeatmapSubjects })(memo(SubjectControls)); diff --git a/src/SubjectControls/index.test.js b/src/SubjectControls/index.test.js new file mode 100644 index 000000000..01ed9fe16 --- /dev/null +++ b/src/SubjectControls/index.test.js @@ -0,0 +1,24 @@ +import React from 'react'; +import { render, screen, userEvent, waitFor } from '@testing-library/react'; + +import SubjectControls from './'; + +test('rendering without crashing', () => { + render(); +}); + +describe('the track button', () => { + +}); + +describe('the heatmap button', () => { + +}); + +describe('the "jump to location" button', () => { + +}); + +describe('the "historical data" button', () => { + +}); diff --git a/src/SubjectControls/styles.module.scss b/src/SubjectControls/styles.module.scss index b9db19ae6..ea1ba4889 100644 --- a/src/SubjectControls/styles.module.scss +++ b/src/SubjectControls/styles.module.scss @@ -1,4 +1,5 @@ @import '../common/styles/layout'; +@import '../common/styles/vars/colors'; .controls { display: flex; @@ -19,4 +20,4 @@ stroke: black; } } -} \ No newline at end of file +} diff --git a/src/SubjectGroupList/SubjectListItem.js b/src/SubjectGroupList/SubjectListItem.js index f1e79ce8d..3809411f9 100644 --- a/src/SubjectGroupList/SubjectListItem.js +++ b/src/SubjectGroupList/SubjectListItem.js @@ -19,7 +19,7 @@ const SubjectListItem = (props) => { {subject.name} {!isEmpty(defaultProperty) && {`${defaultProperty.label}: ${defaultProperty.value} ${defaultProperty.units}`}}

- + ; }; diff --git a/src/SubjectHistoricalDataModal/index.js b/src/SubjectHistoricalDataModal/index.js index 516a70d7c..ffc5ba444 100644 --- a/src/SubjectHistoricalDataModal/index.js +++ b/src/SubjectHistoricalDataModal/index.js @@ -10,7 +10,13 @@ import startCase from 'lodash/startCase'; import { fetchObservationsForSubject } from '../ducks/observations'; import { removeModal } from '../ducks/modals'; + +import { calcGpsDisplayString } from '../utils/location'; + +/* calcGpsDisplayString(lat, lng, currentFormat) */ + import LoadingOverlay from '../LoadingOverlay'; +import TextCopyBtn from '../TextCopyBtn'; import DateTime from '../DateTime'; import styles from './styles.module.scss'; @@ -26,7 +32,7 @@ export const getObservationUniqProperties = (observations) => { return uniqPropertiesByLabel.map(property => property.label); }; -const SubjectHistoricalDataModal = ({ title, subjectId, fetchObservationsForSubject }) => { +const SubjectHistoricalDataModal = ({ gpsFormat, title, subjectId, subjectIsStatic, fetchObservationsForSubject }) => { const [loading, setLoadState] = useState(true); const [subjectObservations, setSubjectObservations] = useState([]); const [observationsCount, setObservationsCount] = useState(1); @@ -44,10 +50,6 @@ const SubjectHistoricalDataModal = ({ title, subjectId, fetchObservationsForSubj }); }, [fetchObservationsForSubject, subjectId]); - useEffect(() => { - if (activePage === 1) fetchObservations(); - }, [activePage, fetchObservations]); - useEffect(() => { fetchObservations(activePage); }, [activePage, fetchObservations]); @@ -75,15 +77,20 @@ const SubjectHistoricalDataModal = ({ title, subjectId, fetchObservationsForSubj Date {observationProperties.map(property => {startCase(property)})} + {!subjectIsStatic && Location} - {subjectObservations.map(({ id, recorded_at, device_status_properties }) => - + {subjectObservations.map(({ id, recorded_at, location, device_status_properties }) => { + const locationString = !subjectIsStatic && calcGpsDisplayString(location.latitude, location.longitude, gpsFormat); + + return {observationProperties.map(property => {getMatchedProperty(property, device_status_properties)})} - - )} + {!!locationString && {locationString} + } + ; + })} {observationsCount > ITEMS_PER_PAGE && ({ gpsFormat }); -export default connect(null, { fetchObservationsForSubject, removeModal })(memo(SubjectHistoricalDataModal)); \ No newline at end of file +export default connect(mapStateToProps, { fetchObservationsForSubject, removeModal })(memo(SubjectHistoricalDataModal)); \ No newline at end of file diff --git a/src/SubjectHistoricalDataModal/index.test.js b/src/SubjectHistoricalDataModal/index.test.js index 40f05f313..873fbb2c0 100644 --- a/src/SubjectHistoricalDataModal/index.test.js +++ b/src/SubjectHistoricalDataModal/index.test.js @@ -7,6 +7,7 @@ import userEvent from '@testing-library/user-event'; import { fetchObservationsForSubject } from '../ducks/observations'; import { mockStore } from '../__test-helpers/MockStore'; +import { GPS_FORMATS } from '../utils/location'; import mockedObservationsData from '../__test-helpers/fixtures/observations'; import SubjectHistoricalDataModal, { ITEMS_PER_PAGE, getObservationUniqProperties } from './'; @@ -16,7 +17,7 @@ jest.mock('../ducks/observations', () => ({ fetchObservationsForSubject: jest.fn(), })); -const store = mockStore({ data: {}, view: {} }); +const store = mockStore({ data: {}, view: { userPreferences: { gpsFormat: GPS_FORMATS.DEG } } }); describe('SubjectHistoricalDataModal', () => { let fetchObservationsForSubjectMock; diff --git a/src/SubjectHistoryButton/PatrolAwareTrackToggleButton.js b/src/SubjectHistoryButton/PatrolAwareTrackToggleButton.js new file mode 100644 index 000000000..ef1176f16 --- /dev/null +++ b/src/SubjectHistoryButton/PatrolAwareTrackToggleButton.js @@ -0,0 +1,69 @@ +import React, { memo, useCallback, useMemo } from 'react'; +import { connect } from 'react-redux'; +import isEqual from 'react-fast-compare'; + +import { togglePatrolTrackState } from '../ducks/patrols'; +import { toggleTrackState } from '../ducks/map-ui'; + +import { trackEventFactory, PATROL_LIST_ITEM_CATEGORY } from '../utils/analytics'; + +import TrackToggleButton from './'; + +const patrolListItemTracker = trackEventFactory(PATROL_LIST_ITEM_CATEGORY); + +const PatrolAwareTrackToggleButton = ({ buttonRef, dispatch: _dispatch, patrolData, patrolTrackState, subjectTrackState, togglePatrolTrackState, toggleTrackState, ...rest }) => { + const { patrol, leader } = patrolData; + + const patrolTrackPinned = useMemo(() => patrolTrackState.pinned.includes(patrol.id), [patrol.id, patrolTrackState.pinned]); + const patrolTrackVisible = useMemo(() => !patrolTrackPinned && patrolTrackState.visible.includes(patrol.id), [patrol.id, patrolTrackPinned, patrolTrackState.visible]); + const patrolTrackHidden = useMemo(() => !patrolTrackPinned && !patrolTrackVisible, [patrolTrackPinned, patrolTrackVisible]); + + const subjectTrackPinned = useMemo(() => !!leader && subjectTrackState.pinned.includes(leader.id), [leader, subjectTrackState.pinned]); + const subjectTrackVisible = useMemo(() => !!leader && !subjectTrackPinned && subjectTrackState.visible.includes(leader.id), [leader, subjectTrackPinned, subjectTrackState.visible]); + const subjectTrackHidden = useMemo(() => !subjectTrackPinned && !subjectTrackVisible, [subjectTrackPinned, subjectTrackVisible]); + // trackVisible={patrolTrackVisible} trackPinned={patrolTrackPinned} onClick={onTrackButtonClick} + + const patrolToggleStates = useMemo(() => [patrolTrackPinned, patrolTrackVisible, patrolTrackHidden], [patrolTrackHidden, patrolTrackPinned, patrolTrackVisible]); + const subjectToggleStates = useMemo(() => [subjectTrackPinned, subjectTrackVisible, subjectTrackHidden], [subjectTrackHidden, subjectTrackPinned, subjectTrackVisible]); + + const onTrackButtonClick = useCallback(() => { + const nextPatrolTrackStateIfToggled = patrolTrackPinned + ? 'hidden' + : patrolTrackHidden + ? 'visible' + : 'pinned'; + + if (!leader) return; + const actionToTrack = `Toggle patrol track state to ${nextPatrolTrackStateIfToggled} from patrol card popover`; + + if (isEqual(patrolToggleStates, subjectToggleStates)) { + toggleTrackState(leader.id); + togglePatrolTrackState(patrol.id); + patrolListItemTracker.track(actionToTrack); + return; + } + if (!patrolTrackHidden && subjectTrackHidden) { + togglePatrolTrackState(patrol.id); + patrolListItemTracker.track(actionToTrack); + return; + } + if (subjectTrackPinned && patrolTrackVisible) { + togglePatrolTrackState(patrol.id); + patrolListItemTracker.track(actionToTrack); + } + if (patrolTrackPinned && subjectTrackVisible) { + toggleTrackState(leader.id); + } + if (patrolTrackHidden && !subjectTrackHidden) { + toggleTrackState(leader.id); + return; + } + }, [leader, patrol.id, patrolToggleStates, patrolTrackHidden, patrolTrackPinned, patrolTrackVisible, subjectToggleStates, subjectTrackHidden, subjectTrackPinned, subjectTrackVisible, togglePatrolTrackState, toggleTrackState]); + + return ; +}; + + +const mapStateToProps = ({ view: { patrolTrackState, subjectTrackState } }) => ({ patrolTrackState, subjectTrackState }); + +export default connect(mapStateToProps, { togglePatrolTrackState, toggleTrackState })(memo(PatrolAwareTrackToggleButton)); \ No newline at end of file diff --git a/src/SubjectHistoryButton/index.js b/src/SubjectHistoryButton/index.js new file mode 100644 index 000000000..9caad1385 --- /dev/null +++ b/src/SubjectHistoryButton/index.js @@ -0,0 +1,29 @@ +import React, { forwardRef, memo } from 'react'; +import noop from 'lodash/noop'; +import PropTypes from 'prop-types'; +import styles from './styles.module.scss'; + +const SubjectHistoryButton = (props, ref) => { + const { className: externalClassName, disabled, onClick, showLabel, ...rest } = props; + + + return
+ + {showLabel && Historical Data} +
; +}; + +export default memo(forwardRef(SubjectHistoryButton)); + +SubjectHistoryButton.defaultProps = { + onClick: noop, + showLabel: true, +}; + +SubjectHistoryButton.propTypes = { + trackVisible: PropTypes.bool.isRequired, + trackPinned: PropTypes.bool.isRequired, + onClick: PropTypes.func, + showLabel: PropTypes.bool, + loading: PropTypes.bool, +}; \ No newline at end of file diff --git a/src/SubjectHistoryButton/index.test.js b/src/SubjectHistoryButton/index.test.js new file mode 100644 index 000000000..7958da5e8 --- /dev/null +++ b/src/SubjectHistoryButton/index.test.js @@ -0,0 +1,32 @@ +import React from 'react'; +import { render, screen, userEvent, waitFor } from '@testing-library/react'; + +import SubjectHistoryButton from './'; + +const onClick = jest.fn(); + +test('rendering without crashing', () => { + render(); +}); + +test('call onClick', () => { + render(); + waitFor(async () => { + const toggleButton = await screen.getByRole('button'); + userEvent.click(toggleButton); + expect(onClick).toHaveBeenCalled(); + }); +}); + +describe('show different titles depending on showLabel prop', () => { + test('show the label showLabel is true', () => { + render(); + expect(screen.getByText('Historical Data')).toBeTruthy(); + }); + + + test('Do not show any label if showLabel is false', () => { + render(); + expect(() => screen.getByText('Historical Data')).toThrow(); + }); +}); \ No newline at end of file diff --git a/src/SubjectHistoryButton/styles.module.scss b/src/SubjectHistoryButton/styles.module.scss new file mode 100644 index 000000000..29b51f833 --- /dev/null +++ b/src/SubjectHistoryButton/styles.module.scss @@ -0,0 +1,61 @@ +@import '../common/styles/buttons'; +@import '../common/styles/vars/colors'; + +$background_image_url: '../common/images/icons/'; + +@mixin button($image: 'tracks_off') { + background: url('#{$background-image_url+$image}.svg'); + background-size: 85%; + background-position: 0.15rem 0.1rem; + background-repeat: no-repeat; + border: none; + display: block; + height: $square-button-dimension; + outline: none; + width: $square-button-dimension; + + &:focus { + outline: none; + } +} + +.button { + @include button('historical-data'); + margin-top: 0.25rem; +} + +.container { + display: flex; + align-items: center; + flex-flow: row; + position: relative; + + &.hasLabel { + background-color: $subject-control-btn-bg; + border: 0.06px solid $secondary-medium-light-gray; + max-width: 5.75rem; + max-height: 1.85rem; + border-radius: 0.25rem; + cursor: pointer; + + [class*=spinner] { + position: relative; + top: -16%; + } + + button { + min-height: 1.80rem; + height: 1.80rem; + min-width: 1.80rem; + width: 1.80rem; + } + + span { + font-size: 0.68rem; + line-height: normal; + padding: .1rem .7rem; + margin: 0 -.2rem; + } + } + +} diff --git a/src/SubjectPopup/index.js b/src/SubjectPopup/index.js index 2b792b5bd..cfc1d8ed5 100644 --- a/src/SubjectPopup/index.js +++ b/src/SubjectPopup/index.js @@ -1,4 +1,4 @@ -import React, { lazy, memo, Fragment, useCallback, useMemo, useState } from 'react'; +import React, { memo, Fragment, useCallback, useMemo, useState } from 'react'; import PropTypes from 'prop-types'; import { connect } from 'react-redux'; import format from 'date-fns/format'; @@ -12,7 +12,6 @@ import SubjectControls from '../SubjectControls'; import { ReactComponent as ChatIcon } from '../common/images/icons/chat-icon.svg'; import AddReport from '../AddReport'; -import { addModal } from '../ducks/modals'; import { showPopup } from '../ducks/popup'; import { DEVELOPMENT_FEATURE_FLAGS } from '../constants'; @@ -24,11 +23,9 @@ import styles from './styles.module.scss'; const { ENABLE_UFA_NAVIGATION_UI } = DEVELOPMENT_FEATURE_FLAGS; -const SubjectHistoricalDataModal = lazy(() => import('../SubjectHistoricalDataModal')); - const STORAGE_KEY = 'showSubjectDetailsByDefault'; -const SubjectPopup = ({ data, popoverPlacement, timeSliderState, addModal, showPopup }) => { +const SubjectPopup = ({ data, popoverPlacement, timeSliderState, showPopup }) => { const { geometry, properties } = data; const { active: isTimeSliderActive } = timeSliderState; @@ -40,8 +37,10 @@ const SubjectPopup = ({ data, popoverPlacement, timeSliderState, addModal, showP const { tracks_available } = properties; const coordProps = typeof properties.coordinateProperties === 'string' ? JSON.parse(properties.coordinateProperties) : properties.coordinateProperties; + const isStatic = subjectIsStatic(data); + const hasAdditionalDeviceProps = !!device_status_properties?.length; - const additionalPropsShouldBeToggleable = hasAdditionalDeviceProps && device_status_properties.length > 2 && !subjectIsStatic(data); + const additionalPropsShouldBeToggleable = hasAdditionalDeviceProps && device_status_properties.length > 2 && !isStatic; const [additionalPropsToggledOn, toggleAdditionalPropsVisibility] = useState(window.localStorage.getItem(STORAGE_KEY) === 'true' ? true : false); const showAdditionalProps = hasAdditionalDeviceProps && @@ -62,10 +61,6 @@ const SubjectPopup = ({ data, popoverPlacement, timeSliderState, addModal, showP showPopup('subject-messages', { geometry, properties: properties, coordinates: geometry.coordinates }); }, [geometry, properties, showPopup]); - const onHistoricalDataClick = useCallback(() => { - addModal({ title: 'Historical Data', content: SubjectHistoricalDataModal, subjectId: properties.id }); - }, [addModal, properties]); - const locationObject = { longitude: geometry.coordinates[0], latitude: geometry.coordinates[1], @@ -79,7 +74,7 @@ const SubjectPopup = ({ data, popoverPlacement, timeSliderState, addModal, showP
{properties.default_status_value && <> {properties.image && {`Subject} - {!isTimeSliderActive ? properties.default_status_value : 'No historical data'} + {properties.default_status_value} }
{properties.name}
@@ -111,33 +106,32 @@ const SubjectPopup = ({ data, popoverPlacement, timeSliderState, addModal, showP
} {tracks_available && } - {hasAdditionalDeviceProps && showAdditionalProps && } From ea09a75ac52f38b1f5ac96f7e08a72d0ae82f301 Mon Sep 17 00:00:00 2001 From: Joshua Krautwurst Date: Thu, 19 May 2022 14:19:25 -0700 Subject: [PATCH 16/18] css tweaks for overflow issue --- src/SubjectControls/_mixins.scss | 1 - src/SubjectControls/styles.module.scss | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SubjectControls/_mixins.scss b/src/SubjectControls/_mixins.scss index d2c1e6e38..4dd43a643 100644 --- a/src/SubjectControls/_mixins.scss +++ b/src/SubjectControls/_mixins.scss @@ -14,7 +14,6 @@ display: flex; flex-flow: row; line-height: normal; - overflow: hidden; position: relative; .button { diff --git a/src/SubjectControls/styles.module.scss b/src/SubjectControls/styles.module.scss index 6e9ccc4ff..ef2485185 100644 --- a/src/SubjectControls/styles.module.scss +++ b/src/SubjectControls/styles.module.scss @@ -30,6 +30,7 @@ max-width: 5.75rem; max-height: 1.85rem; border-radius: 0.2rem; + overflow: hidden; cursor: pointer; [class*=spinner] { From 6a761dfcbb2fcf18b27aa7d72ba6db160127a3fe Mon Sep 17 00:00:00 2001 From: Joshua Krautwurst Date: Thu, 19 May 2022 14:50:28 -0700 Subject: [PATCH 17/18] font size tweak --- src/SubjectControls/styles.module.scss | 2 +- src/SubjectHistoryButton/styles.module.scss | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/SubjectControls/styles.module.scss b/src/SubjectControls/styles.module.scss index ef2485185..e977c79ab 100644 --- a/src/SubjectControls/styles.module.scss +++ b/src/SubjectControls/styles.module.scss @@ -46,7 +46,7 @@ } span { - font-size: 0.68rem; + font-size: 0.65rem; line-height: normal; padding: 0.1rem 0.3rem; margin: 0 -.2rem; diff --git a/src/SubjectHistoryButton/styles.module.scss b/src/SubjectHistoryButton/styles.module.scss index b04f79eb7..154b3a49f 100644 --- a/src/SubjectHistoryButton/styles.module.scss +++ b/src/SubjectHistoryButton/styles.module.scss @@ -51,7 +51,7 @@ $background_image_url: '../common/images/icons/'; } span { - font-size: 0.68rem; + font-size: 0.65rem; line-height: normal; padding: .1rem .7rem; margin: 0 -.2rem; From aa8fc97bc72e39175f123ca0f9e564e3ee8eb2af Mon Sep 17 00:00:00 2001 From: Joshua Krautwurst Date: Fri, 20 May 2022 14:19:31 -0700 Subject: [PATCH 18/18] style tweaks as per QA feedback --- src/SubjectHistoryButton/styles.module.scss | 30 ++++++--------------- 1 file changed, 8 insertions(+), 22 deletions(-) diff --git a/src/SubjectHistoryButton/styles.module.scss b/src/SubjectHistoryButton/styles.module.scss index 154b3a49f..b22539f3b 100644 --- a/src/SubjectHistoryButton/styles.module.scss +++ b/src/SubjectHistoryButton/styles.module.scss @@ -1,34 +1,20 @@ @import '../common/styles/buttons'; @import '../common/styles/vars/colors'; +@import '../SubjectControls/mixins'; -$background_image_url: '../common/images/icons/'; - -@mixin button($image: 'tracks_off') { - background: url('#{$background-image_url+$image}.svg'); - background-size: 85%; - background-position: 0.15rem 0.1rem; - background-repeat: no-repeat; - border: none; - display: block; - height: $square-button-dimension; - outline: none; - width: $square-button-dimension; - - &:focus { - outline: none; - } -} - -.button { - @include button('historical-data'); - pointer-events: none; -} .container { display: flex; align-items: center; flex-flow: row; position: relative; + .button { + @include buttonBackground('historical-data'); + pointer-events: none; + background-size: 90%; + background-repeat: no-repeat; + background-position: center; + } &.hasLabel { background-color: $subject-control-btn-bg;