AI Implementation feature(887): Admin Area General Settings and Categories 1.05 (#27)
This commit was merged in pull request #27.
This commit is contained in:
@@ -7,8 +7,10 @@ import { BootstrapService } from '../../core/services/bootstrap.service';
|
||||
import { MarkdownService } from '../../core/services/markdown.service';
|
||||
import { AdminCategoriesComponent } from './categories/categories.component';
|
||||
import {
|
||||
datetimeMessage,
|
||||
deriveEventState,
|
||||
endAfterStartValidator,
|
||||
isoDatetimeValidator,
|
||||
normalizePageTitle,
|
||||
pageTitleMessage,
|
||||
toDatetimeLocal,
|
||||
@@ -91,14 +93,34 @@ import {
|
||||
|
||||
<label for="eventStartUtc">Event start (UTC)</label>
|
||||
<div>
|
||||
<input id="eventStartUtc" type="datetime-local" formControlName="eventStartUtc" data-testid="general-eventStart" />
|
||||
<input
|
||||
id="eventStartUtc"
|
||||
type="datetime-local"
|
||||
formControlName="eventStartUtc"
|
||||
data-testid="general-eventStart"
|
||||
[attr.aria-invalid]="showEventStartError() ? 'true' : null"
|
||||
[attr.aria-describedby]="showEventStartError() ? 'general-eventStart-error' : null"
|
||||
/>
|
||||
@if (showEventStartError()) {
|
||||
<div class="field-error" id="general-eventStart-error" data-testid="general-eventStart-error">{{ eventStartMessage() }}</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<label for="eventEndUtc">Event end (UTC)</label>
|
||||
<div>
|
||||
<input id="eventEndUtc" type="datetime-local" formControlName="eventEndUtc" data-testid="general-eventEnd" />
|
||||
<input
|
||||
id="eventEndUtc"
|
||||
type="datetime-local"
|
||||
formControlName="eventEndUtc"
|
||||
data-testid="general-eventEnd"
|
||||
[attr.aria-invalid]="showEventEndError() || (form.controls.eventEndUtc.touched && !!form.error?.['endBeforeStart']) ? 'true' : null"
|
||||
[attr.aria-describedby]="(showEventEndError() || (form.controls.eventEndUtc.touched && !!form.error?.['endBeforeStart'])) ? 'general-eventEnd-error general-endBeforeStart' : null"
|
||||
/>
|
||||
@if (showEventEndError()) {
|
||||
<div class="field-error" id="general-eventEnd-error" data-testid="general-eventEnd-error">{{ eventEndMessage() }}</div>
|
||||
}
|
||||
@if (form.controls.eventEndUtc.touched && form.error?.['endBeforeStart']) {
|
||||
<div class="field-error" data-testid="general-endBeforeStart">Event end must be after event start.</div>
|
||||
<div class="field-error" id="general-endBeforeStart" data-testid="general-endBeforeStart">Event end must be after event start.</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
@@ -179,14 +201,22 @@ export class AdminGeneralComponent implements OnInit {
|
||||
private readonly pageTitleInvalid = signal<boolean>(false);
|
||||
private readonly pageTitleTouchedOrDirty = signal<boolean>(false);
|
||||
|
||||
private readonly eventStartValue = signal<string>('');
|
||||
private readonly eventStartInvalid = signal<boolean>(false);
|
||||
private readonly eventStartTouchedOrDirty = signal<boolean>(false);
|
||||
|
||||
private readonly eventEndValue = signal<string>('');
|
||||
private readonly eventEndInvalid = signal<boolean>(false);
|
||||
private readonly eventEndTouchedOrDirty = signal<boolean>(false);
|
||||
|
||||
readonly form = this.fb.nonNullable.group(
|
||||
{
|
||||
pageTitle: this.fb.nonNullable.control('', [Validators.required, Validators.maxLength(120), this.pageTitleNotBlankValidator()]),
|
||||
logo: this.fb.nonNullable.control(''),
|
||||
welcomeMarkdown: this.fb.nonNullable.control(''),
|
||||
themeKey: this.fb.nonNullable.control('classic'),
|
||||
eventStartUtc: this.fb.nonNullable.control(''),
|
||||
eventEndUtc: this.fb.nonNullable.control(''),
|
||||
eventStartUtc: this.fb.nonNullable.control('', [isoDatetimeValidator]),
|
||||
eventEndUtc: this.fb.nonNullable.control('', [isoDatetimeValidator]),
|
||||
defaultChallengeIp: this.fb.nonNullable.control('', [Validators.required]),
|
||||
registrationsEnabled: this.fb.nonNullable.control(false),
|
||||
},
|
||||
@@ -210,6 +240,22 @@ export class AdminGeneralComponent implements OnInit {
|
||||
pageTitleMessage(this.pageTitleValue(), this.form.controls.pageTitle.errors),
|
||||
);
|
||||
|
||||
readonly showEventStartError = computed(
|
||||
() => this.eventStartTouchedOrDirty() && this.eventStartInvalid(),
|
||||
);
|
||||
|
||||
readonly eventStartMessage = computed(() =>
|
||||
datetimeMessage('Event start', this.eventStartValue(), this.form.controls.eventStartUtc.errors),
|
||||
);
|
||||
|
||||
readonly showEventEndError = computed(
|
||||
() => this.eventEndTouchedOrDirty() && this.eventEndInvalid(),
|
||||
);
|
||||
|
||||
readonly eventEndMessage = computed(() =>
|
||||
datetimeMessage('Event end', this.eventEndValue(), this.form.controls.eventEndUtc.errors),
|
||||
);
|
||||
|
||||
constructor() {
|
||||
this.form.controls.welcomeMarkdown.valueChanges
|
||||
.pipe(takeUntilDestroyed(this.destroyRef))
|
||||
@@ -231,6 +277,40 @@ export class AdminGeneralComponent implements OnInit {
|
||||
this.pageTitleInvalid.set(pt.invalid);
|
||||
this.pageTitleTouchedOrDirty.set(pt.touched || pt.dirty);
|
||||
});
|
||||
|
||||
const es = this.form.controls.eventStartUtc;
|
||||
this.eventStartValue.set(es.value);
|
||||
this.eventStartInvalid.set(es.invalid);
|
||||
this.eventStartTouchedOrDirty.set(es.touched || es.dirty);
|
||||
es.valueChanges
|
||||
.pipe(takeUntilDestroyed(this.destroyRef))
|
||||
.subscribe((v) => {
|
||||
this.eventStartValue.set(v);
|
||||
this.eventStartTouchedOrDirty.set(es.touched || es.dirty);
|
||||
});
|
||||
es.statusChanges
|
||||
.pipe(takeUntilDestroyed(this.destroyRef))
|
||||
.subscribe(() => {
|
||||
this.eventStartInvalid.set(es.invalid);
|
||||
this.eventStartTouchedOrDirty.set(es.touched || es.dirty);
|
||||
});
|
||||
|
||||
const ee = this.form.controls.eventEndUtc;
|
||||
this.eventEndValue.set(ee.value);
|
||||
this.eventEndInvalid.set(ee.invalid);
|
||||
this.eventEndTouchedOrDirty.set(ee.touched || ee.dirty);
|
||||
ee.valueChanges
|
||||
.pipe(takeUntilDestroyed(this.destroyRef))
|
||||
.subscribe((v) => {
|
||||
this.eventEndValue.set(v);
|
||||
this.eventEndTouchedOrDirty.set(ee.touched || ee.dirty);
|
||||
});
|
||||
ee.statusChanges
|
||||
.pipe(takeUntilDestroyed(this.destroyRef))
|
||||
.subscribe(() => {
|
||||
this.eventEndInvalid.set(ee.invalid);
|
||||
this.eventEndTouchedOrDirty.set(ee.touched || ee.dirty);
|
||||
});
|
||||
}
|
||||
|
||||
async ngOnInit(): Promise<void> {
|
||||
@@ -272,6 +352,14 @@ export class AdminGeneralComponent implements OnInit {
|
||||
this.form.controls.pageTitle.markAsUntouched();
|
||||
this.form.controls.pageTitle.markAsPristine();
|
||||
this.pageTitleTouchedOrDirty.set(false);
|
||||
|
||||
this.form.controls.eventStartUtc.markAsUntouched();
|
||||
this.form.controls.eventStartUtc.markAsPristine();
|
||||
this.eventStartTouchedOrDirty.set(false);
|
||||
|
||||
this.form.controls.eventEndUtc.markAsUntouched();
|
||||
this.form.controls.eventEndUtc.markAsPristine();
|
||||
this.eventEndTouchedOrDirty.set(false);
|
||||
}
|
||||
|
||||
async onSubmit(): Promise<void> {
|
||||
|
||||
Reference in New Issue
Block a user