-
-
Notifications
You must be signed in to change notification settings - Fork 208
Open
Description
Working further after I got feedback on my stupid mistake from this:
#1864
The directives seem to work. Really nice!
Except for the following, see video:
https://www.loom.com/share/97fb2f0d78344ebf848eff2d467edd0c
so when drag/dropping the scrollbar, it's (very) easy to get a sort of recursive/repetitive jumping after dropping the scrollbar
The code:
import { ChangeDetectionStrategy, ChangeDetectorRef, Component } from '@angular/core';
import { Discipline, DisciplineType } from '../../../shared/models/discipline.model';
import { AngularDisciplineService } from '../core/services/discipline.service';
import { FormBuilder, FormGroup, ReactiveFormsModule } from '@angular/forms';
import { CollaborationsInformationService } from './collaborations-information.service';
import { BehaviorSubject, combineLatest, filter, firstValueFrom, lastValueFrom, map, Observable, startWith, tap } from 'rxjs';
import { CollaborationCompetitionProjection, CompetitionType, Organisation } from '../../../shared/models/organisation.model';
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
import { Title } from '@angular/platform-browser';
import { ActivatedRoute, Params, Router } from '@angular/router';
import { LocalStorage } from '../core/services/local-storage';
import { doesFormHaveErrors } from '../core/services/get-form-error-texts.service';
import { NavigationSidebarService } from '../sidebar/navigation-sidebar/navigation-sidebar.service';
import { OrganisationProjectionService } from '../core/services/organisation-projection.service';
import { transition, trigger, useAnimation } from '@angular/animations';
import { fadeIn, fadeOut } from '../core/animations/fade-in-out';
import { DateUtils } from '../../../shared/date.utils';
import { Helpers } from 'app/core/services/helpers.service';
import { UserService } from 'app/core/services/data-model-services/user.service';
import Fuse from 'fuse.js';
import { AngularCountryService } from 'app/core/services/countries.service';
import { AngularLevelHelpersService } from 'app/core/services/level-helpers.service';
import { CurrentOrganisationService } from 'app/core/services/organisation-service/current-organisation.service';
import { getMonth } from 'date-fns';
import { AuthenticationService } from 'app/core/services/authentication.service';
import { ToastService } from 'app/generic-components/toast/toast.service';
import { OrganisationService } from 'app/core/services/data-model-services/organisation.service';
import { MatDialog, MatDialogConfig } from '@angular/material/dialog';
import { DropDownDialogData, DropDownDialogOption, DropdownDialogComponent } from 'app/generic-components/dropdown-dialog/dropdown-dialog.component';
import { Timestamp } from 'firebase/firestore';
import { LoadingOverlayService } from 'app/core/services/loading-overlay.service';
import { AsyncPipe } from '@angular/common';
import { CountrySelectComponent } from '../generic-components/country-select/country-select.component';
import { MatFormField } from '@angular/material/form-field';
import { MatOption, MatSelect } from '@angular/material/select';
import { TranslateModule } from '@ngx-translate/core';
import { MatExpansionPanel, MatExpansionPanelHeader } from '@angular/material/expansion';
import { PictureSwitchAnimationComponent } from '../generic-components/picture-switch-animation/picture-switch-animation.component';
import { MatTooltip } from '@angular/material/tooltip';
import { MatIcon } from '@angular/material/icon';
import { MatButton } from '@angular/material/button';
import { FooterComponent } from '../footer/footer.component';
import { MatInput } from '@angular/material/input';
import { RxVirtualView, RxVirtualViewContent, RxVirtualViewObserver, RxVirtualViewPlaceholder } from '@rx-angular/template/virtual-view';
@UntilDestroy()
@Component({
changeDetection: ChangeDetectionStrategy.OnPush,
selector: 'collaboration-information-main',
styleUrls: ['collaborations-information-main.style.scss'],
template: `
<!--HEADER-->
@let competitions = competitions$ | async;
@let showNavigationSidebar = showNavigationSidebar$ | async;
<div rxVirtualViewObserver style="overflow-y: auto;">
<div [class.sidebar-open-header-container]="showNavigationSidebar" class="header-background header-container">
<div class="header-background-rotate header">
<!--TITLES-->
<div class="titles-container">
<h1 class="title">Collaborations</h1>
<p class="subtitle">Explore our collaborations!</p>
</div>
<!--FILTERS-->
<div [class.sidebar-open-filters-container]="showNavigationSidebar" class="filters-container">
@if (collaborationsInformationService.countryList$ | async; as countryList) {
<div
[@fadeInOut]
[class.sidebar-open-filters-select-box-container]="showNavigationSidebar"
class="filters-select-box-container"
[formGroup]="filtersForm"
>
<div [class.sidebar-open-filter-select-box]="showNavigationSidebar" class="filter-select-box">
<p class="filter-label">Country</p>
<country-select
appearance="outline"
[countriesToShow]="countryList"
[form]="filtersForm"
[shouldHaveEmptySelection]="true"
[shouldShowLabel]="false"
property="country"
></country-select>
</div>
<div>
<p class="filter-label">Competition type</p>
<mat-form-field [class.sidebar-open-filter-select-box]="showNavigationSidebar" class="filter-select-box" appearance="outline">
<mat-select matInput placeholder="Competition Type" formControlName="competition_type" (focusout)="cdr.markForCheck()">
<mat-option></mat-option>
@for (type of competitionTypes; track type) {
<mat-option color="primary" [value]="type.toLowerCase()">{{ type }}</mat-option>
}
</mat-select>
</mat-form-field>
</div>
<div>
<p class="filter-label">Competition discipline</p>
<mat-form-field [class.sidebar-open-filter-select-box]="showNavigationSidebar" class="filter-select-box" appearance="outline">
<mat-select matInput placeholder="Competition discipline" formControlName="discipline" (focusout)="cdr.markForCheck()">
<mat-option></mat-option>
@for (discipline of disciplines; track discipline.type) {
<mat-option [value]="discipline.type">{{ discipline.translationLabel | translate }}</mat-option>
}
</mat-select>
</mat-form-field>
</div>
<div>
<p class="filter-label">Year</p>
<mat-form-field [class.sidebar-open-filter-select-box]="showNavigationSidebar" class="filter-select-box" appearance="outline">
<mat-select matInput placeholder="Year" formControlName="competitionYear" (focusout)="cdr.markForCheck()">
<mat-option></mat-option>
<mat-option value="upcoming">Upcoming</mat-option>
@for (year of competitionYears; track year) {
<mat-option [value]="year">{{ year }}</mat-option>
}
</mat-select>
</mat-form-field>
</div>
<div>
<p class="filter-label">Search for competition</p>
<mat-form-field [class.sidebar-open-filter-select-box]="showNavigationSidebar" class="filter-select-box" appearance="outline">
<input matInput formControlName="freeTextFilter" />
</mat-form-field>
</div>
</div>
}
</div>
</div>
</div>
<div class="divider"></div>
<div [class.sidebar-open-content-container]="showNavigationSidebar$ | async" class="content-container white-space">
<p class="results-text">Showing {{ amountOfResultsFetched }} Results</p>
@if (competitions?.length) {
<div class="card-container flex-column">
@for (competition of competitions; track competition.key; let i = $index) {
<div rxVirtualView class="testing">
@if (isNewMonth(competitions[i === 0 ? 0 : i - 1].startDateSecondsAsNumber, competition.startDateSecondsAsNumber, i === 0)) {
<div class="month-container">
<div class="month-info">{{ getMonthAndYearForDisplay(competition.startDateSecondsAsNumber) }}</div>
</div>
}
<mat-expansion-panel
*rxVirtualViewContenthttps://github.com/rx-angular/rx-angular/issues/1864
hideToggle
class="card"
[attr.data-e2e-id]="competition.key"
[class.disabled-card]="competition.isCompetitionCancelled"
>
<mat-expansion-panel-header [collapsedHeight]="'100%'" [expandedHeight]="'100%'" (click)="togglePanelState(competition)">
<picture-switch-animation
id="card-image"
[newPicturePath]="getCompImage(competition)"
[pictureWidth]="'100%'"
[isSquare]="true"
[class.competition-is-cancelled]="competition.isCompetitionCancelled"
></picture-switch-animation>
<div id="card-text" class="flex-row">
<div class="left-section flex-column ">
<div id="competition-info" class="flex-column">
<div id="cancelled-and-location" class="flex-row">
@if (competition.isCompetitionCancelled) {
<p id="cancelled-text">Cancelled</p>
}
<div class="country-flag flex-row" [class.competition-is-cancelled]="competition.isCompetitionCancelled">
<div [class]="'flag-icon flag-icon-' + countryService.getCountryShort2(competition.country)"></div>
<div>
{{ countryService.getCountryName(competition.country) + (competition?.city ? ' - ' + competition?.city : '') }}
</div>
</div>
</div>
<div class="add-bold" [class.competition-is-cancelled]="competition.isCompetitionCancelled">{{ competition.name }}</div>
<div [class.competition-is-cancelled]="competition.isCompetitionCancelled">
{{ competition.startDateString }} - {{ competition.endDateString }}
</div>
</div>
<p
id="follow-the-competition"
class="follow-competition"
[class.competition-is-cancelled]="competition.isCompetitionCancelled"
(click)="navigateToLiveCompetition(competition.key)"
[matTooltip]="'Navigate to ' + competition.name + ' live competition view'"
[matTooltipPosition]="'below'"
>
<mat-icon>open_in_new</mat-icon>
Follow the competition
</p>
</div>
<div class="right-section flex-column" [class.competition-is-cancelled]="competition.isCompetitionCancelled">
@if (competition.has_registrations || competition.is_registration_enabled) {
<div class="align-right flex-row" [matTooltip]="getRegistrationTootipButtonText(competition)">
<button
id="registration-button"
[disabled]="isRegistrationButtonDisabled(competition)"
(click)="navigateToRegistration($event, competition)"
mat-raised-button
color="primary"
>
Register
</button>
</div>
}
<div id="open-card-button" class="align-right flex-row">
@if (!competition.panelStateOpen) {
<div class="add-bold">More Info</div>
} @else {
<div class="add-bold">Hide Info</div>
}
<mat-icon [class.transform-open-close]="competition.panelStateOpen === true">expand_more </mat-icon>
</div>
</div>
</div>
</mat-expansion-panel-header>
<div class="expansion-panel-divider"></div>
<div id="open-card-container" class="flex-column" [class.competition-is-cancelled]="competition.isCompetitionCancelled">
<div class="add-bold">Competition levels</div>
<ul class="comp-levels flex-row">
@if (competition.levelsProjection) {
@for (level of competition.levelsProjection; track level; let i = $index) {
<li>{{ levelHelpersService.getLevelNameForDisplayFromLongLevel(competition.discipline, level) }}</li>
}
} @else {
-
}
</ul>
</div>
</mat-expansion-panel>
<div *rxVirtualViewPlaceholder style="height: 500px;">test</div>
</div>
}
</div>
}
@if (areThereMoreThanThirtyCompetitions) {
<button id="load-all-competitions-button" mat-raised-button color="primary" (click)="shouldLoadAllCompetitions$$.next(true)">
<p>Load All Competitions</p>
<mat-icon>cached</mat-icon>
</button>
}
</div>
<footer-main></footer-main>
</div>
`,
animations: [
trigger('fadeInOut', [
transition('void => *', [useAnimation(fadeIn, { params: { timings: '300ms ease-out' } })]),
transition('* => void', [useAnimation(fadeOut, { params: { timings: '300ms ease-out' } })]),
transition('* => void', [useAnimation(fadeOut, { params: { params: '500ms ease-out' } })]),
]),
],
imports: [
AsyncPipe,
ReactiveFormsModule,
CountrySelectComponent,
MatFormField,
MatSelect,
MatOption,
TranslateModule,
MatExpansionPanel,
PictureSwitchAnimationComponent,
MatExpansionPanelHeader,
MatTooltip,
MatIcon,
MatButton,
FooterComponent,
MatInput,
RxVirtualViewObserver,
RxVirtualView,
RxVirtualViewContent,
RxVirtualViewPlaceholder,
],
})
export class CollaborationsInformationMainComponent {
disciplines: readonly Discipline[];
competitionYears: string[];
public filtersForm: FormGroup;
public currentQueryParams;
competitionTypes: string[] = ['National', 'International', 'Official'];
competitions$: Observable<CollaborationCompetitionProjection[]>;
amountOfResultsFetched: number;
areThereMoreThanThirtyCompetitions: boolean;
protected shouldLoadAllCompetitions$$: BehaviorSubject<boolean> = new BehaviorSubject(false);
shouldLoadAllCompetitions$: Observable<boolean> = this.shouldLoadAllCompetitions$$.asObservable();
readonly showNavigationSidebar$: Observable<boolean>;
readonly collaborationCountryKey: string = 'collaboration_country_filter';
readonly collaborationDisciplineKey: string = 'collaboration_discipline_filter';
readonly collaborationTypeKey: string = 'collaboration_competition_type_filter';
readonly collaborationYearKey: string = 'collaboration_competition_year_filter';
constructor(
public disciplineService: AngularDisciplineService,
public collaborationsInformationService: CollaborationsInformationService,
private fb: FormBuilder,
private titleService: Title,
private route: ActivatedRoute,
private helpers: Helpers,
private router: Router,
private dialog: MatDialog,
private localStorage: LocalStorage,
private navigationSidebarService: NavigationSidebarService,
private organisationProjectionService: OrganisationProjectionService,
public cdr: ChangeDetectorRef,
public authenticationService: AuthenticationService,
private userService: UserService,
public countryService: AngularCountryService,
public levelHelpersService: AngularLevelHelpersService,
public currentOrganisationService: CurrentOrganisationService,
private toastService: ToastService,
private organisationService: OrganisationService,
private loadingOverlayService: LoadingOverlayService,
) {
this.disciplines = this.disciplineService.getDisciplines();
this.showNavigationSidebar$ = this.navigationSidebarService.showNavigationSidebar$;
this.loadingOverlayService.enable('load-collaborations', 'Loading collaborations...');
this.collaborationsInformationService.loadCompetitionsToShow();
this.createForm();
this.currentQueryParams = { ...this.route.snapshot.queryParams };
if (this.currentQueryParams.country) {
this.filtersForm.get('country').patchValue(this.currentQueryParams.country);
} else if (!!this.getFilterProperties(this.collaborationCountryKey)) {
this.filtersForm.get('country').patchValue(this.getFilterProperties(this.collaborationCountryKey));
}
if (this.currentQueryParams.discipline) {
this.filtersForm.get('discipline').patchValue(this.currentQueryParams.discipline);
} else if (!!this.getFilterProperties(this.collaborationDisciplineKey)) {
this.filtersForm.get('discipline').patchValue(this.getFilterProperties(this.collaborationDisciplineKey));
}
if (this.currentQueryParams.competition_type) {
this.filtersForm.get('competition_type').patchValue(this.currentQueryParams.competition_type);
} else if (!!this.getFilterProperties(this.collaborationTypeKey)) {
this.filtersForm.get('competition_type').patchValue(this.getFilterProperties(this.collaborationTypeKey));
}
if (this.currentQueryParams.competitionYear) {
this.filtersForm.get('competitionYear').patchValue(this.currentQueryParams.competitionYear);
} else if (!!this.getFilterProperties(this.collaborationYearKey)) {
this.filtersForm.get('competitionYear').patchValue(this.getFilterProperties(this.collaborationYearKey));
} else {
if (!this.helpers.isInPlayWright) this.filtersForm.get('competitionYear').patchValue('upcoming');
}
this.updateQueryParams();
}
ngOnInit() {
this.titleService.setTitle('AC - Collaborations');
const filtersValueChanges$: Observable<Partial<Organisation> | any> = this.filtersForm.valueChanges.pipe(
tap(filters => {
if (filters.country || filters.discipline || filters.competition_type || filters.competitionYear || filters.freeTextFilter?.length > 3) {
// This is just to log the properties that actually have values
this.helpers.functionalityLog('collaboration_page', 'Filter Selection', {
filtersUsed: Object.keys(filters).reduce((objectToLog, propToLog) => {
if (filters[propToLog]) objectToLog[propToLog] = filters[propToLog];
return objectToLog;
}, {}),
});
}
}),
startWith(this.filtersForm.getRawValue()),
filter(_ => !doesFormHaveErrors(this.filtersForm)),
map(_ => this.filtersForm.getRawValue()),
tap((filtersFormValue: Partial<Organisation> | any) =>
this.setFiltersInLocalStorage(
filtersFormValue.country,
filtersFormValue.discipline,
filtersFormValue.competition_type,
filtersFormValue.competitionYear,
),
),
);
this.competitions$ = combineLatest([
filtersValueChanges$,
this.organisationProjectionService.collaborationCompetitionProjections$,
this.shouldLoadAllCompetitions$,
]).pipe(
tap(() => this.updateQueryParams()),
tap(([_, projection, __]) => {
if (projection) {
this.loadingOverlayService.disable('load-collaborations');
}
}),
filter(([_, projections, __]: [any, CollaborationCompetitionProjection[], boolean]) => !!projections),
map(([_, projections, __]: [any, CollaborationCompetitionProjection[], boolean]): [any, CollaborationCompetitionProjection[], boolean] => {
const projectionsThatUsersCanSee: CollaborationCompetitionProjection[] = this.filterCompetitionsThatUsersAreNotAllowedToSee(projections);
return [_, projectionsThatUsersCanSee, __];
}),
map(([_, projections, __]: [any, CollaborationCompetitionProjection[], boolean]) => {
// Here we add more info to the projections, so we don't need to do extra computations in the template
const projectionsWithMoreProps: CollaborationCompetitionProjection[] = this.addPropertiesToProjectionsForTemplateUse(projections);
return [_, projectionsWithMoreProps, __];
}),
tap(([_, projections, __]: [any, CollaborationCompetitionProjection[], boolean]) => {
this.initializeCompetitionYearsArray(projections);
}),
map(([filters, projections, __]: [any, CollaborationCompetitionProjection[], boolean]) =>
this.filterProjections(
filters.country,
filters.discipline,
filters.competition_type,
filters.competitionYear,
filters.freeTextFilter,
Object.values(projections),
__,
),
),
tap(([projections, shouldForceLoadAllCompetitions]: [CollaborationCompetitionProjection[], boolean]) => {
// Set the real amount of projections that were fetched and filtered by the selection and input filters
this.amountOfResultsFetched = projections.length;
this.setIfThereAreModeThanThirtyCompetitions(projections, shouldForceLoadAllCompetitions);
}),
map(([projections, shouldForceLoadAllCompetitions]: [CollaborationCompetitionProjection[], boolean]): CollaborationCompetitionProjection[] =>
shouldForceLoadAllCompetitions ? projections : projections.filter((_, index) => index < 30),
),
);
// We need this because if we deeplink to this page it wouldn't log with the correct user email
this.userService.userEmail$.pipe(untilDestroyed(this)).subscribe(_ => {
this.helpers.functionalityLog('collaboration_page', 'Entering collaborations');
});
}
filterCompetitionsThatUsersAreNotAllowedToSee(projections: CollaborationCompetitionProjection[]): CollaborationCompetitionProjection[] {
return Object.values(projections).filter((projection: CollaborationCompetitionProjection) => !projection.isHiddenOrganisation);
}
addPropertiesToProjectionsForTemplateUse(projections: CollaborationCompetitionProjection[]): CollaborationCompetitionProjection[] {
return projections.map((projection: CollaborationCompetitionProjection) => {
const start_date: string = this.getDateStringFromSeconds(projection.startDateSecondsAsNumber);
const end_date: string = this.getDateStringFromSeconds(projection.endDateSecondsAsNumber);
projection.panelStateOpen = false;
projection.endDateString = end_date;
projection.startDateString = start_date;
return projection;
});
}
initializeCompetitionYearsArray(projections: CollaborationCompetitionProjection[]) {
const competitionYearsSet: Set<string> = new Set<string>();
Object.values(projections).forEach((projection: CollaborationCompetitionProjection) => {
projection.startDateSecondsAsNumber ? competitionYearsSet.add(DateUtils.getYearFromSeconds(projection.startDateSecondsAsNumber)) : null;
});
this.competitionYears = Array.from(competitionYearsSet).sort((a: string, b: string) => +b - +a);
}
setIfThereAreModeThanThirtyCompetitions(projections: CollaborationCompetitionProjection[], shouldForceLoadAllCompetitions: boolean) {
if (!shouldForceLoadAllCompetitions) {
this.areThereMoreThanThirtyCompetitions = projections.length > 30;
} else {
this.areThereMoreThanThirtyCompetitions = false;
}
}
setFiltersInLocalStorage(country: string, discipline: string, competitionType: string, competitionYear: string) {
this.collaborationsInformationService.setFilterProperties(this.collaborationCountryKey, country);
this.collaborationsInformationService.setFilterProperties(this.collaborationDisciplineKey, discipline);
this.collaborationsInformationService.setFilterProperties(this.collaborationTypeKey, competitionType);
this.collaborationsInformationService.setFilterProperties(this.collaborationYearKey, competitionYear);
}
updateQueryParams() {
let queryParams: Params = {
country: this.filtersForm.get('country')?.value,
discipline: this.filtersForm.get('discipline')?.value,
competition_type: this.filtersForm.get('competition_type')?.value,
competitionYear: this.filtersForm.get('competitionYear')?.value,
};
this.router.navigate([], {
relativeTo: this.route,
queryParams: queryParams,
queryParamsHandling: 'merge', // remove to replace all query params by provided
});
}
filterProjections(
country: string,
discipline: DisciplineType,
competitionType: CompetitionType,
competitionYear: string,
freeTextFilter: string,
competitionsProjections: CollaborationCompetitionProjection[],
shouldForceLoadAllCompetitions: boolean,
): [CollaborationCompetitionProjection[], boolean] {
let allCompetitionsProjections: CollaborationCompetitionProjection[] = competitionsProjections;
if (freeTextFilter) {
const fuseOptions = {
keys: ['name', 'country'],
threshold: 0.2,
};
let fuse = new Fuse(competitionsProjections, fuseOptions);
allCompetitionsProjections = fuse.search(freeTextFilter).map(fuseReturnObject => fuseReturnObject.item);
}
return [
allCompetitionsProjections
.filter((projection: CollaborationCompetitionProjection) => {
let shouldFilterByYear: boolean;
if (competitionYear) {
if (competitionYear === 'upcoming') {
const start_date: Date = DateUtils.convertSecondsFromMidnightToDate(projection.startDateSecondsAsNumber);
const today: Date = new Date();
shouldFilterByYear = DateUtils.isFirstDateBeforeSecond(today, start_date);
} else shouldFilterByYear = DateUtils.getYearFromSeconds(projection.startDateSecondsAsNumber) === competitionYear;
} else shouldFilterByYear = true;
return (
(country ? projection.country === country : true) &&
(discipline ? projection.discipline === discipline : true) &&
(competitionType ? projection.competition_type === competitionType : true) &&
shouldFilterByYear
);
})
.sort((projectionA: CollaborationCompetitionProjection, projectionB: CollaborationCompetitionProjection): number => {
if (competitionYear && competitionYear === 'upcoming') return this.sortCompetitionProjectionsByDateAndName(projectionA, projectionB, false);
else return this.sortCompetitionProjectionsByDateAndName(projectionA, projectionB, true);
}),
shouldForceLoadAllCompetitions,
];
}
createForm() {
this.filtersForm = this.fb.group({
country: ['', {}],
competition_type: ['', {}],
discipline: ['', {}],
competitionYear: ['', {}],
freeTextFilter: ['', {}],
});
}
getCompImage(competition: CollaborationCompetitionProjection): string {
if (!!competition.competitionPosterUrl) return competition.competitionPosterUrl;
else if (!!competition.logoUrl) return competition.logoUrl;
else if (!!competition.associatedOrganisationLogoUrl) return competition.associatedOrganisationLogoUrl;
else return '/assets/logos/minimized_logo_blue.svg';
}
getFilterProperties(key: string): any {
return this.localStorage.getItem(key);
}
navigateToLiveCompetition(competitionKey: string) {
// Query Params added, so we know that we navigated from the collaboration page
this.helpers.functionalityLog('collaboration_page', 'Competition Clicked', { competitionKey });
// skipLocationChange => used to be able to navigate from live competitions to collaborations without being necessary to navigate back two times
this.router.navigate([`competition/${competitionKey}/information`], { skipLocationChange: true });
}
sortCompetitionProjectionsByDateAndName(
projectionA: CollaborationCompetitionProjection,
projectionB: CollaborationCompetitionProjection,
shouldSortInDescendingOrder: boolean,
): number {
const dateInSecondsA: number = projectionA.startDateSecondsAsNumber;
const dateInSecondsB: number = projectionB.startDateSecondsAsNumber;
if (dateInSecondsA !== dateInSecondsB) return shouldSortInDescendingOrder ? dateInSecondsB - dateInSecondsA : dateInSecondsA - dateInSecondsB;
else {
const nameA: string = projectionA.name.toLowerCase();
const nameB: string = projectionB.name.toLowerCase();
if (nameA < nameB) {
return -1;
}
if (nameA > nameB) {
return 1;
}
return 0;
}
}
togglePanelState(competition: CollaborationCompetitionProjection) {
competition.panelStateOpen = !competition.panelStateOpen;
}
getDateStringFromSeconds(seconds: number): string {
return seconds ? DateUtils.convertSecondsFromMidnightToDateString(seconds) : '';
}
getMonthAndYearForDisplay(seconds: number): string {
if (seconds === null || seconds === undefined) return;
const Date: Date = DateUtils.convertSecondsFromMidnightToDate(seconds);
return DateUtils.getMonthAndYearString(Date);
}
isNewMonth(previousCompetitionDateInSeconds: number, currentCompetitionDateInSeconds: number, isFirstIteration: boolean): boolean {
if (isFirstIteration) return true;
else {
const monthOfPreviousCompetition: number = getMonth(DateUtils.convertSecondsFromMidnightToDate(previousCompetitionDateInSeconds));
const monthOfCurrentCompetition: number = getMonth(DateUtils.convertSecondsFromMidnightToDate(currentCompetitionDateInSeconds));
return monthOfPreviousCompetition !== monthOfCurrentCompetition;
}
}
async navigateToRegistration(event, organisation: CollaborationCompetitionProjection) {
// stops the levels div from opening when clicking the registration button
event.stopPropagation();
if (organisation.is_registration_enabled) {
this.router.navigate([`registrations/configuration/${organisation.key}`], { replaceUrl: true });
} else if (organisation.has_registrations) {
if (organisation.is_open_for_registrations) {
const clubsWhereUserIsManagerOf: Organisation[] = await firstValueFrom(this.organisationService.connectToClubsList$());
if (clubsWhereUserIsManagerOf.length === 0) {
// If we change the toast string we have to change the string in the collaboration page testsuite as well
this.toastService.show({
text: 'You are not a manager of any club, please contact your club so they can add you as a manager to be able to register to this competition',
type: 'warning',
});
return;
}
let clubToCreateRegistration: Organisation;
if (clubsWhereUserIsManagerOf.length > 1) {
let clubOptionsToSelect: DropDownDialogOption[] = [];
clubsWhereUserIsManagerOf.forEach(club => {
clubOptionsToSelect.push({
value: club.$key,
label: club.name,
});
});
let config: MatDialogConfig<DropDownDialogData> = {
data: {
title: 'Select the club to start registration',
options: clubOptionsToSelect,
selectionRequired: true,
hasCancelButton: true,
placeholder: 'Select a Club...',
},
autoFocus: false,
} as MatDialogConfig;
let dialogRef = this.dialog.open(DropdownDialogComponent, config);
let result: any = await lastValueFrom(dialogRef.afterClosed());
if (result?.clicked === 'ok') {
clubToCreateRegistration = clubsWhereUserIsManagerOf.find(club => club.$key === result.value);
} else {
return;
}
} else {
clubToCreateRegistration = clubsWhereUserIsManagerOf[0];
}
// we need this because sometimes the currentOrganisation might be null which would cause the navigation below to fail.
// An example is whenever you were on org admin, and you went to live competitions and then to collaborations and tried to register the navigation would fail
this.currentOrganisationService.setOrganisation(clubToCreateRegistration.$key);
await this.loadingOverlayService.enable('navigateToClubRegistrations', 'Navigation to club registrations...');
await firstValueFrom(this.currentOrganisationService.organisation$.pipe(filter(org => org?.$key === clubToCreateRegistration.$key)));
await this.router.navigate([`/organisation-admin/${clubToCreateRegistration.$key}/members`], {
replaceUrl: true,
queryParams: { clubtab: 'Registrations', organisationKey: organisation.key, organisationDiscipline: organisation.discipline },
});
await this.loadingOverlayService.disable('navigateToClubRegistrations');
} else {
// If we change the toast string we have to change the string in the collaboration page testsuite as well
this.toastService.show({ text: 'This competition is not accepting registrations right now', type: 'warning' });
}
}
}
isRegistrationButtonDisabled(organisation: CollaborationCompetitionProjection): boolean {
return !!this.getRegistrationTootipButtonText(organisation);
}
getRegistrationTootipButtonText(organisation: CollaborationCompetitionProjection): string {
const todaySeconds: number = Timestamp.now().seconds;
if (organisation.endDateSecondsAsNumber < todaySeconds) return 'This competition has already ended';
else if (!this.authenticationService.isUserLoggedIn()) return 'Please sign in to register';
else return null;
}
}
Metadata
Metadata
Assignees
Labels
No labels