This commit is contained in:
2026-03-15 12:50:33 +01:00
parent dd68a6b21d
commit d907c89eb6
36 changed files with 309 additions and 286 deletions

View File

@@ -1,4 +1,5 @@
import {Component, inject} from '@angular/core';
import {Component, DestroyRef, inject} from '@angular/core';
import {takeUntilDestroyed} from '@angular/core/rxjs-interop';
import {Upload} from '../../../services/upload';
import {UploadService} from '../../../services/upload.service';
import {ActivatedRoute} from '@angular/router';
@@ -22,6 +23,7 @@ export class EditFileComponent {
private activatedRoute = inject(ActivatedRoute);
private uploadService = inject(UploadService);
private fileService = inject(FileDataService);
private destroyRef = inject(DestroyRef);
public selectedFiles: FileList | null = null;
public currentUpload: Upload | null = null;
@@ -32,7 +34,8 @@ export class EditFileComponent {
this.activatedRoute.params
.pipe(
map(param => param as {songId: string}),
map(param => param.songId)
map(param => param.songId),
takeUntilDestroyed(this.destroyRef)
)
.subscribe(songId => {
this.songId = songId;

View File

@@ -1,9 +1,10 @@
import {Component, OnInit, inject} from '@angular/core';
import {Component, DestroyRef, inject, OnInit} from '@angular/core';
import {takeUntilDestroyed} from '@angular/core/rxjs-interop';
import {Song} from '../../../services/song';
import {ReactiveFormsModule, UntypedFormGroup} from '@angular/forms';
import {ReactiveFormsModule} from '@angular/forms';
import {ActivatedRoute, Router, RouterStateSnapshot} from '@angular/router';
import {SongService} from '../../../services/song.service';
import {EditService} from '../edit.service';
import {EditService, SongFormGroup} from '../edit.service';
import {first, map, switchMap} from 'rxjs/operators';
import {startWith} from 'rxjs';
import {KEYS} from '../../../services/key.helper';
@@ -62,15 +63,9 @@ import {StatusPipe} from '../../../../../widget-modules/pipes/status-translater/
],
})
export class EditSongComponent implements OnInit {
private activatedRoute = inject(ActivatedRoute);
private songService = inject(SongService);
private editService = inject(EditService);
private router = inject(Router);
private textRenderingService = inject(TextRenderingService);
public dialog = inject(MatDialog);
public song: Song | null = null;
public form: UntypedFormGroup = new UntypedFormGroup({});
public form = {} as SongFormGroup;
public keys = KEYS;
public types = SongService.TYPES;
public status = SongService.STATUS;
@@ -83,6 +78,12 @@ export class EditSongComponent implements OnInit {
public faLink = faExternalLinkAlt;
public songtextFocus = false;
public chordValidationIssues: ChordValidationIssue[] = [];
private activatedRoute = inject(ActivatedRoute);
private songService = inject(SongService);
private editService = inject(EditService);
private router = inject(Router);
private textRenderingService = inject(TextRenderingService);
private destroyRef = inject(DestroyRef);
public ngOnInit(): void {
this.activatedRoute.params
@@ -90,23 +91,24 @@ export class EditSongComponent implements OnInit {
map(param => param as {songId: string}),
map(param => param.songId),
switchMap(songId => this.songService.read$(songId)),
first()
first(),
takeUntilDestroyed(this.destroyRef)
)
.subscribe(song => {
this.song = song;
if (!song) return;
this.form = this.editService.createSongForm(song);
this.form.controls.flags.valueChanges.subscribe(_ => this.onFlagsChanged(_ as string));
this.form.controls.text.valueChanges.pipe(startWith(this.form.controls.text.value)).subscribe(text => {
this.updateChordValidation(text as string);
this.form.controls.flags.valueChanges.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(value => this.onFlagsChanged(value));
this.form.controls.text.valueChanges.pipe(startWith(this.form.controls.text.value), takeUntilDestroyed(this.destroyRef)).subscribe(text => {
this.updateChordValidation(text);
});
this.onFlagsChanged(this.form.controls.flags.value as string);
this.onFlagsChanged(this.form.controls.flags.value);
});
}
public async onSave(): Promise<void> {
if (!this.song || this.form.invalid) return;
const data = this.form.value as Partial<Song>;
const data = this.form.getRawValue() as Partial<Song>;
await this.songService.update$(this.song.id, data);
this.form.markAsPristine();
await this.router.navigateByUrl('songs/' + this.song.id);
@@ -121,7 +123,6 @@ export class EditSongComponent implements OnInit {
const input = event.input;
const value = event.value;
// Add our fruit
if ((value || '').trim()) {
const flags = [...this.flags, value.trim()];
this.form.controls.flags.setValue(flags.join(';'));
@@ -174,7 +175,7 @@ export class EditSongComponent implements OnInit {
private async onSaveDialogAfterClosed(save: boolean, url: string) {
if (save && this.song && !this.form.invalid) {
const data = this.form.value as Partial<Song>;
const data = this.form.getRawValue() as Partial<Song>;
await this.songService.update$(this.song.id, data);
}

View File

@@ -1,30 +1,48 @@
import {Injectable} from '@angular/core';
import {Song} from '../../services/song';
import {UntypedFormControl, UntypedFormGroup} from '@angular/forms';
import {FormControl, FormGroup} from '@angular/forms';
export type SongFormGroup = FormGroup<{
text: FormControl<string>;
title: FormControl<string>;
comment: FormControl<string>;
flags: FormControl<string>;
key: FormControl<string>;
tempo: FormControl<number>;
type: FormControl<Song['type']>;
status: FormControl<Song['status']>;
legalType: FormControl<Song['legalType']>;
legalOwner: FormControl<Song['legalOwner']>;
legalOwnerId: FormControl<string>;
artist: FormControl<string>;
label: FormControl<string>;
termsOfUse: FormControl<string>;
origin: FormControl<string>;
}>;
@Injectable({
providedIn: 'root',
})
export class EditService {
public createSongForm(song: Song): UntypedFormGroup {
return new UntypedFormGroup({
text: new UntypedFormControl(song.text),
title: new UntypedFormControl(song.title),
comment: new UntypedFormControl(song.comment),
flags: new UntypedFormControl(song.flags),
key: new UntypedFormControl(song.key),
tempo: new UntypedFormControl(song.tempo),
type: new UntypedFormControl(song.type),
status: new UntypedFormControl(song.status ?? 'draft'),
public createSongForm(song: Song): SongFormGroup {
return new FormGroup({
text: new FormControl(song.text, {nonNullable: true}),
title: new FormControl(song.title, {nonNullable: true}),
comment: new FormControl(song.comment, {nonNullable: true}),
flags: new FormControl(song.flags, {nonNullable: true}),
key: new FormControl(song.key, {nonNullable: true}),
tempo: new FormControl(song.tempo, {nonNullable: true}),
type: new FormControl(song.type, {nonNullable: true}),
status: new FormControl(song.status ?? 'draft', {nonNullable: true}),
legalType: new UntypedFormControl(song.legalType),
legalOwner: new UntypedFormControl(song.legalOwner),
legalOwnerId: new UntypedFormControl(song.legalOwnerId),
legalType: new FormControl(song.legalType, {nonNullable: true}),
legalOwner: new FormControl(song.legalOwner, {nonNullable: true}),
legalOwnerId: new FormControl(song.legalOwnerId, {nonNullable: true}),
artist: new UntypedFormControl(song.artist),
label: new UntypedFormControl(song.label),
termsOfUse: new UntypedFormControl(song.termsOfUse),
origin: new UntypedFormControl(song.origin),
artist: new FormControl(song.artist, {nonNullable: true}),
label: new FormControl(song.label, {nonNullable: true}),
termsOfUse: new FormControl(song.termsOfUse, {nonNullable: true}),
origin: new FormControl(song.origin, {nonNullable: true}),
});
}
}