Adding patron info

Adding several components
Restructuring UI
This commit is contained in:
Tara Wilson 2024-12-06 19:52:20 -05:00
parent cb433ba390
commit 2358ef1c96
46 changed files with 259 additions and 91 deletions

View File

@ -22,7 +22,7 @@ public class TicketController(
/// </summary> /// </summary>
/// <returns>Base64 String Qr Code</returns> /// <returns>Base64 String Qr Code</returns>
[HttpPost] [HttpPost]
public ActionResult<MintResponse> Post([FromBody] AddTicket mintRequest) public ActionResult<MintResponse> Post([FromBody] AddTicket request)
{ {
//TODO: Protect Endpoint //TODO: Protect Endpoint
@ -39,9 +39,10 @@ public class TicketController(
{ {
Id = ticketId, Id = ticketId,
QrCode = qrCode, QrCode = qrCode,
Type = mintRequest.Type, Type = request.Type,
EventId = mintRequest.EventId, EventId = request.EventId,
SeasonId = mintRequest.SeasonId != Guid.Empty ? mintRequest.SeasonId : Guid.Empty, SeasonId = request.SeasonId != Guid.Empty ? request.SeasonId : Guid.Empty,
Patron = request.Patron,
}; };
//save the minted ticket //save the minted ticket

View File

@ -11,7 +11,19 @@ Content-Type: application/json
{ {
"type": 0, "type": 0,
"eventId": "{{eventId}}" "eventId": "{{eventId}}",
"patron": {
"firstName": "Tara",
"middleName": "",
"lastName": "Wilson",
"email": "terralilly85@icloud.com",
"phoneNumber": "",
"addressOne": "1330 Douglas Ave",
"addressTwo": "",
"city": "Youngstown",
"state": "Ohio",
"zip": "44502"
}
} }
### Mint Single Season Ticket ### Mint Single Season Ticket
@ -23,7 +35,19 @@ Content-Type: application/json
{ {
"type": 1, "type": 1,
"eventId": "{{eventId}}", "eventId": "{{eventId}}",
"seasonId": "{{seasonId}}" "seasonId": "{{seasonId}}",
"patron": {
"firstName": "Tara",
"middleName": "",
"lastName": "Wilson",
"email": "terralilly85@icloud.com",
"phoneNumber": "",
"addressOne": "1330 Douglas Ave",
"addressTwo": "",
"city": "Youngstown",
"state": "Ohio",
"zip": "44502"
}
} }
### ###

View File

@ -0,0 +1,15 @@
using models.Core;
using MongoDB.Driver;
namespace data.Seasons;
public class Get
{
public Season Execute(Guid seasonId)
{
var database = MongoFactory.GetDatabase();
var collection = database.GetCollection<Season>("seasons");
return collection.Find(s => s.Id == seasonId).FirstOrDefault();
}
}

View File

@ -0,0 +1,15 @@
namespace models.Core;
public class Patron
{
public required string FirstName { get; set; }
public string? MiddleName { get; set; }
public required string LastName { get; set; }
public required string Email { get; set; }
public string? PhoneNumber { get; set; }
public required string AddressOne { get; set; }
public string? AddressTwo { get; set; }
public required string City { get; set; }
public required string State { get; set; }
public required string Zip { get; set; }
}

View File

@ -9,4 +9,5 @@ public class Ticket
public Guid EventId { get; set; } public Guid EventId { get; set; }
public TicketType Type { get; set; } public TicketType Type { get; set; }
public required string QrCode { get; set; } public required string QrCode { get; set; }
public required Patron Patron { get; set; }
} }

View File

@ -1,3 +1,4 @@
using models.Core;
using models.Enumerations; using models.Enumerations;
namespace models.Request; namespace models.Request;
@ -7,4 +8,5 @@ public class AddTicket
public TicketType Type { get; set; } public TicketType Type { get; set; }
public Guid EventId { get; set; } public Guid EventId { get; set; }
public Guid SeasonId { get; set; } = Guid.Empty; public Guid SeasonId { get; set; } = Guid.Empty;
public required Patron Patron { get; set; }
} }

View File

