Add conditional display logic to staff application form based on open/close status

This commit is contained in:
akastijn 2025-10-17 22:00:23 +02:00
parent 5eaeb3552a
commit ed9d41cdc6
2 changed files with 294 additions and 283 deletions

View File

@ -6,313 +6,320 @@
</div> </div>
</app-header> </app-header>
<main> <main>
<section class="darkmodeSection staff-application-container"> @if (staffApplicationsIsOpen()) {
<div class="form-container"> <section class="darkmodeSection staff-application-container">
<div class="pages"> <div class="form-container">
<!-- Welcome Page --> <div class="pages">
@if (currentPageIndex === 0) { <!-- Welcome Page -->
<section class="formPage"> @if (currentPageIndex === 0) {
<img ngSrc="/public/img/logos/logo.png" alt="Logo" height="319" width="550"/>
<h1>Moderator Application</h1>
<p>Thank you for your interest in becoming a moderator on our Minecraft server.</p>
<p>Please take your time to fill out this application thoroughly.</p>
<button mat-raised-button (click)="nextPage()">
Get Started
</button>
</section>
}
<!-- Confirmation Page -->
@if (currentPageIndex === 1) {
<section class="formPage">
<div class="description">
<p>You are logged in as <strong>{{ authService.username() }}</strong>. If this is the correct account
please continue</p>
<br>
<p><strong>Notice: </strong> Submitting a staff application is <strong>not</strong> an instant process.
We will review your application carefully and get back to you if we think you're a good fit.</p>
<p style="font-style: italic;">Applications that seem to have been made with
little to no effort will be automatically rejected.</p>
</div>
<button mat-raised-button (click)="nextPage()" [disabled]="authService.username() == null">
I, {{ authService.username() }}, understand and agree
</button>
</section>
}
<form [formGroup]="form">
<!-- Basic Information Page -->
@if (currentPageIndex === 2) {
<section class="formPage"> <section class="formPage">
<div class="description"> <img ngSrc="/public/img/logos/logo.png" alt="Logo" height="319" width="550"/>
<h2>Basic Information</h2> <h1>Moderator Application</h1>
<p>Thank you for your interest in becoming a moderator on our Minecraft server.</p>
<!-- Email --> <p>Please take your time to fill out this application thoroughly.</p>
<mat-form-field appearance="fill" style="width: 100%;"> <button mat-raised-button (click)="nextPage()">
<mat-label>Email</mat-label> Get Started
<input matInput
formControlName="email"
placeholder="Email">
@if (form.controls.email.invalid && form.controls.email.touched) {
<mat-error>
@if (form.controls.email.errors?.['required']) {
Email is required
} @else if (form.controls.email.errors?.['email']) {
Please enter a valid email address
}
</mat-error>
}
</mat-form-field>
@if (emailIsValid()) {
<div class="valid-email">
<ng-container matSuffix>
<mat-icon>check</mat-icon>
<span>You have validated your email previously.</span>
</ng-container>
</div>
} @else {
<div class="invalid-email">
<ng-container matSuffix>
<mat-icon>close</mat-icon>
<span>You have not used this email address before. Before going to the next page you will be asked to verify it.</span>
</ng-container>
</div>
}
<!-- Age -->
<mat-form-field appearance="fill" style="width: 100%;">
<mat-label>Age</mat-label>
<input matInput
formControlName="age"
placeholder="Age">
@if (form.controls.age.invalid && form.controls.age.touched) {
<mat-error>
@if (form.controls.age.errors?.['required']) {
Age is required
} @else if (form.controls.age.errors?.['min']) {
You must be at least 13 years old
} @else if (form.controls.age.errors?.['pattern']) {
Please enter a valid number
}
</mat-error>
}
</mat-form-field>
<!-- Discord Username -->
<mat-form-field appearance="fill" style="width: 100%;">
<mat-label>Discord Username</mat-label>
<input matInput
formControlName="discordUsername"
placeholder="Discord Username">
@if (form.controls.discordUsername.invalid && form.controls.discordUsername.touched) {
<mat-error>
Discord username is required
</mat-error>
}
</mat-form-field>
<!-- PC Requirements -->
<div class="checkbox-field">
<mat-checkbox formControlName="meetsRequirements">
I confirm that I meet the PC requirements (able to record video at 30fps 720p or higher, and able
to talk in voice chat)
</mat-checkbox>
@if (form.controls.meetsRequirements.invalid && form.controls.meetsRequirements.touched) {
<mat-error class="checkbox-error">
You must meet the PC requirements to apply
</mat-error>
}
</div>
<!-- Pronouns (Optional) -->
<mat-form-field appearance="fill" style="width: 100%;">
<mat-label>Pronouns (Optional)</mat-label>
<input matInput
formControlName="pronouns"
placeholder="Pronouns">
</mat-form-field>
</div>
<button mat-raised-button (click)="validateMailOrNextPage()"
[disabled]="form.controls.email.invalid || form.controls.age.invalid || form.controls.discordUsername.invalid || !form.controls.meetsRequirements.value">
Next
</button> </button>
</section> </section>
} }
<!-- Experience Page --> <!-- Confirmation Page -->
@if (currentPageIndex === 3) { @if (currentPageIndex === 1) {
<section class="formPage"> <section class="formPage">
<div class="description"> <div class="description">
<h2>Experience & Availability</h2> <p>You are logged in as <strong>{{ authService.username() }}</strong>. If this is the correct account
please continue</p>
<br>
<p><strong>Notice: </strong> Submitting a staff application is <strong>not</strong> an instant
process.
We will review your application carefully and get back to you if we think you're a good fit.</p>
<p style="font-style: italic;">Applications that seem to have been made with
little to no effort will be automatically rejected.</p>
</div>
<button mat-raised-button (click)="nextPage()" [disabled]="authService.username() == null">
I, {{ authService.username() }}, understand and agree
</button>
</section>
}
<!-- Join Date --> <form [formGroup]="form">
<mat-form-field appearance="fill" style="width: 100%;"> <!-- Basic Information Page -->
<mat-label>When did you join our server? (Estimate)</mat-label> @if (currentPageIndex === 2) {
<input matInput [matDatepicker]="picker" formControlName="joinDate"> <section class="formPage">
<mat-datepicker-toggle matIconSuffix [for]="picker"></mat-datepicker-toggle> <div class="description">
<mat-datepicker #picker></mat-datepicker> <h2>Basic Information</h2>
@if (form.controls.joinDate.invalid && form.controls.joinDate.touched) {
<mat-error> <!-- Email -->
Join date is required <mat-form-field appearance="fill" style="width: 100%;">
</mat-error> <mat-label>Email</mat-label>
<input matInput
formControlName="email"
placeholder="Email">
@if (form.controls.email.invalid && form.controls.email.touched) {
<mat-error>
@if (form.controls.email.errors?.['required']) {
Email is required
} @else if (form.controls.email.errors?.['email']) {
Please enter a valid email address
}
</mat-error>
}
</mat-form-field>
@if (emailIsValid()) {
<div class="valid-email">
<ng-container matSuffix>
<mat-icon>check</mat-icon>
<span>You have validated your email previously.</span>
</ng-container>
</div>
} @else {
<div class="invalid-email">
<ng-container matSuffix>
<mat-icon>close</mat-icon>
<span>You have not used this email address before. Before going to the next page you will be asked to verify it.</span>
</ng-container>
</div>
} }
</mat-form-field>
<!-- Weekly Playtime --> <!-- Age -->
<mat-form-field appearance="fill" style="width: 100%;"> <mat-form-field appearance="fill" style="width: 100%;">
<mat-label>Average expected playtime in a week (hours)</mat-label> <mat-label>Age</mat-label>
<input matInput <input matInput
formControlName="weeklyPlaytime" formControlName="age"
placeholder="Hours per week"> placeholder="Age">
@if (form.controls.weeklyPlaytime.invalid && form.controls.weeklyPlaytime.touched) { @if (form.controls.age.invalid && form.controls.age.touched) {
<mat-error> <mat-error>
@if (form.controls.weeklyPlaytime.errors?.['required']) { @if (form.controls.age.errors?.['required']) {
Weekly playtime is required Age is required
} @else if (form.controls.weeklyPlaytime.errors?.['min']) { } @else if (form.controls.age.errors?.['min']) {
Weekly playtime must be at least 1 hour You must be at least 13 years old
} } @else if (form.controls.age.errors?.['pattern']) {
</mat-error> Please enter a valid number
} }
</mat-form-field> </mat-error>
}
</mat-form-field>
<!-- Available Days --> <!-- Discord Username -->
<div class="field-container"> <mat-form-field appearance="fill" style="width: 100%;">
<label class="field-label">Available days for moderating:</label> <mat-label>Discord Username</mat-label>
<div class="days-container"> <input matInput
@for (day of availableDays; track day) { formControlName="discordUsername"
<div class="day-chip" [class.selected]="form.controls.availableDays.value.includes(day)" placeholder="Discord Username">
(click)="toggleDay(day)"> @if (form.controls.discordUsername.invalid && form.controls.discordUsername.touched) {
{{ day }} <mat-error>
</div> Discord username is required
</mat-error>
}
</mat-form-field>
<!-- PC Requirements -->
<div class="checkbox-field">
<mat-checkbox formControlName="meetsRequirements">
I confirm that I meet the PC requirements (able to record video at 30fps 720p or higher, and
able
to talk in voice chat)
</mat-checkbox>
@if (form.controls.meetsRequirements.invalid && form.controls.meetsRequirements.touched) {
<mat-error class="checkbox-error">
You must meet the PC requirements to apply
</mat-error>
} }
</div> </div>
@if (form.controls.availableDays.invalid && form.controls.availableDays.touched) {
<mat-error> <!-- Pronouns (Optional) -->
Please select at least one day <mat-form-field appearance="fill" style="width: 100%;">
</mat-error> <mat-label>Pronouns (Optional)</mat-label>
} <input matInput
formControlName="pronouns"
placeholder="Pronouns">
</mat-form-field>
</div> </div>
<button mat-raised-button (click)="validateMailOrNextPage()"
[disabled]="form.controls.email.invalid || form.controls.age.invalid || form.controls.discordUsername.invalid || !form.controls.meetsRequirements.value">
Next
</button>
</section>
}
<!-- Available Times --> <!-- Experience Page -->
<mat-form-field appearance="fill" style="width: 100%;"> @if (currentPageIndex === 3) {
<mat-label>Available times (Your timezone: {{ userTimezone }})</mat-label> <section class="formPage">
<textarea matInput <div class="description">
formControlName="availableTimes" <h2>Experience & Availability</h2>
placeholder="e.g., 6PM-10PM weekdays, 2PM-8PM weekends"
rows="2"></textarea>
@if (form.controls.availableTimes.invalid && form.controls.availableTimes.touched) {
<mat-error>
Available times are required
</mat-error>
}
</mat-form-field>
</div>
<button mat-raised-button (click)="nextPage()"
[disabled]="form.controls.joinDate.invalid || form.controls.weeklyPlaytime.invalid || form.controls.availableDays.invalid || form.controls.availableTimes.invalid">
Next
</button>
</section>
}
<!-- Qualifications Page --> <!-- Join Date -->
@if (currentPageIndex === 4) { <mat-form-field appearance="fill" style="width: 100%;">
<section class="formPage"> <mat-label>When did you join our server? (Estimate)</mat-label>
<div class="description"> <input matInput [matDatepicker]="picker" formControlName="joinDate">
<h2>Qualifications & Expectations</h2> <mat-datepicker-toggle matIconSuffix [for]="picker"></mat-datepicker-toggle>
<mat-datepicker #picker></mat-datepicker>
@if (form.controls.joinDate.invalid && form.controls.joinDate.touched) {
<mat-error>
Join date is required
</mat-error>
}
</mat-form-field>
<!-- Previous Experience --> <!-- Weekly Playtime -->
<mat-form-field appearance="fill" style="width: 100%;"> <mat-form-field appearance="fill" style="width: 100%;">
<mat-label>Previous experience (here or in other relevant places)</mat-label> <mat-label>Average expected playtime in a week (hours)</mat-label>
<textarea matInput <input matInput
formControlName="previousExperience" formControlName="weeklyPlaytime"
placeholder="Describe your previous experience" placeholder="Hours per week">
rows="4"></textarea> @if (form.controls.weeklyPlaytime.invalid && form.controls.weeklyPlaytime.touched) {
@if (form.controls.previousExperience.invalid && form.controls.previousExperience.touched) { <mat-error>
<mat-error> @if (form.controls.weeklyPlaytime.errors?.['required']) {
@if (form.controls.previousExperience.errors?.['required']) { Weekly playtime is required
Previous experience is required } @else if (form.controls.weeklyPlaytime.errors?.['min']) {
} @else if (form.controls.previousExperience.errors?.['minlength']) { Weekly playtime must be at least 1 hour
Please provide more details (at least 10 characters) }
</mat-error>
}
</mat-form-field>
<!-- Available Days -->
<div class="field-container">
<label class="field-label">Available days for moderating:</label>
<div class="days-container">
@for (day of availableDays; track day) {
<div class="day-chip" [class.selected]="form.controls.availableDays.value.includes(day)"
(click)="toggleDay(day)">
{{ day }}
</div>
} }
</mat-error> </div>
} @if (form.controls.availableDays.invalid && form.controls.availableDays.touched) {
</mat-form-field> <mat-error>
Please select at least one day
</mat-error>
}
</div>
<!-- Plugin Experience --> <!-- Available Times -->
<mat-form-field appearance="fill" style="width: 100%;"> <mat-form-field appearance="fill" style="width: 100%;">
<mat-label>Experience with plugins that players use on our server</mat-label> <mat-label>Available times (Your timezone: {{ userTimezone }})</mat-label>
<textarea matInput <textarea matInput
formControlName="pluginExperience" formControlName="availableTimes"
placeholder="Describe your experience with our server plugins" placeholder="e.g., 6PM-10PM weekdays, 2PM-8PM weekends"
rows="4"></textarea> rows="2"></textarea>
@if (form.controls.pluginExperience.invalid && form.controls.pluginExperience.touched) { @if (form.controls.availableTimes.invalid && form.controls.availableTimes.touched) {
<mat-error> <mat-error>
@if (form.controls.pluginExperience.errors?.['required']) { Available times are required
Plugin experience is required </mat-error>
} @else if (form.controls.pluginExperience.errors?.['minlength']) { }
Please provide more details (at least 10 characters) </mat-form-field>
} </div>
</mat-error> <button mat-raised-button (click)="nextPage()"
} [disabled]="form.controls.joinDate.invalid || form.controls.weeklyPlaytime.invalid || form.controls.availableDays.invalid || form.controls.availableTimes.invalid">
</mat-form-field> Next
</button>
</section>
}
<!-- Moderator Expectations --> <!-- Qualifications Page -->
<mat-form-field appearance="fill" style="width: 100%;"> @if (currentPageIndex === 4) {
<mat-label>What do you believe the expectations of a moderator are?</mat-label> <section class="formPage">
<textarea matInput <div class="description">
formControlName="moderatorExpectations" <h2>Qualifications & Expectations</h2>
placeholder="Describe what you think a moderator should do"
rows="4"></textarea>
@if (form.controls.moderatorExpectations.invalid && form.controls.moderatorExpectations.touched) {
<mat-error>
@if (form.controls.moderatorExpectations.errors?.['required']) {
Moderator expectations are required
} @else if (form.controls.moderatorExpectations.errors?.['minlength']) {
Please provide more details (at least 10 characters)
}
</mat-error>
}
</mat-form-field>
<!-- Additional Information --> <!-- Previous Experience -->
<mat-form-field appearance="fill" style="width: 100%;"> <mat-form-field appearance="fill" style="width: 100%;">
<mat-label>Additional Information (Optional)</mat-label> <mat-label>Previous experience (here or in other relevant places)</mat-label>
<textarea matInput <textarea matInput
formControlName="additionalInfo" formControlName="previousExperience"
placeholder="Any additional information you'd like to share" placeholder="Describe your previous experience"
rows="4"></textarea> rows="4"></textarea>
</mat-form-field> @if (form.controls.previousExperience.invalid && form.controls.previousExperience.touched) {
</div> <mat-error>
<button mat-raised-button (click)="onSubmit()" @if (form.controls.previousExperience.errors?.['required']) {
[disabled]="isFormInvalid()"> Previous experience is required
Submit Application } @else if (form.controls.previousExperience.errors?.['minlength']) {
</button> Please provide more details (at least 10 characters)
</section> }
} </mat-error>
</form> }
</div> </mat-form-field>
<!-- Navigation dots --> <!-- Plugin Experience -->
@if (totalPages.length > 1) { <mat-form-field appearance="fill" style="width: 100%;">
<div class="form-navigation"> <mat-label>Experience with plugins that players use on our server</mat-label>
<button mat-icon-button class="nav-button" (click)="previousPage()" [disabled]="isFirstPage()"> <textarea matInput
<mat-icon>navigate_before</mat-icon> formControlName="pluginExperience"
</button> placeholder="Describe your experience with our server plugins"
rows="4"></textarea>
@if (form.controls.pluginExperience.invalid && form.controls.pluginExperience.touched) {
<mat-error>
@if (form.controls.pluginExperience.errors?.['required']) {
Plugin experience is required
} @else if (form.controls.pluginExperience.errors?.['minlength']) {
Please provide more details (at least 10 characters)
}
</mat-error>
}
</mat-form-field>
@for (i of totalPages; track i) { <!-- Moderator Expectations -->
<div <mat-form-field appearance="fill" style="width: 100%;">
class="nav-dot" <mat-label>What do you believe the expectations of a moderator are?</mat-label>
[class.active]="i === currentPageIndex" <textarea matInput
(click)="goToPage(i)"> formControlName="moderatorExpectations"
</div> placeholder="Describe what you think a moderator should do"
} rows="4"></textarea>
@if (form.controls.moderatorExpectations.invalid && form.controls.moderatorExpectations.touched) {
<mat-error>
@if (form.controls.moderatorExpectations.errors?.['required']) {
Moderator expectations are required
} @else if (form.controls.moderatorExpectations.errors?.['minlength']) {
Please provide more details (at least 10 characters)
}
</mat-error>
}
</mat-form-field>
<button mat-icon-button class="nav-button" (click)="nextPage()" [disabled]="isLastPage()"> <!-- Additional Information -->
<mat-icon>navigate_next</mat-icon> <mat-form-field appearance="fill" style="width: 100%;">
</button> <mat-label>Additional Information (Optional)</mat-label>
<textarea matInput
formControlName="additionalInfo"
placeholder="Any additional information you'd like to share"
rows="4"></textarea>
</mat-form-field>
</div>
<button mat-raised-button (click)="onSubmit()"
[disabled]="isFormInvalid()">
Submit Application
</button>
</section>
}
</form>
</div> </div>
}
</div> <!-- Navigation dots -->
</section> @if (totalPages.length > 1) {
<div class="form-navigation">
<button mat-icon-button class="nav-button" (click)="previousPage()" [disabled]="isFirstPage()">
<mat-icon>navigate_before</mat-icon>
</button>
@for (i of totalPages; track i) {
<div
class="nav-dot"
[class.active]="i === currentPageIndex"
(click)="goToPage(i)">
</div>
}
<button mat-icon-button class="nav-button" (click)="nextPage()" [disabled]="isLastPage()">
<mat-icon>navigate_next</mat-icon>
</button>
</div>
}
</div>
</section>
} @else {
<h1>Staff applications are closed at this time. Please keep an eye on our announcement channel in Discord to see
when it opens!</h1>
}
</main> </main>
</div> </div>

View File

@ -68,6 +68,7 @@ export class StaffApplicationComponent implements OnInit, OnDestroy, AfterViewIn
protected availableDays: string[] = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']; protected availableDays: string[] = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'];
protected selectedDays: string[] = []; protected selectedDays: string[] = [];
protected userTimezone: string = Intl.DateTimeFormat().resolvedOptions().timeZone; protected userTimezone: string = Intl.DateTimeFormat().resolvedOptions().timeZone;
protected staffApplicationsIsOpen = signal<boolean>(false)
constructor( constructor(
@ -151,6 +152,9 @@ export class StaffApplicationComponent implements OnInit, OnDestroy, AfterViewIn
} }
ngOnInit() { ngOnInit() {
this.staffApplicationService.getStaffApplicationsIsOpen().subscribe(isOpen => {
this.staffApplicationsIsOpen.set(isOpen)
})
const uuid = this.authService.getUuid(); const uuid = this.authService.getUuid();
if (uuid === null) { if (uuid === null) {
alert('Error retrieving token, please relog on the website and try again') alert('Error retrieving token, please relog on the website and try again')