Added redemptions page. Fixed some issues. Removed some instances of console.log().

This commit is contained in:
Tom
2025-01-13 23:37:31 +00:00
parent 7a7fb832a0
commit 04a50f6db0
39 changed files with 2342 additions and 1564 deletions

View File

@ -0,0 +1,24 @@
<mat-form-field>
<mat-label>Redeemable Action</mat-label>
<input
matInput
type="text"
placeholder="Pick a Redeemable Action"
aria-label="redeemable action"
[formControl]="formControl"
[matAutocomplete]="auto"
(blur)="blur()"
(input)="input()">
<mat-autocomplete #auto="matAutocomplete" [displayWith]="displayFn" (optionSelected)="select($event.option.value)">
@for (action of filteredActions; track action.name) {
<mat-option [value]="action">{{action.name}}</mat-option>
}
</mat-autocomplete>
@if (!search && formControl.invalid && (formControl.dirty || formControl.touched)) {
@for (error of errorMessageKeys; track $index) {
@if (formControl.hasError(error)) {
<small class="error">{{errorMessages[error]}}</small>
}
}
}
</mat-form-field>

View File

@ -0,0 +1,4 @@
.error {
display: block;
color: #ba1a1a;
}

View File

@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ActionDropdownComponent } from './action-dropdown.component';
describe('ActionDropdownComponent', () => {
let component: ActionDropdownComponent;
let fixture: ComponentFixture<ActionDropdownComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [ActionDropdownComponent]
})
.compileComponents();
fixture = TestBed.createComponent(ActionDropdownComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,90 @@
import { Component, EventEmitter, inject, input, Input, OnInit, Output } from '@angular/core';
import { FormControl, ReactiveFormsModule, Validators } from '@angular/forms';
import { MatAutocompleteModule } from '@angular/material/autocomplete';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input';
import { ActivatedRoute } from '@angular/router';
import RedeemableAction from '../../shared/models/redeemable_action';
@Component({
selector: 'action-dropdown',
imports: [MatAutocompleteModule, MatFormFieldModule, MatInputModule, ReactiveFormsModule],
templateUrl: './action-dropdown.component.html',
styleUrl: './action-dropdown.component.scss'
})
export class ActionDropdownComponent implements OnInit {
@Input() formControl = new FormControl<RedeemableAction | string | undefined>(undefined);
@Input() errorMessages: { [errorKey: string]: string } = {}
@Input() search: boolean = false;
@Input() actions: RedeemableAction[] = [];
@Input() action: string | undefined;
@Output() readonly actionChange = new EventEmitter<string>();
private readonly route = inject(ActivatedRoute);
errorMessageKeys: string[] = []
constructor() {
this.route.data.subscribe(data => {
if (!data['redeemableActions'])
return;
this.actions = data['redeemableActions'];
});
}
ngOnInit(): void {
this.errorMessageKeys = Object.keys(this.errorMessages);
if (!this.action)
return;
const action = this.actions.find(r => r.name == this.action);
this.formControl.setValue(action);
}
get filteredActions() {
const value = this.formControl.value;
if (typeof value == 'string') {
return this.actions.filter(r => r.name.toLowerCase().includes(value.toLowerCase()));
}
return this.actions;
}
select(event: RedeemableAction) {
this.actionChange.emit(event.name);
}
input() {
if (this.search && typeof this.formControl.value == 'string') {
this.actionChange.emit(this.formControl.value);
}
}
blur() {
if (!this.search && typeof this.formControl.value == 'string') {
const name = this.formControl.value;
const nameLower = name.toLowerCase();
let newValue: RedeemableAction | undefined = undefined;
const insenstiveActions = this.filteredActions.filter(a => a.name.toLowerCase() == nameLower);
if (insenstiveActions.length > 1) {
const sensitiveAction = insenstiveActions.find(a => a.name == name);
newValue = sensitiveAction ?? undefined;
} else if (insenstiveActions.length == 1) {
newValue = insenstiveActions[0];
}
if (newValue && newValue.name != this.formControl.value) {
this.formControl.setValue(newValue);
this.actionChange.emit(newValue.name);
} else if (!newValue)
this.actionChange.emit(undefined);
}
}
displayFn(value: any) {
return value?.name;
}
}

View File

@ -67,10 +67,6 @@ export class ActionsComponent implements OnInit {
}
});
this.client.subscribeToRequests('delete_redeemable_action', d => {
// if (d.request.nounce != null && d.request.nounce.startsWith(this.client.session_id)) {
// return;
// }
this.items = this.actions.filter(a => a.name != d.request.data.name);
});