better show filters

This commit is contained in:
2024-04-09 20:33:59 +02:00
parent 3d31594dbc
commit 669bd0d852
9 changed files with 137 additions and 26 deletions

View File

@@ -1,3 +1,5 @@
export interface FilterValues { export interface FilterValues {
time: number; time: number;
owner: string;
showType: string;
} }

View File

@@ -10,6 +10,34 @@
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
<mat-form-field appearance="outline">
<mat-label>Ersteller</mat-label>
<mat-select formControlName="owner">
<mat-option *ngFor="let owner of owners" [value]="owner.key">{{
owner.value
}}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field appearance="outline">
<mat-label>Art der Veranstaltung</mat-label>
<mat-select formControlName="showType">
<mat-optgroup label="öffentlich">
<mat-option *ngFor="let key of showTypePublic" [value]="key">{{
key | showType
}}
</mat-option>
</mat-optgroup>
<mat-optgroup label="privat">
<mat-option *ngFor="let key of showTypePrivate" [value]="key">{{
key | showType
}}
</mat-option>
</mat-optgroup>
</mat-select>
</mat-form-field>
</div> </div>
<i>Anzahl der Suchergebnisse: {{ shows.length }}</i> <i>Anzahl der Suchergebnisse: {{ shows.length }}</i>

View File

@@ -1,5 +1,5 @@
.third { .third {
display: grid; display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr; grid-template-columns: 1fr 1fr 1fr;
column-gap: 20px; column-gap: 20px;
} }

View File

