Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

record table touch handler #2935

Merged
merged 4 commits into from
Oct 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions appv2/src/UI/Overlay/Records/RecordSet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,15 @@ import {
import { OverlayHeader } from '../OverlayHeader';
import FilterAltIcon from '@mui/icons-material/FilterAlt';
import FilterAltOffIcon from '@mui/icons-material/FilterAltOff';
import { TouchHoldHandler } from '../TouchHoldHandler/TouchHoldHandler';
import { detectTouchDevice } from 'util/detectTouch';

export const RecordSet = (props) => {
const userSettingsState = useSelector(selectUserSettings);
const viewFilters = useSelector((state: any) => state.Map.viewFilters);
const history = useHistory();
const dispatch = useDispatch();
const isTouch = detectTouchDevice();

const [filterTypeChooserOpen, setFilterTypeChooserOpen] = React.useState(false);

Expand All @@ -51,6 +54,7 @@ export const RecordSet = (props) => {
return (
<div className="recordSet_container">
<OverlayHeader />
{isTouch && <TouchHoldHandler /> }
<div className="stickyHeader">
<div
className="recordSet_header"
Expand Down
51 changes: 33 additions & 18 deletions appv2/src/UI/Overlay/Records/RecordTable.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
import React from 'react';
import React, { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { selectMap } from 'state/reducers/map';
import { selectUserSettings } from 'state/reducers/userSettings';
import './RecordTable.css';
import {
activityColumnsToDisplay,
getUnnestedFieldsForActivity,
getUnnestedFieldsForIAPP,
iappColumnsToDisplay
} from './RecordTableHelpers';
import { USER_CLICKED_RECORD, USER_HOVERED_RECORD } from 'state/actions';
import { activityColumnsToDisplay, getUnnestedFieldsForActivity, getUnnestedFieldsForIAPP, iappColumnsToDisplay } from './RecordTableHelpers';
import { USER_CLICKED_RECORD, USER_HOVERED_RECORD, USER_TOUCHED_RECORD } from 'state/actions';
import { detectTouchDevice } from 'util/detectTouch';

export const RecordTableHeader = (props) => {};
export const RecordTableHeader = (props) => {}

export const RecordTable = (props) => {
const unmappedRows = useSelector((state: any) => state.Map?.recordTables?.[props.setID]?.rows);
Expand All @@ -20,6 +16,7 @@ export const RecordTable = (props) => {
// const tableType = userSettingsState?.recordSets?.[props.setID]?.recordSetType;
const dispatch = useDispatch();
const quickPanToRecord = useSelector((state: any) => state.Map?.quickPanToRecord);
const isTouch = detectTouchDevice();

// maybe useful for when there's no headers during dev for adding new types:
/*
Expand Down Expand Up @@ -60,15 +57,21 @@ export const RecordTable = (props) => {
{mappedRows?.map((row, i) => {
return (
<tr
onClick={() => {
dispatch({
type: USER_CLICKED_RECORD,
payload: {
recordType: tableType,
id: tableType === 'Activity' ? row.activity_id : row.site_id,
row: row
}
});
onContextMenu={(event) => {{
event.preventDefault();
event.stopPropagation();
}}}
onClick={()=> {
if(!isTouch) {
dispatch({
type: USER_CLICKED_RECORD,
payload: {
recordType: tableType,
id: tableType === 'Activity'? row.activity_id : row.site_id,
row: row
}
});
}
}}
onMouseOver={() => {
if (quickPanToRecord)
Expand All @@ -81,6 +84,18 @@ export const RecordTable = (props) => {
}
});
}}
onTouchStart={()=> {
if (quickPanToRecord) {
dispatch({
type: USER_TOUCHED_RECORD,
payload: {
recordType: tableType,
id: tableType === 'Activity'? row.activity_id : row.site_id,
row: row
}
});
}
}}
className="record_table_row"
key={i}>
{tableType === 'Activity'
Expand Down
1 change: 1 addition & 0 deletions appv2/src/UI/Overlay/Records/Records.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { selectUserSettings } from 'state/reducers/userSettings';
import { Activity } from './Record';
import './Records.css';
import { OverlayHeader } from '../OverlayHeader';
import { TouchHoldHandler } from '../TouchHoldHandler/TouchHoldHandler';

export const Records = (props) => {
// this version of layer 'highlighting' uses a usestate variable, but should be turned into a redux state variable
Expand Down
22 changes: 22 additions & 0 deletions appv2/src/UI/Overlay/TouchHoldHandler/TouchHoldHandler.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#touch-loader {
position: absolute;
width: 100px;
height: 50px;
bottom: 50%;
left: 50%;
margin: 100px 0 0 0px;
background: white;
border-radius: 1rem;
z-index: 9999999999;
visibility: hidden;
}

#touch-loader-bar {
position: absolute;
top:0;
left:0;
width: 0%;
height: 100%;
background-color: #223f75ab;
border-radius: 1rem;
}
80 changes: 80 additions & 0 deletions appv2/src/UI/Overlay/TouchHoldHandler/TouchHoldHandler.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import React, { useEffect, useState } from "react";
import { useDispatch } from "react-redux";
import { USER_CLICKED_RECORD } from "state/actions";
import { selectMap } from "state/reducers/map";
import { useSelector } from "util/use_selector";
import './TouchHoldHandler.css';

export const TouchHoldHandler = (props) => {
const dispatch = useDispatch();
const mapState = useSelector(selectMap);
const [shouldProgress, setShouldProgress] = useState(false);
const [progress, setProgress] = useState(0);

useEffect(() => {
let touchLoaderBar = document.getElementById('touch-loader-bar');
let touchLoader = document.getElementById('touch-loader');
window.addEventListener('touchstart', (event) => {
touchLoader.style.visibility = "visible";
touchLoader.style.left = `${(event.touches[0].clientX).toString()}px`;
touchLoader.style.bottom = `${(window.innerHeight - event.touches[0].clientY).toString()}px`;

setShouldProgress(true);
});

window.addEventListener('touchend', (event) => {
setShouldProgress(false);
setProgress(0);
touchLoaderBar.style.width = 0 + "%";
touchLoader.style.visibility = "hidden";
});
}, []);

useEffect(() => {
if (shouldProgress && progress == 0) {
setProgress(1);
var width = 1;

const frame = () => {
let touchLoaderBar = document.getElementById('touch-loader-bar');
window.addEventListener('touchend', (event) => {
let touchLoader = document.getElementById('touch-loader');
if (touchLoader) touchLoader.style.visibility = "hidden";
clearInterval(id);
setProgress(0);
setShouldProgress(false);
});
if (width >= 100) {
clearInterval(id);
openMenu();
setProgress(0);
} else {
width++;
if (touchLoaderBar) touchLoaderBar.style.width = width + "%";
}
}
var id = setInterval(frame, 10);
}
}, [shouldProgress])

const openMenu = () => {
if (shouldProgress) {
dispatch({
type: USER_CLICKED_RECORD,
payload: {
recordType: mapState?.userRecordOnHoverRecordType,
id: mapState?.userRecordOnHoverRecordID,
row: mapState?.userRecordOnHoverRecordRow
}}
);
}
}


return (
<div id='touch-loader'>
<div id='touch-loader-bar'></div>
Hold To Open
</div>
);
}
1 change: 1 addition & 0 deletions appv2/src/state/actions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export const URL_CHANGE = 'URL_CHANGE';

export const USER_CLICKED_RECORD = 'USER_CLICKED_RECORD'
export const USER_HOVERED_RECORD = 'USER_HOVERED_RECORD'
export const USER_TOUCHED_RECORD = 'USER_TOUCHED_RECORD'
export const RECORDSETS_TOGGLE_VIEW_FILTER = 'RECORDSETS_TOGGLE_VIEW_FILTER'

export const AUTH_REQUEST_COMPLETE = 'AUTH_REQUEST_COMPLETE';
Expand Down
35 changes: 25 additions & 10 deletions appv2/src/state/reducers/map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ import {
RECORDSETS_TOGGLE_VIEW_FILTER,
USER_HOVERED_RECORD,
INIT_SERVER_BOUNDARIES_GET,
TOGGLE_QUICK_PAN_TO_RECORD
TOGGLE_QUICK_PAN_TO_RECORD,
USER_TOUCHED_RECORD
} from '../actions';

import { AppConfig } from '../config';
Expand Down Expand Up @@ -89,6 +90,10 @@ class MapState {
tooManyLabelsDialog: IGeneralDialog;
viewFilters: boolean;
quickPanToRecord: boolean;
userRecordOnHoverMenuOpen: boolean;
userRecordOnHoverRecordType: any;
userRecordOnHoverRecordID: any;
userRecordOnHoverRecordRow: any;

constructor() {
this.initialized = false;
Expand All @@ -102,24 +107,24 @@ class MapState {
{
title: 'Regional Districts',
type: 'wms',
url: 'https://openmaps.gov.bc.ca/geo/pub/WHSE_ADMIN_BOUNDARIES.ADM_NR_REGIONAL_DISTRICTS_SVW/ows',
url: 'https://openmaps.gov.bc.ca/geo/pub/WHSE_ADMIN_BOUNDARIES.ADM_NR_REGIONAL_DISTRICTS_SVW/ows'
},
{
title: 'BC Parks',
type: 'wms',
url: 'https://openmaps.gov.bc.ca/geo/pub/WHSE_ADMIN_BOUNDARIES.ADM_BC_PROTECTED_AREAS_PARKS/ows',
url: 'https://openmaps.gov.bc.ca/geo/pub/WHSE_ADMIN_BOUNDARIES.ADM_BC_PROTECTED_AREAS_PARKS/ows'
},
{
title: 'Conservancy Areas',
type: 'wms',
url: 'https://openmaps.gov.bc.ca/geo/pub/WHSE_ADMIN_BOUNDARIES.ADM_BC_PROTECTED_AREAS_CONSERVANCY/ows',
url: 'https://openmaps.gov.bc.ca/geo/pub/WHSE_ADMIN_BOUNDARIES.ADM_BC_PROTECTED_AREAS_CONSERVANCY/ows'
},
{
title: 'Municipality Boundaries',
type: 'wms',
url: 'https://openmaps.gov.bc.ca/geo/pub/WHSE_ADMIN_BOUNDARIES.ADM_NR_MUNICIPALITIES_SP/ows',
url: 'https://openmaps.gov.bc.ca/geo/pub/WHSE_ADMIN_BOUNDARIES.ADM_NR_MUNICIPALITIES_SP/ows'
}
]
];
this.baseMapToggle = false;
this.HDToggle = false;
this.activityPageMapExtentToggle = false;
Expand Down Expand Up @@ -157,7 +162,7 @@ class MapState {
page: 0,
highlightedType: null
};
this.quickPanToRecord = false
this.quickPanToRecord = false;
}
}
const initialState = new MapState();
Expand All @@ -169,7 +174,7 @@ function createMapReducer(configuration: AppConfig): (MapState, AnyAction) => Ma
case RECORDSETS_TOGGLE_VIEW_FILTER: {
const nextState = createNextState(state, (draftState) => {
draftState.viewFilters = !draftState.viewFilters;
})
});
return nextState;
}
case USER_CLICKED_RECORD: {
Expand All @@ -196,6 +201,16 @@ function createMapReducer(configuration: AppConfig): (MapState, AnyAction) => Ma
});
return nextState;
}
case USER_TOUCHED_RECORD: {
const nextState = createNextState(state, (draftState) => {
draftState.userRecordOnHoverMenuOpen = true;
draftState.userRecordOnHoverRecordType = action.payload.recordType;
draftState.userRecordOnHoverRecordID = action.payload.id;
draftState.userRecordOnHoverRecordRow = action.payload.row;
draftState.touchTime = Date.now();
});
return nextState;
}
case URL_CHANGE: {
return {
...state,
Expand Down Expand Up @@ -498,14 +513,14 @@ function createMapReducer(configuration: AppConfig): (MapState, AnyAction) => Ma
case RECORDSET_REMOVE_FILTER: {
const nextState = createNextState(state, (draftState) => {
draftState.recordTables[action.payload.setID].page = 0;
})
});
return nextState;
}
case INIT_SERVER_BOUNDARIES_GET: {
const nextState = createNextState(state, (draftState) => {
//draftState.layers[action.payload.setID].loaded = false;
draftState.serverBoundaries = action.payload.data;
})
});
return nextState;
}
case PAGE_OR_LIMIT_UPDATE: {
Expand Down
12 changes: 12 additions & 0 deletions appv2/src/util/detectTouch.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export function detectTouchDevice() {
const toMatch = [
/Android/i,
/webOS/i,
/iPhone/i,
/iPad/i,
];

return toMatch.some((toMatchItem) => {
return navigator.userAgent.match(toMatchItem);
});
}
Loading