Skip to content

Commit adbe02c

Browse files
committed
add covered area feature flag
1 parent e71d041 commit adbe02c

7 files changed

Lines changed: 74 additions & 42 deletions

File tree

web-app/public/locales/en/feeds.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@
7676
"gtfsVisualizationTooltip": "View the routes and stops of the feed",
7777
"detailedCoveredAreaView": "Detailed",
7878
"detailedCoveredAreaViewTooltip": "View the detailed covered area of the feed",
79-
"unableToGenerateBoundingBox": "Unable to generate bounding box from the feed's stops.txt file.",
79+
"unableToGenerateBoundingBox": "Unable to generate bounding box from the feed",
8080
"unableToGetGbfsMap": "Error fetching GBFS Map",
8181
"areYouOfficialProducer": "Are you the official producer or transit agency responsible for this data ?",
8282
"isOfficialSource": "Is this an official data source?",

web-app/src/app/components/CoveredAreaMap.tsx

Lines changed: 48 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,7 @@ const CoveredAreaMap: React.FC<CoveredAreaMapProps> = ({
7979
const [geoJsonError, setGeoJsonError] = useState(false);
8080
const [geoJsonLoading, setGeoJsonLoading] = useState(false);
8181
const [view, setView] = useState<MapViews>(
82-
feed?.data_type === 'gtfs'
83-
? 'gtfsVisualizationView'
84-
: 'detailedCoveredAreaView',
82+
feed?.data_type === 'gtfs' ? 'gtfsVisualizationView' : 'boundingBoxView',
8583
);
8684

8785
const latestGbfsVersion = useSelector(selectLatestGbfsVersion);
@@ -131,18 +129,30 @@ const CoveredAreaMap: React.FC<CoveredAreaMapProps> = ({
131129
// effect to determine which view to display
132130
useEffect(() => {
133131
if (feed == undefined) return;
134-
if (feed?.data_type === 'gbfs') return; // use default for gbfs
132+
if (feed?.data_type === 'gbfs') {
133+
setView(
134+
config.enableDetailedCoveredArea
135+
? 'detailedCoveredAreaView'
136+
: 'boundingBoxView',
137+
);
138+
return;
139+
}
135140

136141
// for gtfs feeds
137142
if (
143+
feed?.data_type === 'gtfs' &&
138144
config.enableGtfsVisualizationMap &&
139145
routesJsonLoadingStatus != 'failed' &&
140146
boundingBox != undefined
141147
) {
142148
setView('gtfsVisualizationView');
143149
return;
144150
}
145-
if (geoJsonData != null && boundingBox != undefined) {
151+
if (
152+
config.enableDetailedCoveredArea &&
153+
geoJsonData != null &&
154+
boundingBox != undefined
155+
) {
146156
setView('detailedCoveredAreaView');
147157
return;
148158
}
@@ -176,22 +186,13 @@ const CoveredAreaMap: React.FC<CoveredAreaMapProps> = ({
176186

177187
const renderMap = (): JSX.Element => {
178188
const displayBoundingBoxMap =
179-
view === 'boundingBoxView' && feed?.data_type === 'gtfs';
189+
view === 'boundingBoxView' &&
190+
(feed?.data_type === 'gtfs' ||
191+
(feed?.data_type === 'gbfs' && boundingBox != null));
180192

181193
const displayGtfsVisualizationView =
182194
view === 'gtfsVisualizationView' && feed?.data_type === 'gtfs';
183195

184-
let gbfsBoundingBox: LatLngExpression[] = [];
185-
if (feed?.data_type === 'gbfs') {
186-
if (geoJsonData == null) {
187-
return <></>;
188-
}
189-
gbfsBoundingBox = computeBoundingBox(geoJsonData) ?? [];
190-
if (gbfsBoundingBox.length === 0) {
191-
setGeoJsonError(true);
192-
}
193-
}
194-
195196
if (displayBoundingBoxMap) {
196197
return <Map polygon={boundingBox ?? []} />;
197198
}
@@ -218,11 +219,20 @@ const CoveredAreaMap: React.FC<CoveredAreaMapProps> = ({
218219
</>
219220
);
220221
}
221-
if (geoJsonData != null) {
222+
if (config.enableDetailedCoveredArea && geoJsonData != null) {
223+
let gbfsGeoJsonBoundingBox: LatLngExpression[] = [];
224+
if (feed?.data_type === 'gbfs') {
225+
gbfsGeoJsonBoundingBox = computeBoundingBox(geoJsonData) ?? [];
226+
if (gbfsGeoJsonBoundingBox.length === 0) {
227+
setGeoJsonError(true);
228+
}
229+
}
230+
const feedBoundingBox: LatLngExpression[] =
231+
feed?.data_type === 'gtfs' ? boundingBox ?? [] : gbfsGeoJsonBoundingBox;
222232
return (
223233
<MapGeoJSON
224234
geoJSONData={geoJsonData}
225-
polygon={boundingBox ?? gbfsBoundingBox}
235+
polygon={feedBoundingBox}
226236
displayMapDetails={feed?.data_type === 'gtfs'}
227237
/>
228238
);
@@ -327,17 +337,19 @@ const CoveredAreaMap: React.FC<CoveredAreaMapProps> = ({
327337
</ToggleButton>
328338
</Tooltip>
329339
)}
330-
<Tooltip title={t('detailedCoveredAreaViewTooltip')}>
331-
<ToggleButton
332-
value='detailedCoveredAreaView'
333-
disabled={
334-
geoJsonLoading || geoJsonError || boundingBox === undefined
335-
}
336-
aria-label='Detailed Covered Area View'
337-
>
338-
<TravelExploreIcon />
339-
</ToggleButton>
340-
</Tooltip>
340+
{config.enableDetailedCoveredArea && (
341+
<Tooltip title={t('detailedCoveredAreaViewTooltip')}>
342+
<ToggleButton
343+
value='detailedCoveredAreaView'
344+
disabled={
345+
geoJsonLoading || geoJsonError || boundingBox === undefined
346+
}
347+
aria-label='Detailed Covered Area View'
348+
>
349+
<TravelExploreIcon />
350+
</ToggleButton>
351+
</Tooltip>
352+
)}
341353
<Tooltip title={t('boundingBoxViewTooltip')}>
342354
<ToggleButton
343355
value='boundingBoxView'
@@ -349,17 +361,19 @@ const CoveredAreaMap: React.FC<CoveredAreaMapProps> = ({
349361
</ToggleButtonGroup>
350362
)}
351363
</Box>
352-
{feed?.data_type === 'gtfs' &&
364+
{(feed?.data_type === 'gtfs' || feed?.data_type === 'gbfs') &&
353365
boundingBox === undefined &&
354366
view === 'boundingBoxView' && (
355367
<WarningContentBox>
356368
{t('unableToGenerateBoundingBox')}
357369
</WarningContentBox>
358370
)}
359371

360-
{feed?.data_type === 'gbfs' && geoJsonError && (
361-
<WarningContentBox>{t('unableToGetGbfsMap')}</WarningContentBox>
362-
)}
372+
{config.enableDetailedCoveredArea &&
373+
feed?.data_type === 'gbfs' &&
374+
geoJsonError && (
375+
<WarningContentBox>{t('unableToGetGbfsMap')}</WarningContentBox>
376+
)}
363377

364378
{(boundingBox != undefined || !geoJsonError) && (
365379
<Box sx={mapBoxPositionStyle}>

web-app/src/app/interface/RemoteConfig.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,11 @@ export interface RemoteConfigValues extends FirebaseDefaultConfig {
4040
/** Max number of data stuff to display on top of the map to avoid overflow */
4141
visualizationMapPreviewDataLimit: number;
4242
visualizationMapFullDataLimit: number;
43+
44+
// This feature flag enable or the coovered area component with expected behavior:
45+
// 1- hides/shows the toggle button for gtfs feeds
46+
// 2- use bounding box view for GBFS instead of full covered area map
47+
enableDetailedCoveredArea: boolean;
4348
}
4449

4550
const featureByPassDefault: BypassConfig = {
@@ -68,6 +73,7 @@ export const defaultRemoteConfigValues: RemoteConfigValues = {
6873
enableGtfsVisualizationMap: false,
6974
visualizationMapFullDataLimit: 5,
7075
visualizationMapPreviewDataLimit: 3,
76+
enableDetailedCoveredArea: false,
7177
};
7278

7379
remoteConfig.defaultConfig = defaultRemoteConfigValues;

web-app/src/app/screens/Feed/components/FullMapView.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ import {
3636
selectGtfsDatasetRoutesJson,
3737
selectGtfsDatasetRoutesLoadingStatus,
3838
selectGtfsDatasetRouteTypes,
39-
selectGtfsFeedBoundingBox,
39+
selectFeedBoundingBox,
4040
selectIsAnonymous,
4141
selectIsAuthenticated,
4242
selectUserProfile,
@@ -78,7 +78,7 @@ export default function FullMapView(): React.ReactElement {
7878
hosted_url: gtfsFeed?.latest_dataset?.hosted_url,
7979
id: gtfsFeed?.latest_dataset?.id,
8080
};
81-
const boundingBox = useSelector(selectGtfsFeedBoundingBox);
81+
const boundingBox = useSelector(selectFeedBoundingBox);
8282
const routes = useSelector(selectGtfsDatasetRoutesJson);
8383
const routeTypes = useSelector(selectGtfsDatasetRouteTypes);
8484

web-app/src/app/screens/Feed/index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import {
2727
selectRelatedFeedsData,
2828
selectRelatedGtfsRTFeedsData,
2929
selectAutoDiscoveryUrl,
30-
selectGtfsFeedBoundingBox,
30+
selectFeedBoundingBox,
3131
} from '../../store/feed-selectors';
3232
import { clearDataset, loadingDataset } from '../../store/dataset-reducer';
3333
import {
@@ -156,7 +156,7 @@ export default function Feed(): React.ReactElement {
156156
const datasets = useSelector(selectDatasetsData);
157157
const hasLoadedAllDatasets = useSelector(selectHasLoadedAllDatasets);
158158
const latestDataset = useSelector(selectLatestDatasetsData);
159-
const boundingBox = useSelector(selectGtfsFeedBoundingBox);
159+
const boundingBox = useSelector(selectFeedBoundingBox);
160160
const feed = useSelector(selectFeedData);
161161
const gbfsAutodiscoveryUrl = useSelector(selectAutoDiscoveryUrl);
162162
const needsToLoadFeed = feed === undefined || feed?.id !== feedId;

web-app/src/app/services/feeds/types.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,13 @@ export interface components {
227227
provider_url?: string;
228228
/** @description A list of GBFS versions that the feed supports. Each version is represented by its version number and a list of endpoints. */
229229
versions?: Array<components['schemas']['GbfsVersion']>;
230+
bounding_box?: components['schemas']['BoundingBox'];
231+
/**
232+
* Format: date-time
233+
* @description The date and time the bounding box was generated, in ISO 8601 date-time format.
234+
* @example "2023-07-10T22:06:00.000Z"
235+
*/
236+
bounding_box_generated_at?: string;
230237
};
231238
GbfsVersion: {
232239
/**

web-app/src/app/store/feed-selectors.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -98,13 +98,18 @@ export const selectRelatedGtfsRTFeedsData = (
9898
return state.feedProfile.relatedFeedsData.gtfsRt;
9999
};
100100

101-
export const selectGtfsFeedBoundingBox = (
101+
export const selectFeedBoundingBox = (
102102
state: RootState,
103103
): LatLngExpression[] | undefined => {
104-
if (!isGtfsFeedType(state.feedProfile.data)) {
104+
if (
105+
!(
106+
isGtfsFeedType(state.feedProfile.data) ||
107+
isGbfsFeedType(state.feedProfile.data)
108+
)
109+
) {
105110
return undefined;
106111
}
107-
const feed = state.feedProfile.data as GTFSFeedType;
112+
const feed = state.feedProfile.data;
108113

109114
if (
110115
feed?.bounding_box?.maximum_latitude == undefined ||

0 commit comments

Comments
 (0)