Skip to content

Commit

Permalink
fix(openchallenges): improve query parameter management using locatio…
Browse files Browse the repository at this point in the history
…n service (#2273)

* enable to filter status using location service

* refactor checkbox filters

* enable search terms

* enable filters that are using searchterms

* enable sorter

* refactor filter types in preparation of accepting multiple params change at the same time

* enable paginator filter

* refactor date filter

* move some codes to data service

* refactor org search page

* remove empty param

* fix params when unselected

* enable scroll restoration

* fix query for contributionRoles

* update client

* replace the string value by its enum value

* fix error from updating client (challengeSort)
  • Loading branch information
rrchai authored Oct 27, 2023
1 parent 9f1639c commit a3716c1
Show file tree
Hide file tree
Showing 24 changed files with 689 additions and 792 deletions.
2 changes: 1 addition & 1 deletion apps/openchallenges/app/src/app/app.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export const appConfig: ApplicationConfig = {
routes,
withEnabledBlockingInitialNavigation(),
withInMemoryScrolling({
// scrollPositionRestoration: 'top',
scrollPositionRestoration: 'enabled',
})
),
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,13 @@
/**
* The category of the challenge.
*/
export type ChallengeCategory = 'featured';
export type ChallengeCategory = 'featured' | 'starting_soon' | 'ending_soon' | 'recently_started' | 'recently_ended';

export const ChallengeCategory = {
Featured: 'featured' as ChallengeCategory
Featured: 'featured' as ChallengeCategory,
StartingSoon: 'starting_soon' as ChallengeCategory,
EndingSoon: 'ending_soon' as ChallengeCategory,
RecentlyStarted: 'recently_started' as ChallengeCategory,
RecentlyEnded: 'recently_ended' as ChallengeCategory
};

Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,14 @@
/**
* What to sort results by.
*/
export type ChallengeSort = 'created' | 'ending_soon' | 'random' | 'recently_ended' | 'recently_started' | 'relevance' | 'starred' | 'starting_soon';
export type ChallengeSort = 'created' | 'random' | 'relevance' | 'starred' | 'start_date' | 'end_date';

export const ChallengeSort = {
Created: 'created' as ChallengeSort,
EndingSoon: 'ending_soon' as ChallengeSort,
Random: 'random' as ChallengeSort,
RecentlyEnded: 'recently_ended' as ChallengeSort,
RecentlyStarted: 'recently_started' as ChallengeSort,
Relevance: 'relevance' as ChallengeSort,
Starred: 'starred' as ChallengeSort,
StartingSoon: 'starting_soon' as ChallengeSort
StartDate: 'start_date' as ChallengeSort,
EndDate: 'end_date' as ChallengeSort
};

Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import { Injectable } from '@angular/core';
import { BehaviorSubject, forkJoin, iif, Observable, of } from 'rxjs';
import {
catchError,
debounceTime,
distinctUntilChanged,
map,
switchMap,
} from 'rxjs/operators';
import {
ChallengePlatformSearchQuery,
ChallengePlatformService,
ChallengePlatformSort,
Image,
ImageAspectRatio,
ImageHeight,
ImageQuery,
ImageService,
Organization,
OrganizationSearchQuery,
OrganizationService,
OrganizationSort,
} from '@sagebionetworks/openchallenges/api-client-angular';
import { forkJoinConcurrent } from '@sagebionetworks/openchallenges/util';
import { Filter } from '@sagebionetworks/openchallenges/ui';

@Injectable({
providedIn: 'root',
})
export class ChallengeSearchDataService {
private platformSearchTerms: BehaviorSubject<string> =
new BehaviorSubject<string>('');

private organizationSearchTerms: BehaviorSubject<string> =
new BehaviorSubject<string>('');

constructor(
private challengePlatformService: ChallengePlatformService,
private organizationService: OrganizationService,
private imageService: ImageService
) {}

setPlatformSearchTerms(searchTerms: string) {
this.platformSearchTerms.next(searchTerms);
}

setOriganizationSearchTerms(searchTerms: string) {
this.organizationSearchTerms.next(searchTerms);
}

searchPlatforms(): Observable<Filter[]> {
return this.platformSearchTerms.pipe(
debounceTime(400),
distinctUntilChanged(),
switchMap((searchTerm: string) => {
const sortedBy: ChallengePlatformSort = 'name';
const platformQuery: ChallengePlatformSearchQuery = {
searchTerms: searchTerm,
sort: sortedBy,
};
return this.challengePlatformService.listChallengePlatforms(
platformQuery
);
}),
map((page) =>
page.challengePlatforms.map((platform) => ({
value: platform.slug,
label: platform.name,
active: false,
}))
)
);
}

searchOriganizations(): Observable<Filter[]> {
return this.organizationSearchTerms.pipe(
debounceTime(400),
distinctUntilChanged(),
switchMap((searchTerm: string) => {
const sortBy: OrganizationSort = 'name';
const orgQuery: OrganizationSearchQuery = {
searchTerms: searchTerm,
sort: sortBy,
};
return this.organizationService.listOrganizations(orgQuery);
}),
map((page) => page.organizations),
switchMap((orgs) =>
forkJoin({
orgs: of(orgs),
avatarUrls: forkJoinConcurrent(
orgs.map((org) => this.getOrganizationAvatarUrl(org)),
Infinity
),
})
),
map(({ orgs, avatarUrls }) =>
orgs.map((org, index) => ({
value: org.id,
label: org.name,
avatarUrl: avatarUrls[index]?.url,
active: false,
}))
)
);
}

private getOrganizationAvatarUrl(org: Organization): Observable<Image> {
return iif(
() => !!org.avatarKey,
this.imageService.getImage({
objectKey: org.avatarKey,
height: ImageHeight._32px,
aspectRatio: ImageAspectRatio._11,
} as ImageQuery),
of({ url: '' })
).pipe(
catchError(() => {
console.error(
'Unable to get the image url. Please check the logs of the image service.'
);
return of({ url: '' });
})
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { FilterPanel } from '@sagebionetworks/openchallenges/ui';
import {
challengeStartYearRangeFilter,
challengeStatusFilter,
challengeInputDataTypesFilter,
challengeSubmissionTypesFilter,
challengeIncentivesFilter,
challengePlatformsFilter,
challengeOrganizationsFilter,
challengeOrganizersFilter,
challengeCategoriesFilter,
} from './challenge-search-filters';

export const challengeStartYearRangeFilterPanel: FilterPanel = {
query: 'startYearRange',
label: 'Challenge Year',
options: challengeStartYearRangeFilter,
collapsed: false,
};

// checkbox filters
export const challengeStatusFilterPanel: FilterPanel = {
query: 'status',
label: 'Status',
options: challengeStatusFilter,
collapsed: false,
};

export const challengeSubmissionTypesFilterPanel: FilterPanel = {
query: 'submissionTypes',
label: 'Submission Type',
options: challengeSubmissionTypesFilter,
collapsed: false,
};

export const challengeIncentivesFilterPanel: FilterPanel = {
query: 'incentives',
label: 'Incentive Type',
options: challengeIncentivesFilter,
collapsed: false,
};

export const challengePlatformsFilterPanel: FilterPanel = {
query: 'platforms',
label: 'Platform',
options: challengePlatformsFilter,
collapsed: false,
};

// dropdown filters
export const challengeInputDataTypesFilterPanel: FilterPanel = {
query: 'inputDataTypes',
label: 'Input Data Type',
options: challengeInputDataTypesFilter,
collapsed: false,
showAvatar: false,
};

export const challengeCategoriesFilterPanel: FilterPanel = {
query: 'categories',
label: 'Category',
options: challengeCategoriesFilter,
collapsed: false,
};

export const challengeOrganizationsFilterPanel: FilterPanel = {
query: 'organizations',
label: 'Organization',
options: challengeOrganizationsFilter,
collapsed: false,
showAvatar: true,
};

export const challengeOrganizatersFilterPanel: FilterPanel = {
query: 'organizers',
label: 'Organizer',
options: challengeOrganizersFilter,
collapsed: false,
showAvatar: true,
};
Loading

0 comments on commit a3716c1

Please sign in to comment.