From 32cad260427223499290acff382e09fbde620c95 Mon Sep 17 00:00:00 2001 From: Alessandro Kreslin Date: Mon, 13 Jul 2026 09:35:17 -0400 Subject: [PATCH 1/5] eslint rules set 1 --- eslint.config.mjs | 11 ++++++++--- .../account/notifications/AccountNotifications.tsx | 4 +--- .../complete-registration/CompleteRegistration.tsx | 2 +- .../contribute/FeedSubmission/Form/FirstStep.tsx | 6 +++++- .../contribute/FeedSubmission/Form/FourthStep.tsx | 6 +++++- .../contribute/FeedSubmission/Form/SecondStep.tsx | 6 +++++- .../FeedSubmission/Form/SecondStepRealtime.tsx | 6 +++++- .../contribute/FeedSubmission/Form/ThirdStep.tsx | 6 +++++- .../feeds/[feedDataType]/[feedId]/static/layout.tsx | 4 ++-- src/app/[locale]/layout.tsx | 2 +- src/app/api/revalidate/route.spec.ts | 6 +++--- src/app/api/revalidate/route.ts | 2 +- src/app/api/session/route.ts | 4 ++-- src/app/components/GtfsVisualizationMap.spec.tsx | 2 +- src/app/components/Map/SelectedRoutesStopsPanel.tsx | 2 +- src/app/components/ThemeToggle.tsx | 3 ++- .../Feed/components/NotificationSettingsDialog.tsx | 4 +--- src/app/screens/FeedSubmitted.tsx | 8 ++++++-- src/app/screens/GbfsValidator/GbfsFeedSearchInput.tsx | 8 +++++--- .../GbfsValidator/components/ErrorDetailsDialog.tsx | 4 ++-- src/app/services/api-auth-middleware.ts | 2 +- src/app/services/profile-service.ts | 2 +- src/app/types.ts | 6 +++--- src/app/utils/precompute.ts | 8 +------- 24 files changed, 68 insertions(+), 46 deletions(-) diff --git a/eslint.config.mjs b/eslint.config.mjs index aa94178c..481e88af 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -61,10 +61,15 @@ export default tseslint.config( '@typescript-eslint/no-unsafe-call': 'off', '@typescript-eslint/no-unsafe-return': 'off', '@typescript-eslint/no-unsafe-enum-comparison': 'off', - '@typescript-eslint/no-unnecessary-type-assertion': 'off', - '@typescript-eslint/no-redundant-type-constituents': 'off', + }, + }, + { + // Test files: `async` test callbacks and `act(async () => {})` wrappers are + // idiomatic even when they contain no `await` (async `act` flushes the + // microtask queue). Relaxing require-await here avoids churn in test infra. + files: ['**/*.spec.{ts,tsx}', '**/*.test.{ts,tsx}'], + rules: { '@typescript-eslint/require-await': 'off', - '@typescript-eslint/no-misused-promises': 'off', }, }, prettierRecommended, diff --git a/src/app/[locale]/account/notifications/AccountNotifications.tsx b/src/app/[locale]/account/notifications/AccountNotifications.tsx index 499a05c6..79dd909c 100644 --- a/src/app/[locale]/account/notifications/AccountNotifications.tsx +++ b/src/app/[locale]/account/notifications/AccountNotifications.tsx @@ -315,9 +315,7 @@ export default function AccountNotifications(): React.ReactElement { { - setFrequency( - e.target.value as NotificationSettings['frequency'], - ); + setFrequency(e.target.value); }} size='small' > diff --git a/src/app/screens/FeedSubmitted.tsx b/src/app/screens/FeedSubmitted.tsx index 6cfa7427..8e265c63 100644 --- a/src/app/screens/FeedSubmitted.tsx +++ b/src/app/screens/FeedSubmitted.tsx @@ -1,6 +1,7 @@ 'use client'; import { Typography, Box, Container, useTheme, Button } from '@mui/material'; +import Image from 'next/image'; export default function FeedSubmitted(): React.ReactElement { const theme = useTheme(); @@ -21,10 +22,13 @@ export default function FeedSubmitted(): React.ReactElement { 🚀 Your feed has been submitted! - rocket diff --git a/src/app/screens/GbfsValidator/GbfsFeedSearchInput.tsx b/src/app/screens/GbfsValidator/GbfsFeedSearchInput.tsx index 3fa621d3..cb821691 100644 --- a/src/app/screens/GbfsValidator/GbfsFeedSearchInput.tsx +++ b/src/app/screens/GbfsValidator/GbfsFeedSearchInput.tsx @@ -37,7 +37,7 @@ export default function GbfsFeedSearchInput({ initialFeedUrl ?? '', ); const [requiresAuth, setRequiresAuth] = useState(false); - const [authType, setAuthType] = useState(''); + const [authType, setAuthType] = useState(''); const [basicAuthUsername, setBasicAuthUsername] = useState< string | undefined >(undefined); @@ -65,7 +65,9 @@ export default function GbfsFeedSearchInput({ // Used to keep the auth inputs up to date useEffect(() => { setRequiresAuth(auth !== undefined); - setAuthType(auth == undefined ? '' : (auth.authType ?? '')); + setAuthType( + auth == undefined ? '' : ((auth.authType as AuthTypeEnum) ?? ''), + ); setBasicAuthUsername( auth != null && 'username' in auth ? auth.username : undefined, ); @@ -91,7 +93,7 @@ export default function GbfsFeedSearchInput({ }; const handleAuthTypeChange = (event: SelectChangeEvent): void => { - setAuthType(event.target.value); + setAuthType(event.target.value as AuthTypeEnum); setBasicAuthUsername(undefined); setBasicAuthPassword(undefined); setBearerAuthValue(undefined); diff --git a/src/app/screens/GbfsValidator/components/ErrorDetailsDialog.tsx b/src/app/screens/GbfsValidator/components/ErrorDetailsDialog.tsx index e045892e..de866a11 100644 --- a/src/app/screens/GbfsValidator/components/ErrorDetailsDialog.tsx +++ b/src/app/screens/GbfsValidator/components/ErrorDetailsDialog.tsx @@ -431,7 +431,7 @@ export function ErrorDetailsDialog({ )} {renderHighlightedObject( - parentContextData as JSONValue, + parentContextData, null, null, )} @@ -439,7 +439,7 @@ export function ErrorDetailsDialog({ ); } return renderHighlightedObject( - parentContextData as JSONValue, + parentContextData, lastPointerSegment ?? null, lastArrayIndex, ); diff --git a/src/app/services/api-auth-middleware.ts b/src/app/services/api-auth-middleware.ts index d83ba77b..1f30c393 100644 --- a/src/app/services/api-auth-middleware.ts +++ b/src/app/services/api-auth-middleware.ts @@ -25,7 +25,7 @@ export const generateAuthMiddlewareWithToken = ( userContextJwt?: string, ): Middleware => { return { - async onRequest(req) { + onRequest(req) { // Always attach the bearer token for IAP/GCIP. req.headers.set('Authorization', `Bearer ${accessToken}`); diff --git a/src/app/services/profile-service.ts b/src/app/services/profile-service.ts index 1835d51f..481c32b1 100644 --- a/src/app/services/profile-service.ts +++ b/src/app/services/profile-service.ts @@ -22,7 +22,7 @@ export const sendEmailVerification = async (): Promise => { /** * Return the current user or null if the user is not logged in. */ -export const getUserFromSession = async (): Promise => { +export const getUserFromSession = (): User | null => { const currentUser = app.auth().currentUser; if (currentUser === null) { return null; diff --git a/src/app/types.ts b/src/app/types.ts index 5c196f87..a6560598 100644 --- a/src/app/types.ts +++ b/src/app/types.ts @@ -78,19 +78,19 @@ export enum LicenseErrorSource { } export interface ProfileError { - code: string | 'unknown'; + code: string; message: string; source?: ProfileErrorSource; } export interface FeedError { - code: string | 'unknown'; + code: string; message: string; source?: FeedErrorSource; } export interface LicenseError { - code: string | 'unknown'; + code: string; message: string; source?: LicenseErrorSource; } diff --git a/src/app/utils/precompute.ts b/src/app/utils/precompute.ts index 62bce45e..83490aad 100644 --- a/src/app/utils/precompute.ts +++ b/src/app/utils/precompute.ts @@ -42,13 +42,7 @@ export interface PrecomputeDeps { /** Small helper: wait once for a map event */ async function once(map: maplibregl.Map, ev: string): Promise { - await new Promise( - // eslint-disable-next-line no-async-promise-executor - async (resolve) => - await map.once(ev, () => { - resolve(); - }), - ); + await map.once(ev); } // Extend helpers for [minLng,minLat,maxLng,maxLat] From 979a71eec8fe8a271513b26d15fce341e5098abb Mon Sep 17 00:00:00 2001 From: Alessandro Kreslin Date: Mon, 13 Jul 2026 09:50:47 -0400 Subject: [PATCH 2/5] eslint enable react-hooks/rules-of-hooks --- eslint.config.mjs | 3 -- .../GBFSFeedAnalytics/DetailPanel.tsx | 40 ++++++++--------- .../GBFSNoticeAnalytics.tsx | 2 +- .../GBFSVersionAnalytics.tsx | 2 +- .../GTFSFeatureAnalytics.tsx | 2 +- .../GTFSNoticeAnalytics.tsx | 2 +- .../Feed/components/AssociatedFeeds.tsx | 8 ++-- src/app/screens/Feeds/SearchTable.spec.tsx | 6 +-- src/app/screens/Feeds/SearchTable.tsx | 45 ++++++++++--------- 9 files changed, 55 insertions(+), 55 deletions(-) diff --git a/eslint.config.mjs b/eslint.config.mjs index 481e88af..af5b8b4c 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -41,9 +41,6 @@ export default tseslint.config( ignoreRestSiblings: true, }, ], - // TODO: hooks called inside render callbacks, incorrect hook usage patterns, - // and missing/extra effect dependencies — to be fixed in a separate ticket. - 'react-hooks/rules-of-hooks': 'off', 'react-hooks/refs': 'off', 'react-hooks/set-state-in-render': 'off', 'react-hooks/set-state-in-effect': 'off', diff --git a/src/app/[locale]/metrics/_components/Analytics/GBFSFeedAnalytics/DetailPanel.tsx b/src/app/[locale]/metrics/_components/Analytics/GBFSFeedAnalytics/DetailPanel.tsx index d04b36f1..82fe022f 100644 --- a/src/app/[locale]/metrics/_components/Analytics/GBFSFeedAnalytics/DetailPanel.tsx +++ b/src/app/[locale]/metrics/_components/Analytics/GBFSFeedAnalytics/DetailPanel.tsx @@ -32,26 +32,6 @@ const DetailPanel: React.FC = ({ row }) => { const theme = useTheme(); const { notices, metrics } = row.original; - if (metrics == null) { - return
No metrics available
; - } - - const chartData = metrics.computed_on.map((date, index) => { - const utcDate = new Date(date).toLocaleDateString('en-CA', { - timeZone: 'UTC', - }); // Converts the date to UTC - - return { - date: utcDate, - count: metrics.errors_count[index], - }; - }); - - const domain = [ - new Date(chartData[0]?.date ?? '').getTime(), - new Date().getTime(), - ]; - // Define the columns for the notices table const columns = useMemo>>( () => [ @@ -91,6 +71,26 @@ const DetailPanel: React.FC = ({ row }) => { muiTableContainerProps: { sx: { maxHeight: '50vh' } }, }); + if (metrics == null) { + return
No metrics available
; + } + + const chartData = metrics.computed_on.map((date, index) => { + const utcDate = new Date(date).toLocaleDateString('en-CA', { + timeZone: 'UTC', + }); // Converts the date to UTC + + return { + date: utcDate, + count: metrics.errors_count[index], + }; + }); + + const domain = [ + new Date(chartData[0]?.date ?? '').getTime(), + new Date().getTime(), + ]; + return ( diff --git a/src/app/[locale]/metrics/_components/Analytics/GBFSNoticeAnalytics/GBFSNoticeAnalytics.tsx b/src/app/[locale]/metrics/_components/Analytics/GBFSNoticeAnalytics/GBFSNoticeAnalytics.tsx index 1aefd028..f57f994d 100644 --- a/src/app/[locale]/metrics/_components/Analytics/GBFSNoticeAnalytics/GBFSNoticeAnalytics.tsx +++ b/src/app/[locale]/metrics/_components/Analytics/GBFSNoticeAnalytics/GBFSNoticeAnalytics.tsx @@ -32,6 +32,7 @@ export default function GBFSNoticeAnalytics(): React.ReactElement { const router = useRouter(); const searchParams = useSearchParams(); const noticeCode = searchParams.get('noticeCode'); + const theme = useTheme(); const [data, setData] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); @@ -133,7 +134,6 @@ export default function GBFSNoticeAnalytics(): React.ReactElement { enableStickyFooter: true, muiTableContainerProps: { sx: { maxHeight: '70vh' } }, renderDetailPanel: ({ row }) => { - const theme = useTheme(); const metrics = row.original; const chartData = metrics.computed_on.map((date, index) => ({ diff --git a/src/app/[locale]/metrics/_components/Analytics/GBFSVersionAnalytics/GBFSVersionAnalytics.tsx b/src/app/[locale]/metrics/_components/Analytics/GBFSVersionAnalytics/GBFSVersionAnalytics.tsx index 2ec10c29..17a208e0 100644 --- a/src/app/[locale]/metrics/_components/Analytics/GBFSVersionAnalytics/GBFSVersionAnalytics.tsx +++ b/src/app/[locale]/metrics/_components/Analytics/GBFSVersionAnalytics/GBFSVersionAnalytics.tsx @@ -39,6 +39,7 @@ import { GBFS_LINK } from '../../../../../constants/Navigation'; export default function GBFSVersionAnalytics(): React.ReactElement { const router = useRouter(); + const theme = useTheme(); const [data, setData] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); @@ -157,7 +158,6 @@ export default function GBFSVersionAnalytics(): React.ReactElement { enableStickyFooter: true, muiTableContainerProps: { sx: { maxHeight: '70vh' } }, renderDetailPanel: ({ row }) => { - const theme = useTheme(); const metrics = row.original; const chartData = metrics.computed_on.map((date, index) => ({ diff --git a/src/app/[locale]/metrics/_components/Analytics/GTFSFeatureAnalytics/GTFSFeatureAnalytics.tsx b/src/app/[locale]/metrics/_components/Analytics/GTFSFeatureAnalytics/GTFSFeatureAnalytics.tsx index 0e4260f3..b4525eb8 100644 --- a/src/app/[locale]/metrics/_components/Analytics/GTFSFeatureAnalytics/GTFSFeatureAnalytics.tsx +++ b/src/app/[locale]/metrics/_components/Analytics/GTFSFeatureAnalytics/GTFSFeatureAnalytics.tsx @@ -41,6 +41,7 @@ import { export default function GTFSFeatureAnalytics(): React.ReactElement { const router = useRouter(); + const theme = useTheme(); const searchParams = useSearchParams(); const featureName = searchParams.get('featureName'); const [data, setData] = useState([]); @@ -221,7 +222,6 @@ export default function GTFSFeatureAnalytics(): React.ReactElement { enableStickyFooter: true, muiTableContainerProps: { sx: { maxHeight: '70vh' } }, renderDetailPanel: ({ row }) => { - const theme = useTheme(); const metrics = row.original; const chartData = metrics.computed_on.map((date, index) => ({ diff --git a/src/app/[locale]/metrics/_components/Analytics/GTFSNoticeAnalytics/GTFSNoticeAnalytics.tsx b/src/app/[locale]/metrics/_components/Analytics/GTFSNoticeAnalytics/GTFSNoticeAnalytics.tsx index 5c003a8a..8019eeaf 100644 --- a/src/app/[locale]/metrics/_components/Analytics/GTFSNoticeAnalytics/GTFSNoticeAnalytics.tsx +++ b/src/app/[locale]/metrics/_components/Analytics/GTFSNoticeAnalytics/GTFSNoticeAnalytics.tsx @@ -39,6 +39,7 @@ import { useRemoteConfig } from '../../../../../context/RemoteConfigProvider'; export default function GTFSNoticeAnalytics(): React.ReactElement { const router = useRouter(); + const theme = useTheme(); const searchParams = useSearchParams(); const noticeCode = searchParams.get('noticeCode'); const [data, setData] = useState([]); @@ -193,7 +194,6 @@ export default function GTFSNoticeAnalytics(): React.ReactElement { enableStickyFooter: true, muiTableContainerProps: { sx: { maxHeight: '70vh' } }, renderDetailPanel: ({ row }) => { - const theme = useTheme(); const metrics = row.original; const chartData = metrics.computed_on.map((date, index) => ({ diff --git a/src/app/screens/Feed/components/AssociatedFeeds.tsx b/src/app/screens/Feed/components/AssociatedFeeds.tsx index 116220e5..8f5bf71b 100644 --- a/src/app/screens/Feed/components/AssociatedFeeds.tsx +++ b/src/app/screens/Feed/components/AssociatedFeeds.tsx @@ -25,8 +25,8 @@ export interface AssociatedFeedsProps { const renderAssociatedGTFSFeedRow = ( assocFeed: GTFSFeedType, + theme: ReturnType, ): React.ReactElement | undefined => { - const theme = useTheme(); if (assocFeed === undefined) { return undefined; } @@ -69,8 +69,8 @@ const renderAssociatedGTFSFeedRow = ( const renderAssociatedGTFSRTFeedRow = ( assocGTFSRTFeed: GTFSRTFeedType, + theme: ReturnType, ): React.ReactElement | undefined => { - const theme = useTheme(); if (assocGTFSRTFeed === undefined) { return undefined; } @@ -139,7 +139,7 @@ export default function AssociatedGTFSRTFeeds({ sx={{ display: 'inline-table', width: '100%' }} > {gtfsFeeds?.map((assocFeed) => - renderAssociatedGTFSFeedRow(assocFeed as GTFSFeedType), + renderAssociatedGTFSFeedRow(assocFeed as GTFSFeedType, theme), )} @@ -162,7 +162,7 @@ export default function AssociatedGTFSRTFeeds({ sx={{ display: 'inline-table', width: '100%' }} > {gtfsRtFeeds?.map((assocGTFSRTFeed) => - renderAssociatedGTFSRTFeedRow(assocGTFSRTFeed), + renderAssociatedGTFSRTFeedRow(assocGTFSRTFeed, theme), )} diff --git a/src/app/screens/Feeds/SearchTable.spec.tsx b/src/app/screens/Feeds/SearchTable.spec.tsx index 1ae29840..601e7a6b 100644 --- a/src/app/screens/Feeds/SearchTable.spec.tsx +++ b/src/app/screens/Feeds/SearchTable.spec.tsx @@ -1,4 +1,4 @@ -import SearchTable, { getDataTypeElement } from './SearchTable'; +import SearchTable, { DataTypeElement } from './SearchTable'; import { render, cleanup, screen, within } from '@testing-library/react'; import { type AllFeedsType } from '../../services/feeds/utils'; import { ThemeProvider } from '@mui/material/styles'; @@ -160,12 +160,12 @@ describe('getProviderElement', () => { }); it('should display the correct data type depending on the feed type', () => { - const { getByText } = render(getDataTypeElement('gtfs')); + const { getByText } = render(); expect(getByText('gtfsSchedule')).toBeInTheDocument(); }); it('should display the correct data type depending on the feed type', () => { - const { getByText } = render(getDataTypeElement('gtfs_rt')); + const { getByText } = render(); expect(getByText('gtfsRealtime')).toBeInTheDocument(); }); }); diff --git a/src/app/screens/Feeds/SearchTable.tsx b/src/app/screens/Feeds/SearchTable.tsx index ad5ddad7..d9472294 100644 --- a/src/app/screens/Feeds/SearchTable.tsx +++ b/src/app/screens/Feeds/SearchTable.tsx @@ -37,27 +37,30 @@ const HeaderTableCell = styled(TableCell)(() => ({ border: 'none', })); -export const getDataTypeElement = ( - dataType: 'gtfs' | 'gtfs_rt' | 'gbfs', -): React.ReactElement => { +const DataTypeHolder = ({ + children, +}: { + children: React.ReactNode; +}): React.ReactElement => { + return ( + + {children} + + ); +}; + +export const DataTypeElement = ({ + dataType, +}: { + dataType: 'gtfs' | 'gtfs_rt' | 'gbfs'; +}): React.ReactElement => { const tCommon = useTranslations('common'); - const DataTypeHolder = ({ - children, - }: { - children: React.ReactNode; - }): React.ReactElement => { - return ( - - {children} - - ); - }; if (dataType === 'gtfs') { return {tCommon('gtfsSchedule')}; } else if (dataType === 'gtfs_rt') { @@ -268,7 +271,7 @@ export default function SearchTable({ - {getDataTypeElement(feed.data_type)} + {feed.data_type === 'gtfs_rt' && ( Date: Mon, 13 Jul 2026 11:32:21 -0400 Subject: [PATCH 3/5] eslint react-hooks/refs and react-hooks/set-state-in-render --- eslint.config.mjs | 2 -- src/app/[locale]/account/AccountGeneral.tsx | 16 ++++++++-------- .../GBFSFeedAnalytics/GBFSFeedAnalytics.tsx | 4 ++-- src/app/components/GtfsVisualizationMap.tsx | 1 - src/app/components/Map/ScanningOverlay.tsx | 18 ++++++++---------- src/app/utils/precompute.ts | 2 +- 6 files changed, 19 insertions(+), 24 deletions(-) diff --git a/eslint.config.mjs b/eslint.config.mjs index af5b8b4c..afc9fd28 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -41,8 +41,6 @@ export default tseslint.config( ignoreRestSiblings: true, }, ], - 'react-hooks/refs': 'off', - 'react-hooks/set-state-in-render': 'off', 'react-hooks/set-state-in-effect': 'off', 'react-hooks/immutability': 'off', 'react-hooks/exhaustive-deps': 'off', diff --git a/src/app/[locale]/account/AccountGeneral.tsx b/src/app/[locale]/account/AccountGeneral.tsx index ea469f56..1d70c994 100644 --- a/src/app/[locale]/account/AccountGeneral.tsx +++ b/src/app/[locale]/account/AccountGeneral.tsx @@ -42,6 +42,9 @@ export default function AccountGeneral(): React.ReactElement { draftIsRegisteredToReceiveAPIAnnouncements, setDraftIsRegisteredToReceiveAPIAnnouncements, ] = React.useState(false); + const [alertSeverity, setAlertSeverity] = React.useState<'success' | 'error'>( + 'success', + ); const handleEditClick = (): void => { setDraftFullName(user?.fullName ?? ''); @@ -76,14 +79,13 @@ export default function AccountGeneral(): React.ReactElement { React.useEffect(() => { if (saveStatus === 'success') { setIsEditing(false); + setAlertSeverity('success'); + } else if (saveStatus === 'fail') { + setAlertSeverity('error'); } }, [saveStatus]); - // Reference is due to dispatch save status acting faster than the exit animation of the alert, causing a flash of the wrong alert severity. With this reference, the severity will be consistent during the whole display of the alert. const isSaving = saveStatus === 'loading'; - const alertSeverity = React.useRef<'success' | 'error'>('success'); - if (saveStatus === 'success') alertSeverity.current = 'success'; - if (saveStatus === 'fail') alertSeverity.current = 'error'; return ( <> @@ -96,15 +98,13 @@ export default function AccountGeneral(): React.ReactElement { anchorOrigin={{ vertical: 'top', horizontal: 'center' }} > { dispatch(saveUserProfileReset()); }} sx={{ width: '100%' }} > - {alertSeverity.current === 'success' - ? t('saveSuccess') - : t('saveError')} + {alertSeverity === 'success' ? t('saveSuccess') : t('saveError')} { + useEffect(() => { if ( schemaPathInitFilter != null && schemaPathFilterOptions.includes(schemaPathInitFilter) diff --git a/src/app/components/GtfsVisualizationMap.tsx b/src/app/components/GtfsVisualizationMap.tsx index d9f0ac45..a9edf09d 100644 --- a/src/app/components/GtfsVisualizationMap.tsx +++ b/src/app/components/GtfsVisualizationMap.tsx @@ -532,7 +532,6 @@ export const GtfsVisualizationMap = ({ scannedTiles={scannedTiles} scanRowsCols={scanRowsCols} handleCancelScan={handleCancelScan} - cancelRequestRef={cancelRequestRef} /> )} diff --git a/src/app/components/Map/ScanningOverlay.tsx b/src/app/components/Map/ScanningOverlay.tsx index 371d2ae6..09947b46 100644 --- a/src/app/components/Map/ScanningOverlay.tsx +++ b/src/app/components/Map/ScanningOverlay.tsx @@ -1,3 +1,4 @@ +import { useState } from 'react'; import { Box, Button, @@ -16,19 +17,13 @@ interface ScanningOverlayProps { cols: number; } | null; handleCancelScan: () => void; - cancelRequestRef: React.MutableRefObject; } export const ScanningOverlay = ( props: React.PropsWithChildren, ): React.ReactElement => { - const { - totalTiles, - scannedTiles, - scanRowsCols, - handleCancelScan, - cancelRequestRef, - } = props; + const { totalTiles, scannedTiles, scanRowsCols, handleCancelScan } = props; + const [cancelClicked, setCancelClicked] = useState(false); const theme = useTheme(); const t = useTranslations('feeds'); const progressPct = @@ -121,8 +116,11 @@ export const ScanningOverlay = (