event subscriptions

This commit is contained in:
toni
2026-03-15 15:39:45 +01:00
parent 29c6828dd1
commit 2620538a2c
26 changed files with 1028 additions and 214 deletions
@@ -0,0 +1,65 @@
<h1>Gesammelte Veranstaltungen</h1>
<p>
<button matButton="filled" (click)="subscribe()">Abbonieren</button>
<button matButton="filled" class="secondary-btn" (click)="unsubscribe()">
Abmelden
</button>
</p>
<div class="table-container">
<table mat-table [dataSource]="datasource" matSort>
<ng-container matColumnDef="source">
<th mat-header-cell mat-sort-header *matHeaderCellDef>
Gefunden bei
</th>
<td mat-cell *matCellDef="let element">
<a [href]="element.source"
>{{truncateSource(element.source)}}</a
>
</td>
</ng-container>
<ng-container matColumnDef="url">
<th mat-header-cell mat-sort-header *matHeaderCellDef>Link</th>
<td mat-cell *matCellDef="let element">
<a
matButton
[href]="element.url"
target="_blank"
[ellipsis]="80"
>{{element.url}}</a
>
</td>
</ng-container>
<ng-container matColumnDef="eventDate">
<th mat-header-cell mat-sort-header *matHeaderCellDef>
Ausrichtungsdatum
</th>
<td mat-cell *matCellDef="let element">{{element.eventDate}}</td>
</ng-container>
<ng-container matColumnDef="title">
<th mat-header-cell mat-sort-header *matHeaderCellDef>Titel</th>
<td mat-cell *matCellDef="let element">{{element.title}}</td>
</ng-container>
<ng-container matColumnDef="description">
<th mat-header-cell mat-sort-header *matHeaderCellDef>
Beschreibung
</th>
<td mat-cell *matCellDef="let element">{{element.description}}</td>
</ng-container>
<ng-container matColumnDef="attachedFiles">
<th mat-header-cell *matHeaderCellDef>Anhänge</th>
<td mat-cell *matCellDef="let element">
@for(attachment of element.attachedFiles; track attachment.id){
<a matButton="outlined" [href]="attachment.url" target="_blank"
>{{attachment.title??'?'}}</a
>
}
</td>
</ng-container>
<tr
mat-header-row
*matHeaderRowDef="displayedColumns; sticky: true"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
</table>
</div>
@@ -0,0 +1,12 @@
:host {
display: flex;
flex-flow: column;
height: 100%;
// overflow: auto;
}
.table-container {
overflow: auto;
border: 1px solid var(--mat-sys-outline);
min-height: 400px;
}
@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { Events } from './events';
describe('Events', () => {
let component: Events;
let fixture: ComponentFixture<Events>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [Events]
})
.compileComponents();
fixture = TestBed.createComponent(Events);
component = fixture.componentInstance;
await fixture.whenStable();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
@@ -0,0 +1,79 @@
import {
ChangeDetectionStrategy,
Component,
inject,
OnInit,
viewChild,
} from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MatSort, MatSortModule } from '@angular/material/sort';
import { MatTableDataSource, MatTableModule } from '@angular/material/table';
import { parse } from 'date-fns';
import { Ellipsis } from '../../directives/ellipsis/ellipsis';
import * as api from '../../generated-api/api';
import { PushService } from '../../services/push/pushService';
@Component({
selector: 'app-events',
imports: [MatTableModule, MatSortModule, MatButtonModule, Ellipsis],
templateUrl: './events.html',
styleUrl: './events.scss',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class Events implements OnInit {
private readonly pushService = inject(PushService);
protected readonly datasource = new MatTableDataSource<api.FoundEventDto>();
protected readonly sort = viewChild.required(MatSort);
protected readonly displayedColumns = [
'eventDate',
'title',
'description',
'attachedFiles',
'url',
'source',
];
public async ngOnInit(): Promise<void> {
this.datasource.sort = this.sort();
const originalSortingAccessor = this.datasource.sortingDataAccessor;
this.datasource.sortingDataAccessor = (item, property) => {
if (property != 'eventDate') {
return originalSortingAccessor(item, property);
}
if (!item.eventDate) {
return NaN;
}
const parts = item.eventDate.split('-');
if (parts.length == 1) {
return parse(parts[0]!, 'dd.MM.yyyy', new Date()).valueOf();
}
if (parts.length == 2) {
const p2 = parts[1].split('.');
p2.splice(0, 1, parts[0]);
return parse(p2.join('.'), 'dd.MM.yyyy', new Date()).valueOf();
}
console.warn('unknown date format:', property);
return originalSortingAccessor(item, property);
};
const data = await api.getFutureEvents();
this.datasource.data = data;
}
protected truncateSource(sourceUrl: string): string {
if (!URL.canParse(sourceUrl)) {
return sourceUrl;
}
const url = new URL(sourceUrl);
return url.hostname;
}
protected async unsubscribe() {
await this.pushService.resetSubscriptions();
}
protected async subscribe() {
this.pushService.subscribeToEvents();
}
}
@@ -5,16 +5,24 @@
Mitgliederliste
</button>
</mat-list-item>
<mat-list-item [claimGuard]="Claim.Useradmin">
<mat-list-item>
<button
matButton="filled"
class="tertiary-btn"
[routerLink]="['/events']">
Veranstaltungen
</button>
</mat-list-item>
<!-- <mat-list-item [claimGuard]="Claim.Useradmin">
<button matButton="filled" color="warn" [routerLink]="['/manageUsers']">
Benutzer Verwalten
</button>
</mat-list-item>
<mat-list-item [claimGuard]="Claim.Memberadmin">
</mat-list-item> -->
<!-- <mat-list-item [claimGuard]="Claim.Memberadmin">
<button matButton="filled" color="primary" [routerLink]="['/exam']">
Prüfungsanmeldung
</button>
</mat-list-item>
</mat-list-item> -->
<mat-list-item>
<button
matButton="outlined"