Picsur/frontend/src/app/components/pref-option/pref-option.component.ts

105 lines
2.9 KiB
TypeScript

import { Component, Input, OnInit } from '@angular/core';
import { AbstractControl, FormControl, ValidationErrors } from '@angular/forms';
import { AutoUnsubscribe } from 'ngx-auto-unsubscribe-decorator';
import {
DecodedPref,
PrefValueType,
} from 'picsur-shared/dist/dto/preferences.dto';
import { AsyncFailable, HasFailed } from 'picsur-shared/dist/types/failable';
import { filter } from 'rxjs';
import { ZodTypeAny } from 'zod';
import { Required } from '../../models/decorators/required.decorator';
import { Logger } from '../../services/logger/logger.service';
import { ErrorService } from '../../util/error-manager/error.service';
import { Throttle } from '../../util/throttle';
@Component({
selector: 'pref-option',
templateUrl: './pref-option.component.html',
styleUrls: ['./pref-option.component.scss'],
})
export class PrefOptionComponent implements OnInit {
private readonly logger = new Logger(PrefOptionComponent.name);
public formControl = new FormControl<any>(undefined, {
updateOn: 'blur',
validators: this.syncValidator.bind(this),
});
private pref: DecodedPref;
@Input('pref') set prefSet(pref: DecodedPref) {
this.pref = pref;
this.formControl.setValue(pref.value);
}
get type() {
return this.pref.type;
}
@Input('update') @Required updateFunction: (
key: string,
pref: PrefValueType,
) => AsyncFailable<any>;
@Input() @Required name = '';
@Input() helpText = '';
@Input() validator?: ZodTypeAny = undefined;
constructor(private readonly errorService: ErrorService) {}
ngOnInit(): void {
this.subscribeUpdate();
}
getErrorMessage() {
if (this.formControl.errors) {
const errors = this.formControl.errors;
if (errors['error']) {
return errors['error'];
}
return 'Invalid value';
}
return '';
}
private syncValidator(control: AbstractControl): ValidationErrors | null {
if (!this.validator) return null;
const result = this.validator.safeParse(control.value);
if (!result.success) {
return { error: result.error.issues[0]?.message ?? 'Invalid value' };
}
return null;
}
private async updatePreference(value: PrefValueType) {
const result = await this.updateFunction(this.pref.key, value);
if (!HasFailed(result)) {
const message =
this.pref.type === 'string'
? `Updated ${this.name}`
: this.pref.type === 'number'
? `Updated ${this.name}`
: this.pref.type === 'boolean'
? value
? `Enabled ${this.name}`
: `Disabled ${this.name}`
: '';
this.errorService.success(message);
} else {
this.errorService.showFailure(result, this.logger);
}
}
@AutoUnsubscribe()
subscribeUpdate() {
return this.formControl.valueChanges
.pipe(
filter(() => this.formControl.errors === null),
Throttle(300),
)
.subscribe(this.updatePreference.bind(this));
}
}