Skip to content

Commit

Permalink
Merge branch 'main' into task/WG-253--file-listing-component
Browse files Browse the repository at this point in the history
  • Loading branch information
shayanaijaz committed Jan 7, 2025
2 parents f2bf285 + a0e4ab3 commit 7fb9c46
Show file tree
Hide file tree
Showing 21 changed files with 634 additions and 164 deletions.
6 changes: 5 additions & 1 deletion react/jest.config.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const esModules = [
'react-leaflet',
'@tacc/core-components',
'uuid',
'react-leaflet-markercluster',
].join('|');

module.exports = {
Expand Down Expand Up @@ -204,7 +205,10 @@ module.exports = {
// timers: "real",

// A map from regular expressions to paths to transformers
transform: { '^.+\\.(js|jsx|mjs)?$': 'babel-jest' },
transform: {
'^.+\\.(js|jsx|mjs)?$': 'babel-jest',
'^.+\\.css$': 'jest-transform-stub',
},

// An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation
transformIgnorePatterns: [`/node_modules/(?!(${esModules}))`],
Expand Down
38 changes: 20 additions & 18 deletions react/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 4 additions & 3 deletions react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@
"@babel/preset-env": "^7.20.2",
"@babel/preset-react": "^7.18.6",
"@babel/preset-typescript": "^7.21.0",
"@changey/react-leaflet-markercluster": "^4.0.0-rc1",
"@fortawesome/fontawesome-svg-core": "^6.6.0",
"@fortawesome/free-solid-svg-icons": "^6.6.0",
"@fortawesome/react-fontawesome": "^0.2.2",
Expand All @@ -54,7 +53,8 @@
"eslint-plugin-react-hooks": "^4.6.0",
"formik": "^2.4.5",
"jwt-decode": "^4.0.0",
"leaflet": "^1.9.3",
"leaflet": "^1.9.4",
"leaflet.markercluster": "^1.5.3",
"postcss-nesting": "^12.0.3",
"prettier": "^2.7.1",
"prop-types": "^15.8.1",
Expand All @@ -63,7 +63,8 @@
"react-dom": "^18.2.0",
"react-dropzone": "^14.2.3",
"react-esri-leaflet": "^2.0.1",
"react-leaflet": "^4.2.0",
"react-leaflet": "^4.2.1",
"react-leaflet-markercluster": "^4.2.1",
"react-query": "^3.39.3",
"react-redux": "^8.0.2",
"react-resize-detector": "^7.1.2",
Expand Down
16 changes: 8 additions & 8 deletions react/src/AppRouter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ import {
Navigate,
useLocation,
} from 'react-router-dom';
import * as ROUTES from './constants/routes';
import MapProject from './pages/MapProject';
import MainMenu from './pages/MainMenu';
import Logout from './pages/Logout/Logout';
import Login from './pages/Login/Login';
import Callback from './pages/Callback/Callback';
import StreetviewCallback from './pages/StreetviewCallback/StreetviewCallback';
import { RootState } from './redux/store';
import * as ROUTES from '@hazmapper/constants/routes';
import MapProject from '@hazmapper/pages/MapProject';
import MainMenu from '@hazmapper/pages/MainMenu';
import Logout from '@hazmapper/pages/Logout/Logout';
import Login from '@hazmapper/pages/Login/Login';
import Callback from '@hazmapper/pages/Callback/Callback';
import StreetviewCallback from '@hazmapper/pages/StreetviewCallback/StreetviewCallback';
import { RootState } from '@hazmapper/redux/store';
import { isTokenValid } from '@hazmapper/utils/authUtils';
import { useBasePath } from '@hazmapper/hooks/environment';

Expand Down
4 changes: 2 additions & 2 deletions react/src/components/FeatureFileTree/FeatureFileTree.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ const FeatureFileTree: React.FC<FeatureFileTreeProps> = ({
return directoryIds;
};

// Have all direcotories be in 'expanded' (i.e. everything is expanded)
// Have all directories be in 'expanded' (i.e. everything is expanded)
const expandedDirectories = getDirectoryNodeIds(fileNodeArray);

const convertToTreeNode = (node: FeatureFileNode) => ({
Expand Down Expand Up @@ -194,4 +194,4 @@ const FeatureFileTree: React.FC<FeatureFileTreeProps> = ({
);
};

export default React.memo(FeatureFileTree);
export default FeatureFileTree;
39 changes: 3 additions & 36 deletions react/src/components/FeatureIcon/FeatureIcon.tsx
Original file line number Diff line number Diff line change
@@ -1,49 +1,16 @@
import React from 'react';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { IconDefinition } from '@fortawesome/fontawesome-svg-core';
import {
faCameraRetro,
faVideo,
faClipboardList,
faMapMarkerAlt,
faDrawPolygon,
faCloud,
faBezierCurve,
faRoad,
faLayerGroup,
faQuestionCircle,
} from '@fortawesome/free-solid-svg-icons';

import { FeatureType, FeatureTypeNullable } from '@hazmapper/types';
import { FeatureTypeNullable } from '@hazmapper/types';
import { featureTypeToIcon } from '@hazmapper/utils/featureIconUtil';
import styles from './FeatureIcon.module.css';

const featureTypeToIcon: Record<FeatureType, IconDefinition> = {
// Asset types
image: faCameraRetro,
video: faVideo,
questionnaire: faClipboardList,
point_cloud: faCloud /* https://tacc-main.atlassian.net/browse/WG-391 */,
streetview: faRoad,

// Geometry types
Point: faMapMarkerAlt,
LineString: faBezierCurve,
Polygon: faDrawPolygon,
MultiPoint: faMapMarkerAlt,
MultiLineString: faBezierCurve,
MultiPolygon: faDrawPolygon,
GeometryCollection: faLayerGroup,

// Collection type
collection: faLayerGroup,
};

interface Props {
featureType: FeatureTypeNullable;
}

export const FeatureIcon: React.FC<Props> = ({ featureType }) => {
const icon = featureType ? featureTypeToIcon[featureType] : faQuestionCircle;
const icon = featureTypeToIcon(featureType);

return <FontAwesomeIcon className={styles.icon} icon={icon} size="sm" />;
};
80 changes: 80 additions & 0 deletions react/src/components/Map/FitBoundsHandler.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import React, { useEffect, useCallback, useRef } from 'react';
import * as turf from '@turf/turf';
import { useMap } from 'react-leaflet';
import { FeatureCollection, Feature } from '@hazmapper/types';
import { useFeatureSelection } from '@hazmapper/hooks';
import { MAP_CONFIG } from './config';
import L from 'leaflet';

const FitBoundsHandler: React.FC<{
featureCollection: FeatureCollection;
}> = ({ featureCollection }) => {
const map = useMap();
const hasFeatures = useRef(false);
const { selectedFeatureId } = useFeatureSelection();

const getBoundsFromFeature = useCallback(
(feature: FeatureCollection | Feature) => {
const bbox = turf.bbox(feature);
return [
[bbox[1], bbox[0]] as [number, number],
[bbox[3], bbox[2]] as [number, number],
];
},
[]
);

const zoomToFeature = useCallback(
(feature: Feature) => {
if (feature.geometry.type === 'Point') {
const coordinates = feature.geometry.coordinates;
const point = L.latLng(coordinates[1], coordinates[0]);

map.setView(point, MAP_CONFIG.maxPointSelectedFeatureZoom, {
animate: false,
});
} else {
const bounds = getBoundsFromFeature(feature);
map.fitBounds(bounds, {
maxZoom: MAP_CONFIG.maxFitBoundsSelectedFeatureZoom,
padding: [50, 50],
animate: false,
});
}
},
[map, getBoundsFromFeature]
);

// Handle initial bounds when features are loaded
useEffect(() => {
if (
featureCollection.features.length &&
!selectedFeatureId &&
!hasFeatures.current
) {
const bounds = getBoundsFromFeature(featureCollection);
map.fitBounds(bounds, {
maxZoom: MAP_CONFIG.maxFitBoundsInitialZoom,
padding: [50, 50],
});
hasFeatures.current = true;
}
}, [map, featureCollection, selectedFeatureId, getBoundsFromFeature]);

// Handle selected feature bounds
useEffect(() => {
if (selectedFeatureId) {
const activeFeature = featureCollection.features.find(
(f) => f.id === selectedFeatureId
);

if (activeFeature) {
zoomToFeature(activeFeature);
}
}
}, [map, selectedFeatureId, featureCollection, zoomToFeature]);

return null;
};

export default FitBoundsHandler;
48 changes: 48 additions & 0 deletions react/src/components/Map/Map.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
.markerCluster {
/* Size and shape */
min-width: 36px;
min-height: 36px;
border-radius: 50%;

/* Colors and borders */
color: #ffffff;
background: var(--global-color-accent--normal);
border: 3px solid #ffffff;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);

/* Centering container */
display: flex;
align-items: center;
justify-content: center;

/* Text styling */
font-family: var(--global-font-family--sans);
font-size: 14px;
font-weight: 500;
line-height: 1;
text-align: center;
}

/* Style for the span containing the number */
.markerCluster span {
/* Additional centering for the text itself */
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
/* Offset slightly to account for border */
margin-top: -1px;
}

.marker {
border-radius: 50%;
}

.markerContainer {
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
}
4 changes: 2 additions & 2 deletions react/src/components/Map/Map.test.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import React from 'react';
import { render } from '@testing-library/react';
import { renderInTest } from '@hazmapper/test/testUtil';
import Map from './Map';
import { tileServerLayers } from '../../__fixtures__/tileServerLayerFixture';
import { featureCollection } from '../../__fixtures__/featuresFixture';

test('renders map', () => {
const { getByText } = render(
const { getByText } = renderInTest(
<Map baseLayers={tileServerLayers} featureCollection={featureCollection} />
);
expect(getByText(/Map/)).toBeDefined();
Expand Down
Loading

0 comments on commit 7fb9c46

Please sign in to comment.