Skip to content

Commit d018f1e

Browse files
committed
Feed status added to search
1 parent 5ec7d53 commit d018f1e

5 files changed

Lines changed: 285 additions & 9 deletions

File tree

web-app/src/app/screens/Feeds/AdvancedSearchTable.tsx

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -194,11 +194,12 @@ export default function AdvancedSearchTable({
194194
{feed.official === true && (
195195
<OfficialChip isLongDisplay={false}></OfficialChip>
196196
)}
197-
{feed.data_type !== 'gbfs' && (
198-
<FeedStatusIndicator
199-
status={feed.status}
200-
></FeedStatusIndicator>
201-
)}
197+
{feed.data_type !== 'gbfs' &&
198+
feed.data_type !== 'gtfs_rt' && (
199+
<FeedStatusIndicator
200+
status={feed.status}
201+
></FeedStatusIndicator>
202+
)}
202203
</Box>
203204

204205
<Box

web-app/src/app/screens/Feeds/SearchFilters.tsx

Lines changed: 93 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { useEffect, useState } from 'react';
99
import { DATASET_FEATURES, groupFeaturesByComponent } from '../../utils/consts';
1010
import { type GbfsVersionConfig } from '../../interface/RemoteConfig';
1111
import { SearchHeader } from '../../styles/Filters.styles';
12+
import { type AllowedFeedSearchStatus } from './utility';
1213

1314
function setInitialExpandGroup(): Record<string, boolean> {
1415
const expandGroup: Record<string, boolean> = {};
@@ -24,27 +25,33 @@ interface SearchFiltersProps {
2425
selectedFeedTypes: Record<string, boolean>;
2526
isOfficialFeedSearch: boolean;
2627
selectedFeatures: string[];
28+
selectedStatuses: AllowedFeedSearchStatus[];
2729
selectedGbfsVersions: string[];
2830
setSelectedFeedTypes: (selectedFeedTypes: Record<string, boolean>) => void;
2931
setIsOfficialFeedSearch: (isOfficialFeedSearch: boolean) => void;
3032
setSelectedFeatures: (selectedFeatures: string[]) => void;
33+
setSelectedStatuses: (selectedStatuses: AllowedFeedSearchStatus[]) => void;
3134
setSelectedGbfsVerions: (selectedVersions: string[]) => void;
3235
isOfficialTagFilterEnabled: boolean;
3336
areFeatureFiltersEnabled: boolean;
37+
areStatusFiltersEnabled: boolean;
3438
areGBFSFiltersEnabled: boolean;
3539
}
3640

3741
export function SearchFilters({
3842
selectedFeedTypes,
3943
isOfficialFeedSearch,
4044
selectedFeatures,
45+
selectedStatuses,
4146
selectedGbfsVersions,
4247
setSelectedFeedTypes,
4348
setIsOfficialFeedSearch,
4449
setSelectedFeatures,
50+
setSelectedStatuses,
4551
setSelectedGbfsVerions,
4652
isOfficialTagFilterEnabled,
4753
areFeatureFiltersEnabled,
54+
areStatusFiltersEnabled,
4855
areGBFSFiltersEnabled,
4956
}: SearchFiltersProps): React.ReactElement {
5057
const { t } = useTranslation('feeds');
@@ -57,6 +64,7 @@ export function SearchFilters({
5764
>({
5865
features: areFeatureFiltersEnabled,
5966
tags: isOfficialTagFilterEnabled,
67+
status: areStatusFiltersEnabled,
6068
gbfsVersions: true,
6169
});
6270
const [featureCheckboxData, setFeatureCheckboxData] = useState<
@@ -164,10 +172,94 @@ export function SearchFilters({
164172
</>
165173
)}
166174

175+
<Accordion
176+
disableGutters
177+
sx={{
178+
border: 0,
179+
'&::before': {
180+
display: 'none',
181+
},
182+
}}
183+
variant={'outlined'}
184+
expanded={expandedCategories.status && areStatusFiltersEnabled}
185+
onChange={() => {
186+
setExpandedCategories({
187+
...expandedCategories,
188+
status: !expandedCategories.status,
189+
});
190+
}}
191+
>
192+
<AccordionSummary
193+
expandIcon={<ExpandMoreIcon />}
194+
aria-controls='panel-status-content'
195+
sx={{ px: 0 }}
196+
>
197+
<SearchHeader
198+
variant='h6'
199+
sx={areStatusFiltersEnabled ? {} : { opacity: 0.5 }}
200+
>
201+
Status
202+
</SearchHeader>
203+
</AccordionSummary>
204+
<AccordionDetails
205+
sx={{
206+
p: 0,
207+
m: 0,
208+
border: 0,
209+
'&.Mui-expanded': { m: 0, minHeight: 'initial' },
210+
}}
211+
>
212+
<NestedCheckboxList
213+
disableAll={!areStatusFiltersEnabled}
214+
debounceTime={300}
215+
checkboxData={[
216+
{
217+
title: t('feedStatus.active.label'),
218+
checked: selectedStatuses.includes('active'),
219+
type: 'checkbox',
220+
props: { key: 'active' },
221+
},
222+
{
223+
title: t('feedStatus.inactive.label'),
224+
checked: selectedStatuses.includes('inactive'),
225+
type: 'checkbox',
226+
props: { key: 'inactive' },
227+
},
228+
{
229+
title: t('feedStatus.future.label'),
230+
checked: selectedStatuses.includes('future'),
231+
type: 'checkbox',
232+
props: { key: 'future' },
233+
},
234+
]}
235+
onCheckboxChange={(checkboxData) => {
236+
const statuses: AllowedFeedSearchStatus[] = [];
237+
checkboxData.forEach((cb) => {
238+
if (cb.checked) {
239+
if (
240+
cb.props?.key === 'active' ||
241+
cb.props?.key === 'inactive' ||
242+
cb.props?.key === 'future'
243+
) {
244+
statuses.push(cb.props.key);
245+
}
246+
}
247+
});
248+
setSelectedStatuses(statuses);
249+
}}
250+
/>
251+
</AccordionDetails>
252+
</Accordion>
253+
167254
{config.enableFeatureFilterSearch && (
168255
<Accordion
169256
disableGutters
170-
sx={{ border: 0 }}
257+
sx={{
258+
border: 0,
259+
'&::before': {
260+
display: 'none',
261+
},
262+
}}
171263
variant={'outlined'}
172264
expanded={expandedCategories.features && areFeatureFiltersEnabled}
173265
onChange={() => {

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

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,10 @@ import { useSearchParams } from 'react-router-dom';
3030
import SearchTable from './SearchTable';
3131
import { Trans, useTranslation } from 'react-i18next';
3232
import {
33+
type AllowedFeedSearchStatus,
3334
getDataTypeParamFromSelectedFeedTypes,
3435
getInitialSelectedFeedTypes,
36+
parseQueryParamStatus,
3537
} from './utility';
3638
import {
3739
chipHolderStyles,
@@ -65,6 +67,9 @@ export default function Feed(): React.ReactElement {
6567
const [selectedFeatures, setSelectedFeatures] = useState<string[]>(
6668
searchParams.get('features')?.split(',') ?? [],
6769
);
70+
const [selectedStatuses, setSelectedStatuses] = useState<
71+
AllowedFeedSearchStatus[]
72+
>(parseQueryParamStatus(searchParams.get('status')?.split(',')));
6873
const [selectGbfsVersions, setSelectGbfsVersions] = useState<string[]>(
6974
searchParams.get('gbfs_versions')?.split(',') ?? [],
7075
);
@@ -94,6 +99,9 @@ export default function Feed(): React.ReactElement {
9499
const areFeatureFiltersEnabled =
95100
(!selectedFeedTypes.gtfs_rt && !selectedFeedTypes.gbfs) ||
96101
selectedFeedTypes.gtfs;
102+
const areStatusFiltersEnabled =
103+
(!selectedFeedTypes.gtfs_rt && !selectedFeedTypes.gbfs) ||
104+
selectedFeedTypes.gtfs;
97105
const areGBFSFiltersEnabled =
98106
selectedFeedTypes.gbfs &&
99107
!selectedFeedTypes.gtfs_rt &&
@@ -125,9 +133,10 @@ export default function Feed(): React.ReactElement {
125133
is_official: isOfficialTagFilterEnabled
126134
? isOfficialFeedSearch || undefined
127135
: undefined,
128-
// Fixed status values for now, until a status filter is implemented
129-
// Filtering out deprecated feeds
130-
status: ['active', 'inactive', 'development', 'future'],
136+
status:
137+
areStatusFiltersEnabled && selectedStatuses.length > 0
138+
? selectedStatuses
139+
: ['active', 'inactive', 'development', 'future'],
131140
feature: areFeatureFiltersEnabled ? selectedFeatures : undefined,
132141
version: areGBFSFiltersEnabled
133142
? selectGbfsVersions.join(',').replaceAll('v', '')
@@ -144,6 +153,7 @@ export default function Feed(): React.ReactElement {
144153
searchLimit,
145154
isOfficialFeedSearch,
146155
selectedFeatures,
156+
selectedStatuses,
147157
selectGbfsVersions,
148158
]);
149159

@@ -168,6 +178,9 @@ export default function Feed(): React.ReactElement {
168178
if (selectedFeatures.length > 0) {
169179
newSearchParams.set('features', selectedFeatures.join(','));
170180
}
181+
if (selectedStatuses.length > 0) {
182+
newSearchParams.set('status', selectedStatuses.join(','));
183+
}
171184
if (selectGbfsVersions.length > 0) {
172185
newSearchParams.set('gbfs_versions', selectGbfsVersions.join(','));
173186
}
@@ -185,6 +198,7 @@ export default function Feed(): React.ReactElement {
185198
activePagination,
186199
selectedFeedTypes,
187200
selectedFeatures,
201+
selectedStatuses,
188202
selectGbfsVersions,
189203
isOfficialFeedSearch,
190204
]);
@@ -208,6 +222,12 @@ export default function Feed(): React.ReactElement {
208222
setSelectedFeatures([...newFeatures]);
209223
}
210224

225+
const newStatusesRaw = searchParams.get('status')?.split(',') ?? [];
226+
const newStatuses = parseQueryParamStatus(newStatusesRaw);
227+
if (newStatuses.join(',') !== selectedStatuses.join(',')) {
228+
setSelectedStatuses([...newStatuses]);
229+
}
230+
211231
const newGbfsVersions = searchParams.get('gbfs_versions')?.split(',') ?? [];
212232
if (newGbfsVersions.join(',') !== selectGbfsVersions.join(',')) {
213233
setSelectGbfsVersions([...newGbfsVersions]);
@@ -263,6 +283,7 @@ export default function Feed(): React.ReactElement {
263283
gbfs: false,
264284
});
265285
setSelectedFeatures([]);
286+
setSelectedStatuses([]);
266287
setSelectGbfsVersions([]);
267288
setIsOfficialFeedSearch(false);
268289
}
@@ -400,6 +421,7 @@ export default function Feed(): React.ReactElement {
400421
selectedFeedTypes={selectedFeedTypes}
401422
isOfficialFeedSearch={isOfficialFeedSearch}
402423
selectedFeatures={selectedFeatures}
424+
selectedStatuses={selectedStatuses}
403425
selectedGbfsVersions={selectGbfsVersions}
404426
setSelectedFeedTypes={(feedTypes) => {
405427
setActivePagination(1);
@@ -413,12 +435,17 @@ export default function Feed(): React.ReactElement {
413435
setActivePagination(1);
414436
setSelectedFeatures(features);
415437
}}
438+
setSelectedStatuses={(statuses) => {
439+
setActivePagination(1);
440+
setSelectedStatuses(statuses);
441+
}}
416442
setSelectedGbfsVerions={(versions) => {
417443
setSelectGbfsVersions(versions);
418444
setActivePagination(1);
419445
}}
420446
isOfficialTagFilterEnabled={isOfficialTagFilterEnabled}
421447
areFeatureFiltersEnabled={areFeatureFiltersEnabled}
448+
areStatusFiltersEnabled={areStatusFiltersEnabled}
422449
areGBFSFiltersEnabled={areGBFSFiltersEnabled}
423450
></SearchFilters>
424451
</Grid>
@@ -498,6 +525,22 @@ export default function Feed(): React.ReactElement {
498525
/>
499526
))}
500527

528+
{areStatusFiltersEnabled &&
529+
selectedStatuses.map((status) => (
530+
<Chip
531+
color='primary'
532+
variant='outlined'
533+
size='small'
534+
label={t('feedStatus.' + status + '.label')}
535+
key={status}
536+
onDelete={() => {
537+
setSelectedStatuses([
538+
...selectedStatuses.filter((s) => s !== status),
539+
]);
540+
}}
541+
/>
542+
))}
543+
501544
{areGBFSFiltersEnabled &&
502545
selectGbfsVersions.map((gbfsVersion) => (
503546
<Chip
@@ -517,6 +560,7 @@ export default function Feed(): React.ReactElement {
517560
))}
518561

519562
{(selectedFeatures.length > 0 ||
563+
selectedStatuses.length > 0 ||
520564
selectGbfsVersions.length > 0 ||
521565
isOfficialFeedSearch ||
522566
selectedFeedTypes.gtfs_rt ||

0 commit comments

Comments
 (0)