diff --git a/react/package-lock.json b/react/package-lock.json
index 92ff6cc7..bc97b59d 100644
--- a/react/package-lock.json
+++ b/react/package-lock.json
@@ -30,7 +30,6 @@
"leaflet": "^1.9.4",
"leaflet.markercluster": "^1.5.3",
"react": "^18.3.1",
- "react-datepicker": "^7.6.0",
"react-dom": "^18.3.1",
"react-esri-leaflet": "^2.0.1",
"react-hook-form": "^7.54.2",
@@ -4034,6 +4033,7 @@
"version": "1.6.9",
"resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.9.tgz",
"integrity": "sha512-uMXCuQ3BItDUbAMhIXw7UPXRfAlOAvZzdK9BWpE60MCn+Svt3aLn9jsPTi/WNGlRUu2uI0v5S7JiIUsbsvh3fw==",
+ "optional": true,
"dependencies": {
"@floating-ui/utils": "^0.2.9"
}
@@ -4042,29 +4042,17 @@
"version": "1.6.13",
"resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.13.tgz",
"integrity": "sha512-umqzocjDgNRGTuO7Q8CU32dkHkECqI8ZdMZ5Swb6QAM0t5rnlrN3lGo1hdpscRd3WS8T6DKYK4ephgIH9iRh3w==",
+ "optional": true,
"dependencies": {
"@floating-ui/core": "^1.6.0",
"@floating-ui/utils": "^0.2.9"
}
},
- "node_modules/@floating-ui/react": {
- "version": "0.27.4",
- "resolved": "https://registry.npmjs.org/@floating-ui/react/-/react-0.27.4.tgz",
- "integrity": "sha512-05mXdkUiVh8NCEcYKQ2C9SV9IkZ9k/dFtYmaEIN2riLv80UHoXylgBM76cgPJYfLJM3dJz7UE5MOVH0FypMd2Q==",
- "dependencies": {
- "@floating-ui/react-dom": "^2.1.2",
- "@floating-ui/utils": "^0.2.9",
- "tabbable": "^6.0.0"
- },
- "peerDependencies": {
- "react": ">=17.0.0",
- "react-dom": ">=17.0.0"
- }
- },
"node_modules/@floating-ui/react-dom": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.2.tgz",
"integrity": "sha512-06okr5cgPzMNBy+Ycse2A6udMi4bqwW/zgBF/rwjcNqWkyr82Mcg8b0vjX8OJpZFy/FKjJmw6wV7t44kK6kW7A==",
+ "optional": true,
"dependencies": {
"@floating-ui/dom": "^1.0.0"
},
@@ -4076,7 +4064,8 @@
"node_modules/@floating-ui/utils": {
"version": "0.2.9",
"resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.9.tgz",
- "integrity": "sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg=="
+ "integrity": "sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==",
+ "optional": true
},
"node_modules/@formatjs/ecma402-abstract": {
"version": "1.11.4",
@@ -12864,14 +12853,6 @@
"node": ">=6"
}
},
- "node_modules/clsx": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
- "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==",
- "engines": {
- "node": ">=6"
- }
- },
"node_modules/co": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
@@ -13660,6 +13641,8 @@
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.6.0.tgz",
"integrity": "sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==",
+ "optional": true,
+ "peer": true,
"funding": {
"type": "github",
"url": "https://github.com/sponsors/kossnocorp"
@@ -23420,20 +23403,6 @@
"react-dom": ">=16.8.0"
}
},
- "node_modules/react-datepicker": {
- "version": "7.6.0",
- "resolved": "https://registry.npmjs.org/react-datepicker/-/react-datepicker-7.6.0.tgz",
- "integrity": "sha512-9cQH6Z/qa4LrGhzdc3XoHbhrxNcMi9MKjZmYgF/1MNNaJwvdSjv3Xd+jjvrEEbKEf71ZgCA3n7fQbdwd70qCRw==",
- "dependencies": {
- "@floating-ui/react": "^0.27.0",
- "clsx": "^2.1.1",
- "date-fns": "^3.6.0"
- },
- "peerDependencies": {
- "react": "^16.9.0 || ^17 || ^18 || ^19 || ^19.0.0-rc",
- "react-dom": "^16.9.0 || ^17 || ^18 || ^19 || ^19.0.0-rc"
- }
- },
"node_modules/react-display-name": {
"version": "0.2.5",
"resolved": "https://registry.npmjs.org/react-display-name/-/react-display-name-0.2.5.tgz",
@@ -25545,11 +25514,6 @@
"url": "https://opencollective.com/unts"
}
},
- "node_modules/tabbable": {
- "version": "6.2.0",
- "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz",
- "integrity": "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew=="
- },
"node_modules/tar": {
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz",
diff --git a/react/package.json b/react/package.json
index 1b521227..80f2abc2 100644
--- a/react/package.json
+++ b/react/package.json
@@ -54,7 +54,6 @@
"leaflet": "^1.9.4",
"leaflet.markercluster": "^1.5.3",
"react": "^18.3.1",
- "react-datepicker": "^7.6.0",
"react-dom": "^18.3.1",
"react-esri-leaflet": "^2.0.1",
"react-hook-form": "^7.54.2",
diff --git a/react/src/components/DeleteMapModal/DeleteMapModal.test.tsx b/react/src/components/DeleteMapModal/DeleteMapModal.test.tsx
index 7af9d499..38ba522e 100644
--- a/react/src/components/DeleteMapModal/DeleteMapModal.test.tsx
+++ b/react/src/components/DeleteMapModal/DeleteMapModal.test.tsx
@@ -91,13 +91,17 @@ describe('DeleteMapModal', () => {
it('should disable delete button for non-deletable projects', async () => {
await renderComponent(nonDeletableProjectMock);
- const deleteButton = screen.getByText('Delete') as HTMLButtonElement;
+ const deleteButton = screen.getByTestId(
+ 'delete-map-button'
+ ) as HTMLButtonElement;
expect(deleteButton.disabled).toBe(true);
});
it('should enable delete button for deletable projects', async () => {
await renderComponent();
- const deleteButton = screen.getByText('Delete') as HTMLButtonElement;
+ const deleteButton = screen.getByTestId(
+ 'delete-map-button'
+ ) as HTMLButtonElement;
expect(deleteButton.disabled).toBe(false);
});
diff --git a/react/src/components/DeleteMapModal/DeleteMapModal.tsx b/react/src/components/DeleteMapModal/DeleteMapModal.tsx
index 3e5f2ca2..6859902f 100644
--- a/react/src/components/DeleteMapModal/DeleteMapModal.tsx
+++ b/react/src/components/DeleteMapModal/DeleteMapModal.tsx
@@ -1,6 +1,5 @@
import React from 'react';
-import { Modal, ModalHeader, ModalBody, ModalFooter } from 'reactstrap';
-import { Button, SectionMessage } from '@tacc/core-components';
+import { Modal, Layout, Flex, Alert } from 'antd';
import { useNavigate } from 'react-router-dom';
import { Project } from '@hazmapper/types';
import { useDeleteProject } from '@hazmapper/hooks/projects/';
@@ -26,6 +25,9 @@ const DeleteMapModal = ({
isError,
isSuccess,
} = useDeleteProject();
+
+ const { Header } = Layout;
+
const handleClose = () => {
parentToggle();
};
@@ -46,45 +48,56 @@ const DeleteMapModal = ({
};
return (
-
-
- Delete Map: {project?.name}{' '}
-
-
+ Delete Map: {project?.name}}
+ onOk={handleDeleteProject}
+ okText="Delete"
+ cancelText={isSuccess ? 'Close' : 'Cancel'}
+ okButtonProps={{
+ loading: isDeletingProject,
+ disabled: isSuccess || !project?.deletable,
+ 'data-testid': 'delete-map-button',
+ }}
+ >
+
{project?.deletable ? (
- <>
- Are you sure you want to delete this map? All associated features,
- metadata, and saved files will be deleted.
- {project?.public && Note that this is a public map. }
-
-
- This cannot be undone.
-
- >
+
+ Are you sure you want to delete this map? All associated
+ features, metadata, and saved files will be deleted.
+
+
+ {project?.public && (
+
+ {' '}
+ Note that this is a public map.
+
+
+
+ )}
+
+ This cannot be undone.
+
+
+ }
+ />
) : (
- 'You don’t have permission to delete this map.'
+ "You don't have permission to delete this map."
)}
-
-
-
-
+
{isError && (
-
- {'There was an error deleting your map.'}
-
+
+
+
)}
-
+
);
};
diff --git a/react/src/components/FiltersPanel/Filter.tsx b/react/src/components/FiltersPanel/Filter.tsx
index ee0009ad..c74ca249 100644
--- a/react/src/components/FiltersPanel/Filter.tsx
+++ b/react/src/components/FiltersPanel/Filter.tsx
@@ -1,25 +1,21 @@
import React from 'react';
import styles from './Filters.module.css';
-import DatePicker from 'react-datepicker';
-import { Button, Flex } from 'antd';
-import 'react-datepicker/dist/react-datepicker.css';
+import { DatePicker } from 'antd';
+import { Button, Flex, Tooltip } from 'antd';
+import type { Dayjs } from 'dayjs';
+import { QuestionCircleOutlined } from '@ant-design/icons';
interface FiltersProps {
selectedAssetTypes: string[];
onFiltersChange: (selectedAssetTypes: string[]) => void;
- startDate: Date;
- setStartDate: (date: Date) => void;
- endDate: Date;
- setEndDate: (date: Date) => void;
+ startDate: Dayjs;
+ setStartDate: (date: Dayjs) => void;
+ endDate: Dayjs;
+ setEndDate: (date: Dayjs) => void;
toggleDateFilter: boolean;
setToggleDateFilter: (toggleDateFilter: boolean) => void;
}
-interface CustomInputProps {
- value?: string;
- onClick?: () => void;
-}
-
export const assetTypeOptions = {
Image: 'Image',
Video: 'Video',
@@ -47,29 +43,6 @@ const Filters: React.FC = ({
}
};
- const CustomInputWithTooltip = React.forwardRef<
- HTMLInputElement,
- CustomInputProps
- >(({ value, onClick }, ref) => (
-
-
-
- ?
-
-
- ));
-
- CustomInputWithTooltip.displayName = 'CustomInputWithTooltip';
-
return (
{toggleDateFilter ? (
@@ -77,26 +50,31 @@ const Filters: React.FC = ({
- Date Range
- Start Date
- setStartDate(date as Date)}
- selectsStart
- startDate={startDate}
- endDate={endDate}
- customInput={}
- />
- End Date
- setEndDate(date as Date)}
- selectsEnd
- startDate={startDate}
- endDate={endDate}
- minDate={startDate}
- customInput={}
- />
+
+
+
+ Date Range
+
+ } />
+
+
+
+ Start Date
+
+ End Date
+
+
>
) : (
);
};
diff --git a/react/src/hooks/features/useFeatures.ts b/react/src/hooks/features/useFeatures.ts
index 2ae69d43..2f8ddb3b 100644
--- a/react/src/hooks/features/useFeatures.ts
+++ b/react/src/hooks/features/useFeatures.ts
@@ -5,13 +5,14 @@ import {
} from '@tanstack/react-query';
import { FeatureCollection } from '@hazmapper/types';
import { useGet } from '@hazmapper/requests';
+import type { Dayjs } from 'dayjs';
interface UseFeaturesParams {
projectId: number;
isPublicView: boolean;
assetTypes: string[];
- startDate?: Date;
- endDate?: Date;
+ startDate?: Dayjs;
+ endDate?: Dayjs;
toggleDateFilter?: boolean;
options?: object;
}
@@ -29,12 +30,21 @@ export const useFeatures = ({
}: UseFeaturesParams): UseQueryResult => {
// TODO can be reworked as /projects can be used and /public-projects can be removed since we are no longer a WSO2 API
const featuresRoute = isPublicView ? 'public-projects' : 'projects';
- let endpoint = `/${featuresRoute}/${projectId}/features/`;
+ const endpoint = `/${featuresRoute}/${projectId}/features/`;
+
+ let queryParams = {};
if (assetTypes?.length) {
- endpoint += `?assetType=${assetTypes.join(',')}`;
+ queryParams = {
+ ...queryParams,
+ assetType: assetTypes.join(','),
+ };
}
if (startDate && endDate && toggleDateFilter) {
- endpoint += `&startDate=${startDate.toISOString()}&endDate=${endDate.toISOString()}`;
+ queryParams = {
+ ...queryParams,
+ startDate: startDate.toISOString(),
+ endDate: endDate.toISOString(),
+ };
}
const defaultQueryOptions = {
@@ -54,12 +64,11 @@ export const useFeatures = ({
projectId,
isPublicView,
assetTypes,
- startDate,
- endDate,
- toggleDateFilter,
+ queryParams,
},
],
options: { ...defaultQueryOptions, ...options },
+ params: queryParams,
});
return query;
};
diff --git a/react/src/pages/Callback/Callback.test.tsx b/react/src/pages/Callback/Callback.test.tsx
index 6edc3356..7ce97af4 100644
--- a/react/src/pages/Callback/Callback.test.tsx
+++ b/react/src/pages/Callback/Callback.test.tsx
@@ -3,7 +3,7 @@ import { renderInTest } from '@hazmapper/test/testUtil';
import Callback from './Callback';
test('renders callback', async () => {
- const { getByText } = renderInTest(, '/callback');
+ const { getByTestId } = renderInTest(, '/callback');
- expect(getByText(/Logging in/)).toBeDefined();
+ expect(getByTestId('spin')).toBeTruthy();
});
diff --git a/react/src/pages/Callback/Callback.tsx b/react/src/pages/Callback/Callback.tsx
index 4ba8786b..11a94f66 100644
--- a/react/src/pages/Callback/Callback.tsx
+++ b/react/src/pages/Callback/Callback.tsx
@@ -3,6 +3,7 @@ import { useLocation, useNavigate } from 'react-router-dom';
import { useDispatch } from 'react-redux';
import { jwtDecode } from 'jwt-decode';
import { loginSuccess } from '../../redux/authSlice';
+import { Flex, Spin } from 'antd';
import { AuthenticatedUser, AuthToken } from '@hazmapper/types';
export default function CallbackPage() {
@@ -29,5 +30,9 @@ export default function CallbackPage() {
}
}, [dispatch, location, navigate]);
- return Logging in.
;
+ return (
+
+
+
+ );
}
diff --git a/react/src/pages/MapProject/MapProject.module.css b/react/src/pages/MapProject/MapProject.module.css
index 0d3375b6..368b183d 100644
--- a/react/src/pages/MapProject/MapProject.module.css
+++ b/react/src/pages/MapProject/MapProject.module.css
@@ -36,7 +36,7 @@
padding: 5px;
right: 10px;
top: 75px;
- bottom: 20px;
+ bottom: 125px;
z-index: 1050;
}
diff --git a/react/src/pages/MapProject/MapProject.tsx b/react/src/pages/MapProject/MapProject.tsx
index eead0d19..3e06a76b 100644
--- a/react/src/pages/MapProject/MapProject.tsx
+++ b/react/src/pages/MapProject/MapProject.tsx
@@ -38,6 +38,7 @@ import * as z from 'zod';
import { useForm, FormProvider } from 'react-hook-form';
import StreetviewPanel from '@hazmapper/components/StreetviewPanel';
import PublicInfoPanel from '@hazmapper/components/PublicInfoPanel';
+import dayjs from 'dayjs';
export const tileLayerSchema = z.object({
id: z.number(),
@@ -161,10 +162,9 @@ const LoadedMapProject: React.FC = ({
Object.keys(assetTypeOptions)
);
const [toggleDateFilter, setToggleDateFilter] = React.useState(false);
- const [startDate, setStartDate] = useState(new Date());
- const [endDate, setEndDate] = useState(
- new Date(Date.now() + 24 * 60 * 60 * 1000)
- );
+ const [startDate, setStartDate] = useState(dayjs().startOf('day'));
+ const [endDate, setEndDate] = useState(dayjs().add(1, 'day').startOf('day'));
+
const { selectedFeature, setSelectedFeatureId: toggleSelectedFeature } =
useFeatureSelection();
const [isQuestionnaireModalOpen, setQuestionnaireModalOpen] = useState(false);
@@ -186,15 +186,14 @@ const LoadedMapProject: React.FC = ({
formatAssetTypeName(type)
);
- const { data: rawFeatureCollection, isLoading: isFeaturesLoading } =
- useFeatures({
- projectId: activeProject.id,
- isPublicView,
- assetTypes: formattedAssetTypes,
- startDate,
- endDate,
- toggleDateFilter,
- });
+ const { data: rawFeatureCollection } = useFeatures({
+ projectId: activeProject.id,
+ isPublicView,
+ assetTypes: formattedAssetTypes,
+ startDate,
+ endDate,
+ toggleDateFilter,
+ });
const { data: tileServerLayers, isLoading: isTileServerLayersLoading } =
useGetTileServers({
@@ -207,8 +206,6 @@ const LoadedMapProject: React.FC = ({
const queryParams = new URLSearchParams(location.search);
const activePanel = queryParams.get(queryPanelKey);
- const loading = isFeaturesLoading || isTileServerLayersLoading;
-
const featureCollection = rawFeatureCollection ?? {
type: 'FeatureCollection',
features: [],
@@ -263,7 +260,7 @@ const LoadedMapProject: React.FC = ({
}}
>
- {activePanel && !loading && (
+ {activePanel && !isTileServerLayersLoading && (
= ({
- {loading ? (
+ {isTileServerLayersLoading ? (
) : (
<>
- {selectedFeature && (
-
-
- toggleSelectedFeature(selectedFeature.id)
- }
- isPublicView={isPublicView}
- onQuestionnaireClick={handleQuestionnaireClick}
- />
-
- )}
- {isQuestionnaireModalOpen && selectedFeature && (
- setQuestionnaireModalOpen(false)}
- feature={selectedFeature}
- />
- )}
>
)}
+ {selectedFeature && (
+
+
toggleSelectedFeature(selectedFeature.id)}
+ isPublicView={isPublicView}
+ onQuestionnaireClick={handleQuestionnaireClick}
+ />
+
+ )}
+ {isQuestionnaireModalOpen && selectedFeature && (
+ setQuestionnaireModalOpen(false)}
+ feature={selectedFeature}
+ />
+ )}
diff --git a/react/src/requests.ts b/react/src/requests.ts
index 40fc188c..b30c6e13 100644
--- a/react/src/requests.ts
+++ b/react/src/requests.ts
@@ -113,7 +113,7 @@ export function useGet({
}
analytics_params = { ...analytics_params, guest_uuid: guestUuid };
}
- params = { ...analytics_params };
+ params = { ...params, ...analytics_params };
}
const getUtil = async () => {