@ -1,7 +1,7 @@
import {Component} from '@angular/core'; import {Component} from '@angular/core';
import {SidebarComponent} from './sidebar/sidebar.component'; import {SidebarComponent} from './components/sidebar/sidebar.component';
import {RouterOutlet} from '@angular/router'; import {RouterOutlet} from '@angular/router';
import {SnackbarComponent} from './snackbar/snackbar.component'; import {SnackbarComponent} from './components/snackbar/snackbar.component';
@Component({ @Component({
selector: 'app-root', selector: 'app-root',

View File

@ -1,14 +1,9 @@
import {Routes} from '@angular/router'; import {Routes} from '@angular/router';
import {DebugComponent} from './page/debug/debug.component';
import {EventComponent} from './page/event/event.component'; import {EventComponent} from './page/event/event.component';
import {TicketComponent} from './page/ticket/ticket.component'; import {TicketComponent} from './page/ticket/ticket.component';
import {ScanComponent} from './page/scan/scan.component'; import {ScanComponent} from './page/scan/scan.component';
export const routes: Routes = [ export const routes: Routes = [
{
path: 'debug',
component: DebugComponent
},
{ {
path: 'event', path: 'event',
component: EventComponent component: EventComponent

View File

@ -1,6 +1,7 @@
<div class="card"> <div class="card">
<label for="events">Events</label> <label for="events">Event</label>
<select name="Events" id="events"> <select name="Events" id="events">
<option>Select...</option>
@for(event of events$(); track event.id) { @for(event of events$(); track event.id) {
<option [value]="event.id">{{event.name}}</option> <option [value]="event.id">{{event.name}}</option>
} }

View File

@ -0,0 +1,3 @@
label {
padding-right: 15px;
}

View File

@ -1,5 +1,5 @@
import {Component, inject, OnInit} from '@angular/core'; import {Component, inject, OnInit} from '@angular/core';
import {EventService} from '../services/event.service'; import {EventService} from '../../services/event.service';
@Component({ @Component({
selector: 'app-event-browser', selector: 'app-event-browser',

View File

@ -0,0 +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>
</div>

View File

@ -0,0 +1,3 @@
label {
padding-right: 15px;
}

View File

@ -0,0 +1,23 @@
import { Component } from '@angular/core';
import {FormControl, ReactiveFormsModule, Validators} from '@angular/forms';
@Component({
selector: 'app-patron-info',
imports: [
ReactiveFormsModule
],
templateUrl: './patron-info.component.html',
styleUrl: './patron-info.component.scss'
})
export class PatronInfoComponent {
public firstName = new FormControl('', [Validators.required]);
public middleName = new FormControl('');
public lastName = new FormControl('', [Validators.required]);
public email = new FormControl('', [Validators.required]);
public phoneNumber = new FormControl('');
public addressOne = new FormControl('', [Validators.required]);
public addressTwo = new FormControl('');
public city = new FormControl('', [Validators.required]);
public state = new FormControl('', [Validators.required]);
public zip = new FormControl('', [Validators.required]);
}

View File

@ -1,7 +1,7 @@
import {Component, inject} from '@angular/core'; import {Component, inject} from '@angular/core';
import {TicketValidity} from '../../models/enums/ticket-validity.enum'; import {TicketValidity} from '../../../models/enums/ticket-validity.enum';
import {TicketTypeEnum} from '../../models/enums/ticket-type.enum'; import {TicketTypeEnum} from '../../../models/enums/ticket-type.enum';
import {ScanService} from '../services/scan.service'; import {ScanService} from '../../services/scan.service';
import {NgOptimizedImage} from '@angular/common'; import {NgOptimizedImage} from '@angular/common';
@Component({ @Component({

View File

@ -1,6 +1,7 @@
<div class="card"> <div class="card">
<label for="seasons">Seasons</label> <label for="seasons">Season</label>
<select name="Seasons" id="seasons"> <select name="Seasons" id="seasons">
<option>No Season</option>
@for(season of seasons$(); track season.id) { @for(season of seasons$(); track season.id) {
<option [value]="season.id">{{season.name}}</option> <option [value]="season.id">{{season.name}}</option>
} }

View File

@ -0,0 +1,3 @@
label {
padding-right: 15px;
}

View File

@ -1,5 +1,5 @@
import {Component, inject, OnInit} from '@angular/core'; import {Component, inject, OnInit} from '@angular/core';
import {SeasonService} from '../services/season.service'; import {SeasonService} from '../../services/season.service';
@Component({ @Component({
selector: 'app-season-browser', selector: 'app-season-browser',

View File

@ -2,7 +2,4 @@
<button class="sidebar-button" [routerLink]="['/ticket']">Generate Tickets</button> <button class="sidebar-button" [routerLink]="['/ticket']">Generate Tickets</button>
<button class="sidebar-button" [routerLink]="['/scan']">Scan Tickets</button> <button class="sidebar-button" [routerLink]="['/scan']">Scan Tickets</button>
<button class="sidebar-button" [routerLink]="['/event']">Manage</button> <button class="sidebar-button" [routerLink]="['/event']">Manage</button>
@if(!environment.production) {
<button class="sidebar-button" [routerLink]="['/debug']">Debug</button>
}
</div> </div>

View File

@ -1,5 +1,5 @@
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import {environment} from '../../environments/environment'; import {environment} from '../../../environments/environment';
import {RouterModule} from '@angular/router'; import {RouterModule} from '@angular/router';
@Component({ @Component({

View File

@ -1,5 +1,5 @@
import {Component, inject} from '@angular/core'; import {Component, inject} from '@angular/core';
import {SnackbarService} from '../services/snackbar.service'; import {SnackbarService} from '../../services/snackbar.service';
@Component({ @Component({
selector: 'app-snackbar', selector: 'app-snackbar',

View File

@ -0,0 +1,9 @@
<div class="card">
<label for="types">Ticket Type</label>
<select name="Types" id="types">
<option>Select...</option>
@for(type of ticketTypes | keyvalue; track type) {
<option [value]="type.key">{{type.value}}</option>
}
</select>
</div>

View File

@ -0,0 +1,3 @@
label {
padding-right: 15px;
}

View File

@ -0,0 +1,15 @@
import { Component } from '@angular/core';
import {TicketTypeEnumLabel} from '../../../models/enums/ticket-type.enum';
import {KeyValuePipe} from '@angular/common';
@Component({
selector: 'app-ticket-type-selector',
imports: [
KeyValuePipe
],
templateUrl: './ticket-type-selector.component.html',
styleUrl: './ticket-type-selector.component.scss'
})
export class TicketTypeSelectorComponent {
public ticketTypes = TicketTypeEnumLabel;
}

View File

@ -3,8 +3,5 @@
<div class="row"> <div class="row">
<img class="qrcode" alt="Embedded QR Code" src="data:image/png;base64,{{qrCode().toString()}}" /> <img class="qrcode" alt="Embedded QR Code" src="data:image/png;base64,{{qrCode().toString()}}" />
</div> </div>
<div class="card card-large">
test
</div>
</div> </div>
} }

View File

@ -1,5 +1,5 @@
import {Component, inject} from '@angular/core'; import {Component, inject} from '@angular/core';
import {TicketService} from '../services/ticket.service'; import {TicketService} from '../../services/ticket.service';
@Component({ @Component({
selector: 'app-ticket', selector: 'app-ticket',

View File

@ -1,3 +0,0 @@
<button class="button" (click)="getQrCode()">Get QR Code</button>
<app-ticket />

View File

@ -1,26 +0,0 @@
import {Component, inject} from '@angular/core';
import {TicketComponent} from "../../ticket/ticket.component";
import {TicketService} from '../../services/ticket.service';
import {AddTicket} from '../../../models/request/add-ticket';
import {TicketTypeEnum} from '../../../models/enums/ticket-type.enum';
@Component({
selector: 'app-debug',
imports: [
TicketComponent
],
templateUrl: './debug.component.html',
styleUrl: './debug.component.scss'
})
export class DebugComponent {
private ticketMinter = inject(TicketService);
public getQrCode(): void {
const mintRequest: AddTicket = {
ticketType: TicketTypeEnum.Single,
eventId: ''
};
this.ticketMinter.addTicket(mintRequest);
}
}

View File

@ -1,24 +1,3 @@
<div class="card">
<!-- 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>
<app-season-browser />
<button class="button" (click)="saveEvent()">Save</button>
</div>
<div class="card"> <div class="card">
<!-- TODO: Move this to a separate component --> <!-- TODO: Move this to a separate component -->
<h3>Add Season</h3> <h3>Add Season</h3>
@ -42,3 +21,24 @@
</div> </div>
<button class="button" (click)="saveSeason()">Save</button> <button class="button" (click)="saveSeason()">Save</button>
</div> </div>
<div class="card">
<!-- 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>
<app-season-browser />
<button class="button" (click)="saveEvent()">Save</button>
</div>

View File

@ -1,8 +1,8 @@
import {Component, inject} from '@angular/core'; import {Component, inject} from '@angular/core';
import {FormControl, ReactiveFormsModule} from '@angular/forms'; import {FormControl, ReactiveFormsModule, Validators} from '@angular/forms';
import {EventService} from '../../services/event.service'; import {EventService} from '../../services/event.service';
import {SeasonService} from '../../services/season.service'; import {SeasonService} from '../../services/season.service';
import {SeasonBrowserComponent} from '../../season-browser/season-browser.component'; import {SeasonBrowserComponent} from '../../components/season-browser/season-browser.component';
@Component({ @Component({
selector: 'app-event', selector: 'app-event',
@ -11,14 +11,14 @@ import {SeasonBrowserComponent} from '../../season-browser/season-browser.compon
styleUrl: './event.component.scss' styleUrl: './event.component.scss'
}) })
export class EventComponent { export class EventComponent {
public eventName = new FormControl(''); public eventName = new FormControl('', [Validators.required]);
public eventDescription = new FormControl(''); public eventDescription = new FormControl('');
public eventDate = new FormControl(new Date); public eventDate = new FormControl(new Date, [Validators.required]);
public seasonName = new FormControl(''); public seasonName = new FormControl('', [Validators.required]);
public seasonDescription = new FormControl(''); public seasonDescription = new FormControl('');
public seasonStartDate = new FormControl(new Date); public seasonStartDate = new FormControl(new Date, [Validators.required]);
public seasonEndDate = new FormControl(new Date); public seasonEndDate = new FormControl(new Date, [Validators.required]);
private eventService = inject(EventService); private eventService = inject(EventService);
private seasonService = inject(SeasonService); private seasonService = inject(SeasonService);

View File

@ -1,6 +1,6 @@
import {Component, inject} from '@angular/core'; import {Component, inject} from '@angular/core';
import {ZXingScannerModule} from '@zxing/ngx-scanner'; import {ZXingScannerModule} from '@zxing/ngx-scanner';
import {ScanResultComponent} from '../../scan-result/scan-result.component'; import {ScanResultComponent} from '../../components/scan-result/scan-result.component';
import {ScanService} from '../../services/scan.service'; import {ScanService} from '../../services/scan.service';
@Component({ @Component({

View File

@ -1,4 +1,7 @@
<div class="card"> <div class="card">
<h3>Generate Tickets</h3> <h3>Generate Tickets</h3>
<app-event-browser /> <app-event-browser />
<app-ticket-type-selector />
<app-patron-info />
<button class="button" (click)="saveTicket()">Save Ticket</button>
</div> </div>

View File

@ -1,14 +1,23 @@
import { Component } from '@angular/core'; import {Component, inject} from '@angular/core';
import {EventBrowserComponent} from '../../event-browser/event-browser.component'; 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';
@Component({ @Component({
selector: 'app-ticket', selector: 'app-ticket',
imports: [ imports: [
EventBrowserComponent EventBrowserComponent,
TicketTypeSelectorComponent,
PatronInfoComponent
], ],
templateUrl: './ticket.component.html', templateUrl: './ticket.component.html',
styleUrl: './ticket.component.scss' styleUrl: './ticket.component.scss'
}) })
export class TicketComponent { export class TicketComponent {
public ticketService = inject(TicketService);
public saveTicket(): void {
}
} }

View File

@ -0,0 +1,12 @@
export interface Patron {
firstName: string,
middleName: string | null,
lastName: string,
email: string,
phoneNumber: string | null,
addressOne: string,
addressTwo: string | null,
city: string,
state: string,
zip: string,
}

View File

@ -0,0 +1,11 @@
import {TicketTypeEnum} from '../enums/ticket-type.enum';
import {Patron} from './patron';
export interface Ticket {
id: string,
seasonId: string,
eventId: string,
type: TicketTypeEnum,
qrCode: string,
patron: Patron
}

View File

@ -7,3 +7,12 @@ export enum TicketTypeEnum {
Senior, Senior,
SeniorSeason SeniorSeason
} }
export const TicketTypeEnumLabel = new Map<number, string>([
[TicketTypeEnum.Single, 'Single'],
[TicketTypeEnum.SingleSeason, 'Single Season'],
[TicketTypeEnum.Family, 'Family'],
[TicketTypeEnum.FamilySeason, 'Family Season'],
[TicketTypeEnum.Senior, 'Senior'],
[TicketTypeEnum.SeniorSeason, 'Senior Season'],
]);