Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(openchallenges): improve query parameter management using location service #2273

Merged
merged 17 commits into from
Oct 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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