Fixing bugs
Refactoring scanning Adding data connections
This commit is contained in:
parent
2358ef1c96
commit
35ddedb5c3
|
|
@ -61,7 +61,7 @@ public class TicketManager : ITicketManager
|
|||
return TicketValidity.Expired;
|
||||
}
|
||||
|
||||
if (@event.Date != DateTime.Today) return TicketValidity.Invalid;
|
||||
if (@event.Date.Day != DateTime.Today.Day) return TicketValidity.Invalid;
|
||||
|
||||
if (DateTime.Now.Hour < @event.Date.Hour - 2)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@ namespace models.Enumerations;
|
|||
|
||||
public enum TicketValidity
|
||||
{
|
||||
Valid,
|
||||
Expired,
|
||||
Early,
|
||||
Invalid
|
||||
Invalid,
|
||||
Valid,
|
||||
}
|
||||
|
|
@ -1,9 +1,11 @@
|
|||
<div class="card">
|
||||
<label for="events">Event</label>
|
||||
<select name="Events" id="events">
|
||||
<option>Select...</option>
|
||||
<div class="card card-fit-parent">
|
||||
<div class="row row-space-between">
|
||||
<label class="label">Event</label>
|
||||
<select #event name="Events" class="select" (change)="click(event.value)">
|
||||
<option value="">Select...</option>
|
||||
@for(event of events$(); track event.id) {
|
||||
<option [value]="event.id">{{event.name}}</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,3 +0,0 @@
|
|||
label {
|
||||
padding-right: 15px;
|
||||
}
|
||||
|
|
@ -1,17 +1,27 @@
|
|||
import {Component, inject, OnInit} from '@angular/core';
|
||||
import {Component, inject, OnInit, signal, WritableSignal} from '@angular/core';
|
||||
import {EventService} from '../../services/event.service';
|
||||
import {ReactiveFormsModule} from '@angular/forms';
|
||||
|
||||
@Component({
|
||||
selector: 'app-event-browser',
|
||||
imports: [],
|
||||
imports: [
|
||||
ReactiveFormsModule
|
||||
],
|
||||
templateUrl: './event-browser.component.html',
|
||||
styleUrl: './event-browser.component.scss'
|
||||
})
|
||||
export class EventBrowserComponent implements OnInit {
|
||||
private eventService = inject(EventService);
|
||||
public events$ = this.eventService.events$;
|
||||
public selectedEventId!: string;
|
||||
public selectedEventId$: WritableSignal<string> = signal('');
|
||||
|
||||
public ngOnInit() {
|
||||
this.eventService.searchAllEvents();
|
||||
}
|
||||
|
||||
public click(eventId: string): void {
|
||||
this.selectedEventId = eventId;
|
||||
this.selectedEventId$.set(eventId);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,12 +2,12 @@ import {Component, inject} from '@angular/core';
|
|||
import {TicketService} from '../../services/ticket.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-ticket',
|
||||
selector: 'app-generated-ticket',
|
||||
imports: [],
|
||||
templateUrl: './ticket.component.html',
|
||||
styleUrl: './ticket.component.scss'
|
||||
templateUrl: './generated-ticket.component.html',
|
||||
styleUrl: './generated-ticket.component.scss'
|
||||
})
|
||||
export class TicketComponent {
|
||||
export class GeneratedTicketComponent {
|
||||
private ticket = inject(TicketService);
|
||||
public qrCode = this.ticket.dataSignal$;
|
||||
}
|
||||
|
|
@ -1,45 +1,45 @@
|
|||
<div class="card">
|
||||
<h3>Patron Information</h3>
|
||||
<div class="column">
|
||||
<span class="row row-space-between">
|
||||
<label>First Name</label>
|
||||
<input [formControl]="firstName" type="text"/>
|
||||
</span>
|
||||
<span class="row row-space-between">
|
||||
<label>Middle Name</label>
|
||||
<input [formControl]="middleName" type="text"/>
|
||||
</span>
|
||||
<span class="row row-space-between">
|
||||
<label>Last Name</label>
|
||||
<input [formControl]="lastName" type="text"/>
|
||||
</span>
|
||||
<span class="row row-space-between">
|
||||
<label>Email</label>
|
||||
<input [formControl]="email" type="text"/>
|
||||
</span>
|
||||
<span class="row row-space-between">
|
||||
<label>Phone</label>
|
||||
<input [formControl]="phoneNumber" type="text"/>
|
||||
</span>
|
||||
<span class="row row-space-between">
|
||||
<label>Address</label>
|
||||
<input [formControl]="addressOne" type="text"/>
|
||||
</span>
|
||||
<span class="row row-space-between">
|
||||
<label>Address</label>
|
||||
<input [formControl]="addressTwo" type="text"/>
|
||||
</span>
|
||||
<span class="row row-space-between">
|
||||
<label>City</label>
|
||||
<input [formControl]="city" type="text"/>
|
||||
</span>
|
||||
<span class="row row-space-between">
|
||||
<label>State</label>
|
||||
<input [formControl]="state" type="text"/>
|
||||
</span>
|
||||
<span class="row row-space-between">
|
||||
<label>Zip</label>
|
||||
<input [formControl]="zip" type="text"/>
|
||||
</span>
|
||||
<div class="row row-space-between row-bottom-margin">
|
||||
<label class="label" for="firstName">First Name</label>
|
||||
<input id="firstName" [formControl]="firstName" type="text" class="input"/>
|
||||
</div>
|
||||
<div class="row row-space-between row-bottom-margin">
|
||||
<label class="label" for="middleName">Middle Name</label>
|
||||
<input id="middleName" [formControl]="middleName" type="text" class="input"/>
|
||||
</div>
|
||||
<div class="row row-space-between row-bottom-margin">
|
||||
<label class="label" for='lastName'>Last Name</label>
|
||||
<input id="lastName" [formControl]="lastName" type="text" class="input"/>
|
||||
</div>
|
||||
<div class="row row-space-between row-bottom-margin">
|
||||
<label class="label" for="email">Email</label>
|
||||
<input id="email" [formControl]="email" type="text" class="input"/>
|
||||
</div>
|
||||
<div class="row row-space-between row-bottom-margin">
|
||||
<label class="label" for="phoneNumber">Phone</label>
|
||||
<input id="phoneNumber" [formControl]="phoneNumber" type="text" class="input"/>
|
||||
</div>
|
||||
<div class="row row-space-between row-bottom-margin">
|
||||
<label class="label" for="addressOne">Address</label>
|
||||
<input id="addressOne" [formControl]="addressOne" type="text" class="input"/>
|
||||
</div>
|
||||
<div class="row row-space-between row-bottom-margin">
|
||||
<label class="label" for="addressTwo">Address</label>
|
||||
<input id="addressTwo" [formControl]="addressTwo" type="text" class="input"/>
|
||||
</div>
|
||||
<div class="row row-space-between row-bottom-margin">
|
||||
<label class="label" for="city">City</label>
|
||||
<input id="city" [formControl]="city" type="text" class="input"/>
|
||||
</div>
|
||||
<div class="row row-space-between row-bottom-margin">
|
||||
<label class="label" for="state">State</label>
|
||||
<input id="state" [formControl]="state" type="text" class="input"/>
|
||||
</div>
|
||||
<div class="row row-space-between row-bottom-margin">
|
||||
<label class="label" for="zip">Zip</label>
|
||||
<input id="zip" [formControl]="zip" type="text" class="input"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,3 +0,0 @@
|
|||
label {
|
||||
padding-right: 15px;
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
import { Component } from '@angular/core';
|
||||
import {Component} from '@angular/core';
|
||||
import {FormControl, ReactiveFormsModule, Validators} from '@angular/forms';
|
||||
import {Patron} from '../../../models/core/patron';
|
||||
|
||||
@Component({
|
||||
selector: 'app-patron-info',
|
||||
|
|
@ -10,14 +11,29 @@ import {FormControl, ReactiveFormsModule, Validators} from '@angular/forms';
|
|||
styleUrl: './patron-info.component.scss'
|
||||
})
|
||||
export class PatronInfoComponent {
|
||||
public firstName = new FormControl('', [Validators.required]);
|
||||
public firstName = new FormControl('', {nonNullable: true, validators: [Validators.required]});
|
||||
public middleName = new FormControl('');
|
||||
public lastName = new FormControl('', [Validators.required]);
|
||||
public email = new FormControl('', [Validators.required]);
|
||||
public lastName = new FormControl('', {nonNullable: true, validators: [Validators.required]});
|
||||
public email = new FormControl('', {nonNullable: true, validators: [Validators.required]});
|
||||
public phoneNumber = new FormControl('');
|
||||
public addressOne = new FormControl('', [Validators.required]);
|
||||
public addressOne = new FormControl('', {nonNullable: true, validators: [Validators.required]});
|
||||
public addressTwo = new FormControl('');
|
||||
public city = new FormControl('', [Validators.required]);
|
||||
public state = new FormControl('', [Validators.required]);
|
||||
public zip = new FormControl('', [Validators.required]);
|
||||
public city = new FormControl('', {nonNullable: true, validators: [Validators.required]});
|
||||
public state = new FormControl('', {nonNullable: true, validators: [Validators.required]});
|
||||
public zip = new FormControl('', {nonNullable: true, validators: [Validators.required]});
|
||||
|
||||
public buildPatron(): Patron {
|
||||
return {
|
||||
firstName: this.firstName.value,
|
||||
middleName: this.middleName.value,
|
||||
lastName: this.lastName.value,
|
||||
email: this.email.value,
|
||||
phoneNumber: this.phoneNumber.value,
|
||||
addressOne: this.addressOne.value,
|
||||
addressTwo: this.addressTwo.value,
|
||||
city: this.city.value,
|
||||
state: this.state.value,
|
||||
zip: this.zip.value,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,57 +1,21 @@
|
|||
@if (ticketValidity() !== TicketValidity.Invalid && ticketType() !== TicketTypeEnum.Null) {
|
||||
<div class="card column">
|
||||
@if (ticketSearch$() != null) {
|
||||
<div class="card">
|
||||
@if (ticketValidity() == TicketValidity.Valid) {
|
||||
<img ngSrc="pass.svg" width="100px" height="100px" alt="Ticket Valid"/>
|
||||
<span>Valid</span>
|
||||
} @else {
|
||||
<img ngSrc="fail.svg" width="100px" height="100px" alt="Ticket Invalid"/>
|
||||
<span>Invalid</span>
|
||||
}
|
||||
<!-- Show Validity, If Valid Show Ticket Type and Indicate Season -->
|
||||
<div class="column">
|
||||
<div class="column">
|
||||
<img [src]="getValidityImage()" width="100px" height="100px" [alt]="getValidityText()"/>
|
||||
<span class="row">{{getValidityText()}}</span>
|
||||
</div>
|
||||
@if (ticketValidity() == TicketValidity.Valid) {
|
||||
<div class="card">
|
||||
@switch (ticketType()){
|
||||
@case (TicketTypeEnum.Family) {
|
||||
<img ngSrc="group.svg" width="25px" height="25px" alt="Family"/>
|
||||
<span>Family</span>
|
||||
}
|
||||
@case (TicketTypeEnum.FamilySeason) {
|
||||
<img ngSrc="group.svg" width="25px" height="25px" alt="Family"/>
|
||||
<span>Family</span>
|
||||
}
|
||||
@case (TicketTypeEnum.Single) {
|
||||
<img ngSrc="single.svg" width="25px" height="25px" alt="Single"/>
|
||||
<span>Single</span>
|
||||
}
|
||||
@case (TicketTypeEnum.SingleSeason) {
|
||||
<img ngSrc="single.svg" width="25px" height="25px" alt="Single"/>
|
||||
<span>Single</span>
|
||||
}
|
||||
@case (TicketTypeEnum.Senior) {
|
||||
<img ngSrc="senior.svg" width="25px" height="25px" alt="Senior"/>
|
||||
<span>Senior</span>
|
||||
}
|
||||
@case (TicketTypeEnum.SeniorSeason) {
|
||||
<img ngSrc="senior.svg" width="25px" height="25px" alt="Senior"/>
|
||||
<span>Senior</span>
|
||||
@if(ticketValidity() === TicketValidity.Valid) {
|
||||
<div class="column">
|
||||
<img [src]="getTypeImage()" width="50px" height="50px" [alt]="getTypeText()"/>
|
||||
<span class="row">{{getTypeText()}}</span>
|
||||
</div>
|
||||
@if(IsSeasonTicket(ticketType())) {
|
||||
<img src="season.svg" width="50px" height="50px" alt="Season Ticket"/>
|
||||
<span class="row">Seasonal</span>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
<div class="card">
|
||||
@if (ticketType() !== TicketTypeEnum.FamilySeason) {
|
||||
<img ngSrc="group.svg" width="25px" height="25px" alt="Family"/>
|
||||
<span>Season</span>
|
||||
}
|
||||
@if (ticketType() !== TicketTypeEnum.SingleSeason) {
|
||||
<img ngSrc="single.svg" width="25px" height="25px" alt="Single"/>
|
||||
<span>Season</span>
|
||||
}
|
||||
@if (ticketType() !== TicketTypeEnum.SeniorSeason) {
|
||||
<img ngSrc="single.svg" width="25px" height="25px" alt="Single"/>
|
||||
<span>Season</span>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,11 @@
|
|||
import {Component, inject} from '@angular/core';
|
||||
import {TicketValidity} from '../../../models/enums/ticket-validity.enum';
|
||||
import {TicketTypeEnum} from '../../../models/enums/ticket-type.enum';
|
||||
import {IsSeasonTicket, TicketTypeEnum} from '../../../models/enums/ticket-type.enum';
|
||||
import {ScanService} from '../../services/scan.service';
|
||||
import {NgOptimizedImage} from '@angular/common';
|
||||
|
||||
@Component({
|
||||
selector: 'app-scan-result',
|
||||
imports: [
|
||||
NgOptimizedImage
|
||||
],
|
||||
imports: [],
|
||||
templateUrl: './scan-result.component.html',
|
||||
styleUrl: './scan-result.component.scss'
|
||||
})
|
||||
|
|
@ -16,6 +13,61 @@ export class ScanResultComponent {
|
|||
private scan = inject(ScanService);
|
||||
public ticketValidity = this.scan.ticketValid$;
|
||||
public ticketType = this.scan.ticketType$;
|
||||
public ticketSearch$ = this.scan.ticketSearch$;
|
||||
protected readonly TicketValidity = TicketValidity;
|
||||
protected readonly TicketTypeEnum = TicketTypeEnum;
|
||||
protected readonly IsSeasonTicket = IsSeasonTicket;
|
||||
|
||||
public getValidityText(): string {
|
||||
switch (this.ticketValidity()) {
|
||||
case TicketValidity.Valid:
|
||||
return 'Valid';
|
||||
case TicketValidity.Expired:
|
||||
return 'Expired';
|
||||
case TicketValidity.Early:
|
||||
return 'Early';
|
||||
default:
|
||||
return 'Invalid';
|
||||
}
|
||||
}
|
||||
|
||||
public getValidityImage(): string {
|
||||
switch (this.ticketValidity()) {
|
||||
case TicketValidity.Valid:
|
||||
return 'pass.svg';
|
||||
default:
|
||||
return 'fail.svg';
|
||||
}
|
||||
}
|
||||
|
||||
public getTypeImage(): string {
|
||||
switch (this.ticketType()) {
|
||||
case TicketTypeEnum.SingleSeason:
|
||||
case TicketTypeEnum.Single:
|
||||
return 'single.svg';
|
||||
case TicketTypeEnum.FamilySeason:
|
||||
case TicketTypeEnum.Family:
|
||||
return 'group.svg';
|
||||
case TicketTypeEnum.SeniorSeason:
|
||||
case TicketTypeEnum.Senior:
|
||||
return 'senior.svg';
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
public getTypeText(): string {
|
||||
switch (this.ticketType()) {
|
||||
case TicketTypeEnum.SingleSeason:
|
||||
case TicketTypeEnum.Single:
|
||||
return 'Single Ticket';
|
||||
case TicketTypeEnum.FamilySeason:
|
||||
case TicketTypeEnum.Family:
|
||||
return 'Family Ticket';
|
||||
case TicketTypeEnum.SeniorSeason:
|
||||
case TicketTypeEnum.Senior:
|
||||
return 'Senior Ticket';
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
<div class="card">
|
||||
<label for="seasons">Season</label>
|
||||
<select name="Seasons" id="seasons">
|
||||
<option>No Season</option>
|
||||
<div class="card card-fit-parent">
|
||||
<div class="row row-space-between">
|
||||
<label class="label">Season</label>
|
||||
<select #season name="Seasons" class="select" (change)="click(season.value)">
|
||||
<option value="">No Season</option>
|
||||
@for(season of seasons$(); track season.id) {
|
||||
<option [value]="season.id">{{season.name}}</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,3 +0,0 @@
|
|||
label {
|
||||
padding-right: 15px;
|
||||
}
|
||||
|
|
@ -1,17 +1,28 @@
|
|||
import {Component, inject, OnInit} from '@angular/core';
|
||||
import {Component, inject, OnInit, signal, WritableSignal} from '@angular/core';
|
||||
import {SeasonService} from '../../services/season.service';
|
||||
import {Season} from '../../../models/core/season';
|
||||
import {ReactiveFormsModule} from '@angular/forms';
|
||||
|
||||
@Component({
|
||||
selector: 'app-season-browser',
|
||||
imports: [],
|
||||
imports: [
|
||||
ReactiveFormsModule
|
||||
],
|
||||
templateUrl: './season-browser.component.html',
|
||||
styleUrl: './season-browser.component.scss'
|
||||
})
|
||||
export class SeasonBrowserComponent implements OnInit {
|
||||
private seasonService = inject(SeasonService);
|
||||
public seasons$ = this.seasonService.seasons$;
|
||||
public selectedSeasonId$: WritableSignal<string> = signal('');
|
||||
public selectedSeasonId!: string;
|
||||
|
||||
public ngOnInit() {
|
||||
this.seasonService.getSeasons();
|
||||
}
|
||||
|
||||
public click(selectedSeasonId: string): void {
|
||||
this.selectedSeasonId$.set(selectedSeasonId);
|
||||
this.selectedSeasonId = selectedSeasonId;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
<div class="card">
|
||||
<label for="types">Ticket Type</label>
|
||||
<select name="Types" id="types">
|
||||
<option>Select...</option>
|
||||
<div class="card card-fit-parent">
|
||||
<div class="row row-space-between">
|
||||
<label class="label">Ticket Type</label>
|
||||
<select #types name="Types" class="select" (change)="click(types.selectedIndex)">
|
||||
@for(type of ticketTypes | keyvalue; track type) {
|
||||
<option [value]="type.key">{{type.value}}</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,3 +0,0 @@
|
|||
label {
|
||||
padding-right: 15px;
|
||||
}
|
||||
|
|
@ -1,15 +1,24 @@
|
|||
import { Component } from '@angular/core';
|
||||
import {TicketTypeEnumLabel} from '../../../models/enums/ticket-type.enum';
|
||||
import {Component, signal, WritableSignal} from '@angular/core';
|
||||
import {TicketTypeEnum, TicketTypeEnumLabel} from '../../../models/enums/ticket-type.enum';
|
||||
import {KeyValuePipe} from '@angular/common';
|
||||
import {ReactiveFormsModule} from '@angular/forms';
|
||||
|
||||
@Component({
|
||||
selector: 'app-ticket-type-selector',
|
||||
imports: [
|
||||
KeyValuePipe
|
||||
KeyValuePipe,
|
||||
ReactiveFormsModule
|
||||
],
|
||||
templateUrl: './ticket-type-selector.component.html',
|
||||
styleUrl: './ticket-type-selector.component.scss'
|
||||
})
|
||||
export class TicketTypeSelectorComponent {
|
||||
public ticketTypes = TicketTypeEnumLabel;
|
||||
public selectedTicketType$: WritableSignal<TicketTypeEnum> = signal(TicketTypeEnum.Null);
|
||||
public selectedTicketType!: TicketTypeEnum;
|
||||
|
||||
public click(ticketType: number): void {
|
||||
this.selectedTicketType$.set(ticketType as TicketTypeEnum);
|
||||
this.selectedTicketType = ticketType as TicketTypeEnum;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,22 +2,22 @@
|
|||
<!-- TODO: Move this to a separate component -->
|
||||
<h3>Add Season</h3>
|
||||
<div class="column">
|
||||
<span class="row row-space-between">
|
||||
<label>Season Name</label>
|
||||
<input [formControl]="seasonName" type="text"/>
|
||||
</span>
|
||||
<span class="row row-space-between">
|
||||
<label>Season Description</label>
|
||||
<input [formControl]="seasonDescription" type="text"/>
|
||||
</span>
|
||||
<span class="row row-space-between">
|
||||
<label>Season Start Date</label>
|
||||
<input [formControl]="seasonStartDate" type="date"/>
|
||||
</span>
|
||||
<span class="row row-space-between">
|
||||
<label>Season End Date</label>
|
||||
<input [formControl]="seasonEndDate" type="date"/>
|
||||
</span>
|
||||
<div class="row row-space-between row-bottom-margin">
|
||||
<label class="label" for="seasonName">Season Name</label>
|
||||
<input id="seasonName" [formControl]="seasonName" type="text" class="input"/>
|
||||
</div>
|
||||
<div class="row row-space-between row-bottom-margin">
|
||||
<label class="label" for="seasonDescription">Season Description</label>
|
||||
<input id="seasonDescription" [formControl]="seasonDescription" type="text" class="input"/>
|
||||
</div>
|
||||
<div class="row row-space-between row-bottom-margin">
|
||||
<label class="label" for="seasonStartDate">Season Start Date</label>
|
||||
<input id="seasonStartDate" [formControl]="seasonStartDate" type="date" class="input"/>
|
||||
</div>
|
||||
<div class="row row-space-between row-bottom-margin">
|
||||
<label class="label" for="seasonEndDate">Season End Date</label>
|
||||
<input id="seasonEndDate" [formControl]="seasonEndDate" type="date" class="input"/>
|
||||
</div>
|
||||
</div>
|
||||
<button class="button" (click)="saveSeason()">Save</button>
|
||||
</div>
|
||||
|
|
@ -26,18 +26,18 @@
|
|||
<!-- TODO: Move this to a separate component -->
|
||||
<h3>Add Event</h3>
|
||||
<div class="column">
|
||||
<span class="row row-space-between">
|
||||
<label>Event Name</label>
|
||||
<input [formControl]="eventName" type="text"/>
|
||||
</span>
|
||||
<span class="row row-space-between">
|
||||
<label>Event Description</label>
|
||||
<input [formControl]="eventDescription" type="text"/>
|
||||
</span>
|
||||
<span class="row row-space-between">
|
||||
<label>Event Date</label>
|
||||
<input [formControl]="eventDate" type="date"/>
|
||||
</span>
|
||||
<div class="row row-space-between row-bottom-margin">
|
||||
<label class="label" for="eventName">Event Name</label>
|
||||
<input id="eventName" [formControl]="eventName" type="text" class="input"/>
|
||||
</div>
|
||||
<div class="row row-space-between row-bottom-margin">
|
||||
<label class="label" for="eventDescription">Event Description</label>
|
||||
<input id="eventDescription" [formControl]="eventDescription" type="text" class="input"/>
|
||||
</div>
|
||||
<div class="row row-space-between row-bottom-margin">
|
||||
<label class="label" for="eventDate">Event Date</label>
|
||||
<input id="eventDate" [formControl]="eventDate" type="date" class="input"/>
|
||||
</div>
|
||||
</div>
|
||||
<app-season-browser />
|
||||
<button class="button" (click)="saveEvent()">Save</button>
|
||||
|
|
|
|||
|
|
@ -1,3 +0,0 @@
|
|||
label {
|
||||
padding-right: 15px;
|
||||
}
|
||||
|
|
@ -1,8 +1,12 @@
|
|||
import {Component, inject} from '@angular/core';
|
||||
import {Component, inject, ViewChild} from '@angular/core';
|
||||
import {FormControl, ReactiveFormsModule, Validators} from '@angular/forms';
|
||||
import {EventService} from '../../services/event.service';
|
||||
import {SeasonService} from '../../services/season.service';
|
||||
import {SeasonBrowserComponent} from '../../components/season-browser/season-browser.component';
|
||||
import {AddEventRequest} from '../../../models/request/add-event-request';
|
||||
import {AddSeason} from '../../../models/request/add-season';
|
||||
import {VALLEY_FORGE_HIGH_SCHOOL} from '../../../models/core/venue';
|
||||
import {PARMA_SYMPHONY_ORCHESTRA} from '../../../models/core/talent';
|
||||
|
||||
@Component({
|
||||
selector: 'app-event',
|
||||
|
|
@ -11,23 +15,40 @@ import {SeasonBrowserComponent} from '../../components/season-browser/season-bro
|
|||
styleUrl: './event.component.scss'
|
||||
})
|
||||
export class EventComponent {
|
||||
public eventName = new FormControl('', [Validators.required]);
|
||||
@ViewChild(SeasonBrowserComponent) seasonBrowser!: SeasonBrowserComponent;
|
||||
public eventName = new FormControl('', {nonNullable: true, validators: [Validators.required]});
|
||||
public eventDescription = new FormControl('');
|
||||
public eventDate = new FormControl(new Date, [Validators.required]);
|
||||
public eventDate = new FormControl(new Date, {nonNullable: true, validators: [Validators.required]});
|
||||
|
||||
public seasonName = new FormControl('', [Validators.required]);
|
||||
public seasonName = new FormControl('', {nonNullable: true, validators: [Validators.required]});
|
||||
public seasonDescription = new FormControl('');
|
||||
public seasonStartDate = new FormControl(new Date, [Validators.required]);
|
||||
public seasonEndDate = new FormControl(new Date, [Validators.required]);
|
||||
public seasonStartDate = new FormControl(new Date, {nonNullable: true, validators: [Validators.required]});
|
||||
public seasonEndDate = new FormControl(new Date, {nonNullable: true, validators: [Validators.required]});
|
||||
|
||||
private eventService = inject(EventService);
|
||||
private seasonService = inject(SeasonService);
|
||||
|
||||
public saveEvent(): void {
|
||||
const request: AddEventRequest = {
|
||||
date: this.eventDate.value,
|
||||
name: this.eventName.value,
|
||||
description: this.eventDescription.value,
|
||||
venue: VALLEY_FORGE_HIGH_SCHOOL,
|
||||
talent: PARMA_SYMPHONY_ORCHESTRA,
|
||||
seasonId: this.seasonBrowser.selectedSeasonId
|
||||
};
|
||||
|
||||
this.eventService.addEvent(request);
|
||||
}
|
||||
|
||||
public saveSeason(): void {
|
||||
const request: AddSeason = {
|
||||
startDate: this.seasonStartDate.value,
|
||||
endDate: this.seasonEndDate.value,
|
||||
name: this.seasonName.value,
|
||||
description: this.seasonDescription.value,
|
||||
};
|
||||
|
||||
this.seasonService.saveSeason(request);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
<button class="button" (click)="hideScanner = !hideScanner">
|
||||
<button class="button" (click)="click()">
|
||||
@if(hideScanner) {
|
||||
Stop
|
||||
} @else {
|
||||
|
|
|
|||
|
|
@ -18,4 +18,11 @@ export class ScanComponent {
|
|||
this.scan.searchTicket(resultString);
|
||||
console.log(resultString);
|
||||
}
|
||||
|
||||
public click(): void {
|
||||
this.hideScanner = !this.hideScanner;
|
||||
this.scan.ticketValid$.set(null);
|
||||
this.scan.ticketType$.set(null);
|
||||
this.scan.ticketSearch$.set(null);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,16 @@
|
|||
<div class="card">
|
||||
<h3>Generate Tickets</h3>
|
||||
<div class="column">
|
||||
<app-ticket-type-selector #ticketType></app-ticket-type-selector>
|
||||
<app-event-browser />
|
||||
<app-ticket-type-selector />
|
||||
@if(IsSeasonTicket(ticketType.selectedTicketType$())) {
|
||||
<app-season-browser />
|
||||
}
|
||||
<app-patron-info />
|
||||
</div>
|
||||
<button class="button" (click)="saveTicket()">Save Ticket</button>
|
||||
</div>
|
||||
|
||||
@if(qrCode().length > 0) {
|
||||
<app-generated-ticket />
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,23 +1,46 @@
|
|||
import {Component, inject} from '@angular/core';
|
||||
import {Component, inject, ViewChild} from '@angular/core';
|
||||
import {EventBrowserComponent} from '../../components/event-browser/event-browser.component';
|
||||
import {TicketTypeSelectorComponent} from '../../components/ticket-type-selector/ticket-type-selector.component';
|
||||
import {PatronInfoComponent} from '../../components/patron-info/patron-info.component';
|
||||
import {TicketService} from '../../services/ticket.service';
|
||||
import {AddTicket} from '../../../models/request/add-ticket';
|
||||
import {SeasonBrowserComponent} from '../../components/season-browser/season-browser.component';
|
||||
import {IsSeasonTicket} from '../../../models/enums/ticket-type.enum';
|
||||
import {GeneratedTicketComponent} from '../../components/generated-ticket/generated-ticket.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-ticket',
|
||||
imports: [
|
||||
EventBrowserComponent,
|
||||
TicketTypeSelectorComponent,
|
||||
PatronInfoComponent
|
||||
PatronInfoComponent,
|
||||
SeasonBrowserComponent,
|
||||
GeneratedTicketComponent
|
||||
],
|
||||
templateUrl: './ticket.component.html',
|
||||
styleUrl: './ticket.component.scss'
|
||||
})
|
||||
export class TicketComponent {
|
||||
@ViewChild(TicketTypeSelectorComponent) ticketTypeSelector!: TicketTypeSelectorComponent;
|
||||
@ViewChild(PatronInfoComponent) patronInfoComponent!: PatronInfoComponent;
|
||||
@ViewChild(EventBrowserComponent) eventBrowserComponent!: EventBrowserComponent;
|
||||
@ViewChild(SeasonBrowserComponent) seasonBrowserComponent!: SeasonBrowserComponent;
|
||||
|
||||
public ticketService = inject(TicketService);
|
||||
public qrCode = this.ticketService.dataSignal$;
|
||||
|
||||
public saveTicket(): void {
|
||||
|
||||
const addTicket: AddTicket = {
|
||||
eventId: this.eventBrowserComponent.selectedEventId,
|
||||
type: this.ticketTypeSelector.selectedTicketType,
|
||||
seasonId:
|
||||
IsSeasonTicket(this.ticketTypeSelector.selectedTicketType)
|
||||
? this.seasonBrowserComponent.selectedSeasonId : '',
|
||||
patron: this.patronInfoComponent.buildPatron()
|
||||
}
|
||||
|
||||
this.ticketService.addTicket(addTicket);
|
||||
}
|
||||
|
||||
protected readonly IsSeasonTicket = IsSeasonTicket;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,32 +22,21 @@ export class EventService extends ApiUtils {
|
|||
|
||||
public addEvent(request: AddEventRequest): void {
|
||||
//TODO: Remove hard coded venue and talent information
|
||||
|
||||
request.talent = {
|
||||
name: 'Parma Symphony Orchestra',
|
||||
description: 'Parma Symphony Orchestra is a Northeast Ohio community orchestra with over 50 years of history bringing classical music to people of all ages, with opportunities for local students and professional guests to perform a wide ranging repertoire.',
|
||||
};
|
||||
|
||||
request.venue = {
|
||||
name: 'Valley Forge High School',
|
||||
description: 'Auditorium',
|
||||
addressOne: '9999 Independence Blvd',
|
||||
addressTwo: null,
|
||||
city: 'Parma',
|
||||
state: 'Ohio',
|
||||
zip: '44130'
|
||||
};
|
||||
|
||||
const options = this.setHttpRequestOptions();
|
||||
const url = environment.apiBase + Endpoints.EVENT;
|
||||
|
||||
this.httpClient.post<AddEventRequest>(url, JSON.stringify(request), options)
|
||||
this.httpClient.post(url, JSON.stringify(request), options)
|
||||
.pipe(
|
||||
catchError(error => {
|
||||
this.snackbar.showError(error.error);
|
||||
return of(undefined);
|
||||
})
|
||||
).subscribe();
|
||||
).subscribe(res => {
|
||||
if(res !== null) {
|
||||
this.snackbar.showMessage('Event added successfully.');
|
||||
this.searchAllEvents();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public searchAllEvents(): void {
|
||||
|
|
|
|||
|
|
@ -13,8 +13,9 @@ import {SnackbarService} from './snackbar.service';
|
|||
providedIn: 'root'
|
||||
})
|
||||
export class ScanService extends ApiUtils {
|
||||
public ticketValid$: WritableSignal<TicketValidity> = signal(TicketValidity.Null);
|
||||
public ticketType$: WritableSignal<TicketTypeEnum> = signal(TicketTypeEnum.Null);
|
||||
public ticketValid$: WritableSignal<TicketValidity | null> = signal(TicketValidity.Invalid);
|
||||
public ticketType$: WritableSignal<TicketTypeEnum | null> = signal(TicketTypeEnum.Null);
|
||||
public ticketSearch$: WritableSignal<TicketSearch | null> = signal(null);
|
||||
private httpClient = inject(HttpClient);
|
||||
private snackbar = inject(SnackbarService);
|
||||
|
||||
|
|
@ -35,8 +36,9 @@ export class ScanService extends ApiUtils {
|
|||
})
|
||||
).subscribe((res: TicketSearch) => {
|
||||
if (res !== undefined) {
|
||||
this.ticketType$.set(res.ticketType);
|
||||
this.ticketValid$.set(res.ticketValidity)
|
||||
this.ticketSearch$.set(res);
|
||||
this.ticketType$.set(res.type as TicketTypeEnum);
|
||||
this.ticketValid$.set(res.validity as TicketValidity);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,7 +48,12 @@ export class SeasonService extends ApiUtils {
|
|||
this.snackbar.showError(error.error);
|
||||
return of(undefined);
|
||||
})
|
||||
).subscribe();
|
||||
).subscribe(res => {
|
||||
if (res !== null) {
|
||||
this.snackbar.showMessage('Season added successfully.');
|
||||
this.getSeasons();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public addEventToSeason(eventId: string, seasonId: string): void {
|
||||
|
|
|
|||
|
|
@ -16,4 +16,14 @@ export class SnackbarService {
|
|||
this.snackbarMessage$.set('');
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
public showMessage(message: string): void {
|
||||
this.showSnackbar$.set(true);
|
||||
this.snackbarMessage$.set(message);
|
||||
|
||||
setTimeout(() => {
|
||||
this.showSnackbar$.set(false);
|
||||
this.snackbarMessage$.set('');
|
||||
}, 5000);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,3 +2,8 @@ export interface Talent {
|
|||
name: string;
|
||||
description: string | null;
|
||||
}
|
||||
|
||||
export const PARMA_SYMPHONY_ORCHESTRA: Talent = {
|
||||
name: 'Parma Symphony Orchestra',
|
||||
description: 'Parma Symphony Orchestra is a Northeast Ohio community orchestra with over 50 years of history bringing classical music to people of all ages, with opportunities for local students and professional guests to perform a wide ranging repertoire.',
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,3 +7,13 @@ export interface Venue {
|
|||
state: string,
|
||||
zip: string,
|
||||
}
|
||||
|
||||
export const VALLEY_FORGE_HIGH_SCHOOL: Venue = {
|
||||
name: 'Valley Forge High School',
|
||||
description: 'Auditorium',
|
||||
addressOne: '9999 Independence Blvd',
|
||||
addressTwo: null,
|
||||
city: 'Parma',
|
||||
state: 'Ohio',
|
||||
zip: '44130'
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ export enum TicketTypeEnum {
|
|||
}
|
||||
|
||||
export const TicketTypeEnumLabel = new Map<number, string>([
|
||||
[TicketTypeEnum.Null, 'Select'],
|
||||
[TicketTypeEnum.Single, 'Single'],
|
||||
[TicketTypeEnum.SingleSeason, 'Single Season'],
|
||||
[TicketTypeEnum.Family, 'Family'],
|
||||
|
|
@ -16,3 +17,9 @@ export const TicketTypeEnumLabel = new Map<number, string>([
|
|||
[TicketTypeEnum.Senior, 'Senior'],
|
||||
[TicketTypeEnum.SeniorSeason, 'Senior Season'],
|
||||
]);
|
||||
|
||||
export function IsSeasonTicket(type: TicketTypeEnum): boolean {
|
||||
return type === TicketTypeEnum.SingleSeason
|
||||
|| type === TicketTypeEnum.FamilySeason
|
||||
|| type === TicketTypeEnum.SeniorSeason;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
export enum TicketValidity {
|
||||
Null,
|
||||
Valid,
|
||||
Expired,
|
||||
Early,
|
||||
Invalid
|
||||
Invalid,
|
||||
Valid,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,8 @@ import {Talent} from '../core/talent';
|
|||
export interface AddEventRequest {
|
||||
date: Date,
|
||||
name: string,
|
||||
description: string,
|
||||
description: string | null,
|
||||
venue: Venue,
|
||||
talent: Talent,
|
||||
seasonId: string
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
import {TicketTypeEnum} from '../enums/ticket-type.enum';
|
||||
import {Patron} from '../core/patron';
|
||||
|
||||
export interface AddTicket {
|
||||
ticketType: TicketTypeEnum,
|
||||
eventId: string
|
||||
type: TicketTypeEnum,
|
||||
eventId: string,
|
||||
seasonId: string | null,
|
||||
patron: Patron,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,6 @@ import {TicketTypeEnum} from '../enums/ticket-type.enum';
|
|||
import {TicketValidity} from '../enums/ticket-validity.enum';
|
||||
|
||||
export interface TicketSearch {
|
||||
ticketType: TicketTypeEnum,
|
||||
ticketValidity: TicketValidity
|
||||
type: TicketTypeEnum,
|
||||
validity: TicketValidity
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,10 @@ body {
|
|||
&-large {
|
||||
width: 250px;
|
||||
}
|
||||
|
||||
&-fit-parent {
|
||||
width: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.button {
|
||||
|
|
@ -39,18 +43,59 @@ body {
|
|||
}
|
||||
}
|
||||
|
||||
.select {
|
||||
padding: 5px;
|
||||
backdrop-filter: blur(25px) saturate(112%);
|
||||
-webkit-backdrop-filter: blur(25px) saturate(112%);
|
||||
background-color: rgba(255, 255, 255, 0.11);
|
||||
border-radius: 8px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.125);
|
||||
width: auto;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(255, 255, 255, 0.0);
|
||||
}
|
||||
}
|
||||
|
||||
.input {
|
||||
padding: 5px;
|
||||
backdrop-filter: blur(25px) saturate(112%);
|
||||
-webkit-backdrop-filter: blur(25px) saturate(112%);
|
||||
background-color: rgba(255, 255, 255, 0.11);
|
||||
border-radius: 8px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.125);
|
||||
width: auto;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(255, 255, 255, 0.0);
|
||||
}
|
||||
}
|
||||
|
||||
.label {
|
||||
padding-right: 15px;
|
||||
}
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: baseline;
|
||||
|
||||
&-space-between {
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
&-bottom-margin {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.column {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
|
||||
&-space-between {
|
||||
justify-content: space-between;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user