@@ -4,6 +4,12 @@ import {ActivatedRoute, Router} from '@angular/router';
import {UntypedFormBuilder, UntypedFormGroup} from '@angular/forms'; import {UntypedFormBuilder, UntypedFormGroup} from '@angular/forms';
import {FilterValues} from './filter-values'; import {FilterValues} from './filter-values';
import {Show} from '../../services/show'; import {Show} from '../../services/show';
import {ShowService} from '../../services/show.service';
import {distinctUntilChanged, map} from 'rxjs/operators';
import {combineLatest, Observable} from 'rxjs';
import {dynamicSort, onlyUnique} from '../../../../services/filter.helper';
import {UserService} from '../../../../services/user/user.service';
import {isEqual} from 'lodash';
@Component({ @Component({
selector: 'app-filter', selector: 'app-filter',
@@ -14,6 +20,9 @@ export class FilterComponent {
@Input() public route = '/shows/'; @Input() public route = '/shows/';
@Input() public shows: Show[] = []; @Input() public shows: Show[] = [];
public showTypePublic = ShowService.SHOW_TYPE_PUBLIC;
public showTypePrivate = ShowService.SHOW_TYPE_PRIVATE;
public filterFormGroup: UntypedFormGroup; public filterFormGroup: UntypedFormGroup;
public times: KeyValue<number, string>[] = [ public times: KeyValue<number, string>[] = [
{key: 1, value: 'letzter Monat'}, {key: 1, value: 'letzter Monat'},
@@ -22,9 +31,19 @@ export class FilterComponent {
{key: 99999, value: 'alle'}, {key: 99999, value: 'alle'},
]; ];
public constructor(private router: Router, activatedRoute: ActivatedRoute, fb: UntypedFormBuilder) { public owners: {key: string; value: string}[] = [];
public constructor(
private router: Router,
private showService: ShowService,
private userService: UserService,
activatedRoute: ActivatedRoute,
fb: UntypedFormBuilder
) {
this.filterFormGroup = fb.group({ this.filterFormGroup = fb.group({
time: 1, time: 1,
owner: null,
showType: null,
}); });
activatedRoute.queryParams.subscribe(params => { activatedRoute.queryParams.subscribe(params => {
@@ -33,8 +52,34 @@ export class FilterComponent {
}); });
this.filterFormGroup.controls.time.valueChanges.subscribe(_ => void this.filerValueChanged('time', _ as number)); this.filterFormGroup.controls.time.valueChanges.subscribe(_ => void this.filerValueChanged('time', _ as number));
this.filterFormGroup.controls.owner.valueChanges.subscribe(_ => void this.filerValueChanged('owner', _ as string));
this.filterFormGroup.controls.showType.valueChanges.subscribe(_ => void this.filerValueChanged('showType', _ as string));
this.owners$().subscribe(owners => (this.owners = owners));
} }
public owners$ = (): Observable<{key: string; value: string}[]> => {
return combineLatest([
this.showService.list$().pipe(
map(shows => {
return shows.map(show => show.owner).filter(onlyUnique);
})
),
this.userService.users$,
]).pipe(
map(([owners, users]) => {
return owners
.map(ownerId => ({
key: ownerId,
value: users.find(user => user.id === ownerId)?.name,
}))
.sort(dynamicSort('value'));
}),
distinctUntilChanged(isEqual),
map(_ => _ as {key: string; value: string}[])
);
};
private async filerValueChanged<T>(key: string, value: T): Promise<void> { private async filerValueChanged<T>(key: string, value: T): Promise<void> {
const route = this.router.createUrlTree([this.route], { const route = this.router.createUrlTree([this.route], {
queryParams: {[key]: value}, queryParams: {[key]: value},

View File

@@ -9,7 +9,7 @@
<app-card <app-card
*ngIf="shows.length > 0" *ngIf="shows.length > 0"
[padding]="false" [padding]="false"
heading="meine Veranstaltungen" heading="Meine Veranstaltungen"
> >
<app-list-item <app-list-item
*ngFor="let show of shows | sortBy: 'desc':'date'" *ngFor="let show of shows | sortBy: 'desc':'date'"
@@ -24,7 +24,7 @@
<app-card <app-card
*ngIf="shows.length > 0" *ngIf="shows.length > 0"
[padding]="false" [padding]="false"
heading="veröffentlichte Veranstaltungen" heading="Veröffentlichte Veranstaltungen"
> >
<app-list-item <app-list-item
*ngFor="let show of shows | sortBy: 'desc':'date'; trackBy: trackBy" *ngFor="let show of shows | sortBy: 'desc':'date'; trackBy: trackBy"

View File

@@ -23,18 +23,29 @@ export class ListComponent {
return +filterValues.time; return +filterValues.time;
}) })
); );
public owner$ = this.activatedRoute.queryParams.pipe(
map(params => {
const filterValues = params as FilterValues;
return filterValues?.owner;
})
);
public publicShows$ = combineLatest([this.shows$, this.lastMonths$]).pipe( public publicShows$ = combineLatest([this.shows$, this.lastMonths$, this.owner$]).pipe(
map(_ => map(([shows, lastMonths, owner]) =>
_[0].filter(f => { shows
.filter(f => {
const d = new Date(); const d = new Date();
d.setMonth(d.getMonth() - _[1]); d.setMonth(d.getMonth() - lastMonths);
return f.published && f.date.toDate() >= d; return f.published && f.date.toDate() >= d;
}) })
.filter(show => !owner || show.owner === owner)
) )
); );
public constructor(private showService: ShowService, private activatedRoute: ActivatedRoute) {} public constructor(
private showService: ShowService,
private activatedRoute: ActivatedRoute
) {}
public trackBy = (index: number, show: unknown) => (show as Show).id; public trackBy = (index: number, show: unknown) => (show as Show).id;
} }

View File

@@ -22,7 +22,11 @@ export class NewComponent implements OnInit {
}); });
public faSave = faSave; public faSave = faSave;
public constructor(private showService: ShowService, showDataService: ShowDataService, private router: Router) { public constructor(
private showService: ShowService,
showDataService: ShowDataService,
private router: Router
) {
this.shows$ = showDataService.list$; this.shows$ = showDataService.list$;
} }

View File

@@ -13,3 +13,20 @@ export function filterSong(song: Song, filterValue: string): boolean {
function normalize(input: string): string { function normalize(input: string): string {
return input?.toLowerCase().replace(/[\s?!.,']/g, ''); return input?.toLowerCase().replace(/[\s?!.,']/g, '');
} }
export const onlyUnique = <T>(value: T, index: number, array: T[]) => array.indexOf(value) === index;
export function dynamicSort(property: string) {
let sortOrder = 1;
if (property[0] === '-') {
sortOrder = -1;
property = property.substr(1);
}
return function (a: unknown, b: unknown) {
/* next line works with strings and numbers,
* and you may want to customize it to your needs
*/
const result = a[property] < b[property] ? -1 : a[property] > b[property] ? 1 : 0;
return result * sortOrder;
};
}

View File

@@ -14,18 +14,7 @@ export class UserService {
private iUserId$ = new BehaviorSubject<string | null>(null); private iUserId$ = new BehaviorSubject<string | null>(null);
private iUser$ = new BehaviorSubject<User | null>(null); private iUser$ = new BehaviorSubject<User | null>(null);
public constructor(private afAuth: AngularFireAuth, private db: DbService, private router: Router) { public users$ = new BehaviorSubject<User[]>([]);
this.afAuth.authState
.pipe(
filter(auth => !!auth),
map(auth => auth?.uid ?? ''),
tap(uid => this.iUserId$.next(uid)),
switchMap(uid => this.readUser$(uid))
)
.subscribe(_ => this.iUser$.next(_));
this.db.col$<User>('users/').subscribe(_ => this.users$.next(_));
}
public get userId$(): Observable<string | null> { public get userId$(): Observable<string | null> {
return this.iUserId$.asObservable(); return this.iUserId$.asObservable();
@@ -37,7 +26,22 @@ export class UserService {
public currentUser = async (): Promise<User | null> => firstValueFrom(this.user$); public currentUser = async (): Promise<User | null> => firstValueFrom(this.user$);
private users$ = new BehaviorSubject<User[]>([]); public constructor(
private afAuth: AngularFireAuth,
private db: DbService,
private router: Router
) {
this.afAuth.authState
.pipe(
filter(auth => !!auth),
map(auth => auth?.uid ?? ''),
tap(uid => this.iUserId$.next(uid)),
switchMap(uid => this.readUser$(uid))
)
.subscribe(_ => this.iUser$.next(_));
this.db.col$<User>('users/').subscribe(_ => this.users$.next(_));
}
public getUserbyId = (userId: string): Promise<User | null> => firstValueFrom(this.getUserbyId$(userId)); public getUserbyId = (userId: string): Promise<User | null> => firstValueFrom(this.getUserbyId$(userId));
public getUserbyId$ = (userId: string): Observable<User | null> => this.users$.pipe(map(_ => _.find(f => f.id === userId) || null)); public getUserbyId$ = (userId: string): Observable<User | null> => this.users$.pipe(map(_ => _.find(f => f.id === userId) || null));