Refactoring
Building out UI Building out API Fixing Bugs
This commit is contained in:
parent
924cee4e0f
commit
cb433ba390
|
|
@ -40,7 +40,8 @@ public class TicketController(
|
|||
Id = ticketId,
|
||||
QrCode = qrCode,
|
||||
Type = mintRequest.Type,
|
||||
EventId = mintRequest.EventId
|
||||
EventId = mintRequest.EventId,
|
||||
SeasonId = mintRequest.SeasonId != Guid.Empty ? mintRequest.SeasonId : Guid.Empty,
|
||||
};
|
||||
|
||||
//save the minted ticket
|
||||
|
|
|
|||
|
|
@ -1,14 +1,16 @@
|
|||
@api_HostAddress = http://localhost:5168
|
||||
@eventId = b9f4478b-701b-4223-9aaa-042b6f53b83a
|
||||
@eventId = cdae537c-e5ad-4945-9557-b14ba473c80f
|
||||
@seasonId = c69552ba-8fcf-43b4-9d4f-23b5203ea40e
|
||||
|
||||
POST {{api_HostAddress}}/event
|
||||
Accept: application/json
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"Date": "2024-12-02T15:00:00.991Z",
|
||||
"EventName": "Winter Concert",
|
||||
"EventDescription": "A wintery journey of classical music",
|
||||
"Date": "2024-12-07T15:00:00.991Z",
|
||||
"Name": "Winter Concert",
|
||||
"Description": "A wintery journey of classical music",
|
||||
"SeasonId": "{{seasonId}}",
|
||||
"Venue": {
|
||||
"Name": "Valley Forge High School",
|
||||
"Description": "Auditorium",
|
||||
|
|
@ -33,8 +35,8 @@ Content-Type: application/json
|
|||
{
|
||||
"Id": "{{eventId}}",
|
||||
"Date": "2024-12-05T15:00:00.991Z",
|
||||
"EventName": "Winter Concert",
|
||||
"EventDescription": "A wintery journey of classical music",
|
||||
"Name": "Winter Concert",
|
||||
"Description": "A wintery journey of classical music",
|
||||
"Venue": {
|
||||
"Name": "Valley Forge High School",
|
||||
"Description": "Auditorium",
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
@api_HostAddress = http://localhost:5168
|
||||
@ticketId = fe21c683-b607-4da7-8e9b-76b199a4b76c
|
||||
@ticketId =
|
||||
|
||||
###
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
@api_HostAddress = http://localhost:5168
|
||||
@seasonId = 76178cf4-3805-4a66-a3d9-a0223d99c2fa
|
||||
@eventId = b9f4478b-701b-4223-9aaa-042b6f53b83a
|
||||
@seasonId = c69552ba-8fcf-43b4-9d4f-23b5203ea40e
|
||||
@eventId = cdae537c-e5ad-4945-9557-b14ba473c80f
|
||||
|
||||
GET {{api_HostAddress}}/season
|
||||
Accept: application/json
|
||||
|
|
@ -13,8 +13,8 @@ Accept: application/json
|
|||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"SeasonName": "PSO 25 - 26",
|
||||
"SeasonDescription": "Parma Symphony Orchestra's 53rd Season",
|
||||
"Name": "PSO 25 - 26",
|
||||
"Description": "Parma Symphony Orchestra's 53rd Season",
|
||||
"StartDate": "2025-08-01T00:00:00.991Z",
|
||||
"EndDate": "2026-05-31T00:00:00.991Z"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,16 +1,31 @@
|
|||
@api_HostAddress = http://localhost:5168
|
||||
@ticketId = fe21c683-b607-4da7-8e9b-76b199a4b76c
|
||||
@eventId = b9f4478b-701b-4223-9aaa-042b6f53b83a
|
||||
@ticketId =
|
||||
@eventId = cdae537c-e5ad-4945-9557-b14ba473c80f
|
||||
@seasonId = c69552ba-8fcf-43b4-9d4f-23b5203ea40e
|
||||
|
||||
### Mint Single Non Season Ticket
|
||||
|
||||
POST {{api_HostAddress}}/ticket
|
||||
Accept: application/json
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"ticketType": "Single",
|
||||
"type": 0,
|
||||
"eventId": "{{eventId}}"
|
||||
}
|
||||
|
||||
### Mint Single Season Ticket
|
||||
|
||||
POST {{api_HostAddress}}/ticket
|
||||
Accept: application/json
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"type": 1,
|
||||
"eventId": "{{eventId}}",
|
||||
"seasonId": "{{seasonId}}"
|
||||
}
|
||||
|
||||
###
|
||||
|
||||
GET {{api_HostAddress}}/ticket?ticketId={{ticketId}}
|
||||
|
|
|
|||
|
|
@ -12,14 +12,16 @@ public class EventManager : IEventManager
|
|||
var @event = new Event
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
EventDescription = request.EventDescription,
|
||||
EventName = request.EventName,
|
||||
SeasonId = request.SeasonId,
|
||||
Description = request.Description,
|
||||
Name = request.Name,
|
||||
Date = request.Date,
|
||||
Talent = request.Talent,
|
||||
Venue = request.Venue
|
||||
};
|
||||
|
||||
new Save().Execute(@event);
|
||||
new data.Seasons.AddEvent().Execute(@event.Id, request.SeasonId);
|
||||
}
|
||||
|
||||
public void PatchEvent(PatchEvent request)
|
||||
|
|
|
|||
|
|
@ -13,8 +13,8 @@ public class SeasonManager : ISeasonManager
|
|||
var season = new Season
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Name = request.SeasonName,
|
||||
Description = request.SeasonDescription,
|
||||
Name = request.Name,
|
||||
Description = request.Description,
|
||||
StartDate = request.StartDate,
|
||||
EndDate = request.EndDate,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@ public class Update
|
|||
{
|
||||
Id = request.Id,
|
||||
Date = request.Date,
|
||||
EventName = request.EventName,
|
||||
EventDescription = request.EventDescription,
|
||||
Name = request.Name,
|
||||
Description = request.Description,
|
||||
Venue = request.Venue,
|
||||
Talent = request.Talent,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -3,9 +3,10 @@ namespace models.Core;
|
|||
public class Event
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
public Guid SeasonId { get; set; }
|
||||
public DateTime Date { get; set; }
|
||||
public required string EventName { get; set; }
|
||||
public string? EventDescription { get; set; }
|
||||
public required string Name { get; set; }
|
||||
public string? Description { get; set; }
|
||||
public required Venue Venue { get; set; }
|
||||
public required Talent Talent { get; set; }
|
||||
public List<Guid> TicketIds { get; set; } = [];
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ namespace models.Core;
|
|||
public class Ticket
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
public Guid SeasonId { get; set; }
|
||||
public Guid EventId { get; set; }
|
||||
public TicketType Type { get; set; }
|
||||
public required string QrCode { get; set; }
|
||||
|
|
|
|||
|
|
@ -5,8 +5,9 @@ namespace models.Request;
|
|||
public class AddEvent
|
||||
{
|
||||
public DateTime Date { get; set; }
|
||||
public required string EventName { get; set; }
|
||||
public string? EventDescription { get; set; }
|
||||
public Guid SeasonId { get; set; }
|
||||
public required string Name { get; set; }
|
||||
public string? Description { get; set; }
|
||||
public required Venue Venue { get; set; }
|
||||
public required Talent Talent { get; set; }
|
||||
}
|
||||
|
|
@ -2,8 +2,8 @@ namespace models.Request;
|
|||
|
||||
public class AddSeason
|
||||
{
|
||||
public required string SeasonName { get; set; }
|
||||
public string? SeasonDescription { get; set; }
|
||||
public required string Name { get; set; }
|
||||
public string? Description { get; set; }
|
||||
public DateTime StartDate { get; set; }
|
||||
public DateTime EndDate { get; set; }
|
||||
}
|
||||
|
|
@ -6,4 +6,5 @@ public class AddTicket
|
|||
{
|
||||
public TicketType Type { get; set; }
|
||||
public Guid EventId { get; set; }
|
||||
public Guid SeasonId { get; set; } = Guid.Empty;
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
namespace models.Request;
|
||||
|
||||
public class EventSearch
|
||||
{
|
||||
public DateTime StartDate { get; set; }
|
||||
public DateTime EndDate { get; set; }
|
||||
}
|
||||
|
|
@ -6,8 +6,8 @@ public class PatchEvent
|
|||
{
|
||||
public Guid Id { get; set; }
|
||||
public DateTime Date { get; set; }
|
||||
public required string EventName { get; set; }
|
||||
public string? EventDescription { get; set; }
|
||||
public required string Name { get; set; }
|
||||
public string? Description { get; set; }
|
||||
public required Venue Venue { get; set; }
|
||||
public required Talent Talent { get; set; }
|
||||
}
|
||||
1
source/ticketUI/public/fail.svg
Normal file
1
source/ticketUI/public/fail.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e8eaed"><path d="M330-120 120-330v-300l210-210h300l210 210v300L630-120H330Zm36-190 114-114 114 114 56-56-114-114 114-114-56-56-114 114-114-114-56 56 114 114-114 114 56 56Zm-2 110h232l164-164v-232L596-760H364L200-596v232l164 164Zm116-280Z"/></svg>
|
||||
|
After Width: | Height: | Size: 345 B |
1
source/ticketUI/public/group.svg
Normal file
1
source/ticketUI/public/group.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e8eaed"><path d="M40-160v-112q0-34 17.5-62.5T104-378q62-31 126-46.5T360-440q66 0 130 15.5T616-378q29 15 46.5 43.5T680-272v112H40Zm720 0v-120q0-44-24.5-84.5T666-434q51 6 96 20.5t84 35.5q36 20 55 44.5t19 53.5v120H760ZM360-480q-66 0-113-47t-47-113q0-66 47-113t113-47q66 0 113 47t47 113q0 66-47 113t-113 47Zm400-160q0 66-47 113t-113 47q-11 0-28-2.5t-28-5.5q27-32 41.5-71t14.5-81q0-42-14.5-81T544-792q14-5 28-6.5t28-1.5q66 0 113 47t47 113ZM120-240h480v-32q0-11-5.5-20T580-306q-54-27-109-40.5T360-360q-56 0-111 13.5T140-306q-9 5-14.5 14t-5.5 20v32Zm240-320q33 0 56.5-23.5T440-640q0-33-23.5-56.5T360-720q-33 0-56.5 23.5T280-640q0 33 23.5 56.5T360-560Zm0 320Zm0-400Z"/></svg>
|
||||
|
After Width: | Height: | Size: 766 B |
1
source/ticketUI/public/pass.svg
Normal file
1
source/ticketUI/public/pass.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e8eaed"><path d="m344-60-76-128-144-32 14-148-98-112 98-112-14-148 144-32 76-128 136 58 136-58 76 128 144 32-14 148 98 112-98 112 14 148-144 32-76 128-136-58-136 58Zm34-102 102-44 104 44 56-96 110-26-10-112 74-84-74-86 10-112-110-24-58-96-102 44-104-44-56 96-110 24 10 112-74 86 74 84-10 114 110 24 58 96Zm102-318Zm-42 142 226-226-56-58-170 170-86-84-56 56 142 142Z"/></svg>
|
||||
|
After Width: | Height: | Size: 473 B |
1
source/ticketUI/public/season.svg
Normal file
1
source/ticketUI/public/season.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e8eaed"><path d="M440-122q-121-15-200.5-105.5T160-440q0-66 26-126.5T260-672l57 57q-38 34-57.5 79T240-440q0 88 56 155.5T440-202v80Zm80 0v-80q87-16 143.5-83T720-440q0-100-70-170t-170-70h-3l44 44-56 56-140-140 140-140 56 56-44 44h3q134 0 227 93t93 227q0 121-79.5 211.5T520-122Z"/></svg>
|
||||
|
After Width: | Height: | Size: 382 B |
1
source/ticketUI/public/senior.svg
Normal file
1
source/ticketUI/public/senior.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e8eaed"><path d="m320-40-64-48 104-139v-213q0-31 5-67.5t15-67.5l-60 33v142h-80v-188l176-100q25-14 43.5-21.5T494-717q25 0 45.5 21.5T587-628q32 54 58 81t56 41q11-8 19-11t19-3q25 0 43 18t18 42v420h-40v-420q0-8-6-14t-14-6q-8 0-14 6t-6 14v50h-40v-19q-54-23-84-51.5T543-557q-11 28-17.5 68.5T521-412l79 112v260h-80v-200l-71-102-9 142L320-40Zm220-700q-33 0-56.5-23.5T460-820q0-33 23.5-56.5T540-900q33 0 56.5 23.5T620-820q0 33-23.5 56.5T540-740Z"/></svg>
|
||||
|
After Width: | Height: | Size: 544 B |
1
source/ticketUI/public/single.svg
Normal file
1
source/ticketUI/public/single.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e8eaed"><path d="M480-480q-66 0-113-47t-47-113q0-66 47-113t113-47q66 0 113 47t47 113q0 66-47 113t-113 47ZM160-160v-112q0-34 17.5-62.5T224-378q62-31 126-46.5T480-440q66 0 130 15.5T736-378q29 15 46.5 43.5T800-272v112H160Zm80-80h480v-32q0-11-5.5-20T700-306q-54-27-109-40.5T480-360q-56 0-111 13.5T260-306q-9 5-14.5 14t-5.5 20v32Zm240-320q33 0 56.5-23.5T560-640q0-33-23.5-56.5T480-720q-33 0-56.5 23.5T400-640q0 33 23.5 56.5T480-560Zm0-80Zm0 400Z"/></svg>
|
||||
|
After Width: | Height: | Size: 548 B |
|
|
@ -4,4 +4,4 @@
|
|||
<div class="main">
|
||||
<router-outlet/>
|
||||
</div>
|
||||
|
||||
<app-snackbar />
|
||||
|
|
|
|||
|
|
@ -1,12 +1,14 @@
|
|||
import {Component} from '@angular/core';
|
||||
import {SidebarComponent} from './sidebar/sidebar.component';
|
||||
import {RouterOutlet} from '@angular/router';
|
||||
import {SnackbarComponent} from './snackbar/snackbar.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
imports: [
|
||||
SidebarComponent,
|
||||
RouterOutlet
|
||||
RouterOutlet,
|
||||
SnackbarComponent,
|
||||
],
|
||||
templateUrl: './app.component.html',
|
||||
styleUrl: './app.component.scss'
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
<div class="card">
|
||||
<label for="events">Events</label>
|
||||
<select name="Events" id="events">
|
||||
@for(event of events$(); track event.id) {
|
||||
<option [value]="event.id">{{event.name}}</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
import {Component, inject, OnInit} from '@angular/core';
|
||||
import {EventService} from '../services/event.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-event-browser',
|
||||
imports: [],
|
||||
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 ngOnInit() {
|
||||
this.eventService.searchAllEvents();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
import {Component, inject} from '@angular/core';
|
||||
import {TicketComponent} from "../../ticket/ticket.component";
|
||||
import {TicketService} from '../../services/ticket.service';
|
||||
import {MintRequest} from '../../../models/request/mint-request';
|
||||
import {AddTicket} from '../../../models/request/add-ticket';
|
||||
import {TicketTypeEnum} from '../../../models/enums/ticket-type.enum';
|
||||
|
||||
@Component({
|
||||
|
|
@ -16,8 +16,9 @@ export class DebugComponent {
|
|||
private ticketMinter = inject(TicketService);
|
||||
|
||||
public getQrCode(): void {
|
||||
const mintRequest: MintRequest = {
|
||||
ticketType: TicketTypeEnum.Single
|
||||
const mintRequest: AddTicket = {
|
||||
ticketType: TicketTypeEnum.Single,
|
||||
eventId: ''
|
||||
};
|
||||
|
||||
this.ticketMinter.addTicket(mintRequest);
|
||||
|
|
|
|||
|
|
@ -1 +1,44 @@
|
|||
<p>event works!</p>
|
||||
<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">
|
||||
<!-- 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>
|
||||
<button class="button" (click)="saveSeason()">Save</button>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
label {
|
||||
padding-right: 15px;
|
||||
}
|
||||
|
|
@ -1,11 +1,33 @@
|
|||
import { Component } from '@angular/core';
|
||||
import {Component, inject} from '@angular/core';
|
||||
import {FormControl, ReactiveFormsModule} from '@angular/forms';
|
||||
import {EventService} from '../../services/event.service';
|
||||
import {SeasonService} from '../../services/season.service';
|
||||
import {SeasonBrowserComponent} from '../../season-browser/season-browser.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-event',
|
||||
imports: [],
|
||||
imports: [ReactiveFormsModule, SeasonBrowserComponent],
|
||||
templateUrl: './event.component.html',
|
||||
styleUrl: './event.component.scss'
|
||||
})
|
||||
export class EventComponent {
|
||||
public eventName = new FormControl('');
|
||||
public eventDescription = new FormControl('');
|
||||
public eventDate = new FormControl(new Date);
|
||||
|
||||
public seasonName = new FormControl('');
|
||||
public seasonDescription = new FormControl('');
|
||||
public seasonStartDate = new FormControl(new Date);
|
||||
public seasonEndDate = new FormControl(new Date);
|
||||
|
||||
private eventService = inject(EventService);
|
||||
private seasonService = inject(SeasonService);
|
||||
|
||||
public saveEvent(): void {
|
||||
|
||||
}
|
||||
|
||||
public saveSeason(): void {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1 +1,4 @@
|
|||
<p>ticket works!</p>
|
||||
<div class="card">
|
||||
<h3>Generate Tickets</h3>
|
||||
<app-event-browser />
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,8 +1,11 @@
|
|||
import { Component } from '@angular/core';
|
||||
import {EventBrowserComponent} from '../../event-browser/event-browser.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-ticket',
|
||||
imports: [],
|
||||
imports: [
|
||||
EventBrowserComponent
|
||||
],
|
||||
templateUrl: './ticket.component.html',
|
||||
styleUrl: './ticket.component.scss'
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,5 +1,57 @@
|
|||
@if(ticketValidity() !== TicketValidity.Invalid && ticketType() !== TicketTypeEnum.Null) {
|
||||
<div class="card">
|
||||
|
||||
@if (ticketValidity() !== TicketValidity.Invalid && ticketType() !== TicketTypeEnum.Null) {
|
||||
<div class="card column">
|
||||
<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>
|
||||
}
|
||||
</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>
|
||||
}
|
||||
}
|
||||
</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>
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,10 +2,13 @@ import {Component, inject} from '@angular/core';
|
|||
import {TicketValidity} from '../../models/enums/ticket-validity.enum';
|
||||
import {TicketTypeEnum} from '../../models/enums/ticket-type.enum';
|
||||
import {ScanService} from '../services/scan.service';
|
||||
import {NgOptimizedImage} from '@angular/common';
|
||||
|
||||
@Component({
|
||||
selector: 'app-scan-result',
|
||||
imports: [],
|
||||
imports: [
|
||||
NgOptimizedImage
|
||||
],
|
||||
templateUrl: './scan-result.component.html',
|
||||
styleUrl: './scan-result.component.scss'
|
||||
})
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
<div class="card">
|
||||
<label for="seasons">Seasons</label>
|
||||
<select name="Seasons" id="seasons">
|
||||
@for(season of seasons$(); track season.id) {
|
||||
<option [value]="season.id">{{season.name}}</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
import {Component, inject, OnInit} from '@angular/core';
|
||||
import {SeasonService} from '../services/season.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-season-browser',
|
||||
imports: [],
|
||||
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 ngOnInit() {
|
||||
this.seasonService.getSeasons();
|
||||
}
|
||||
}
|
||||
|
|
@ -4,14 +4,17 @@ import {AddEventRequest} from '../../models/request/add-event-request';
|
|||
import {ApiUtils} from './api-utils';
|
||||
import {environment} from '../../environments/environment';
|
||||
import {Endpoints} from '../../models/endpoints';
|
||||
import {catchError, of} from 'rxjs';
|
||||
import {catchError, map, of} from 'rxjs';
|
||||
import {SnackbarService} from './snackbar.service';
|
||||
import {Event} from '../../models/core/event';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class EventService extends ApiUtils {
|
||||
public eventSignal: WritableSignal<Event | null> = signal(null);
|
||||
private httpClient = inject(HttpClient);
|
||||
private snackbar = inject(SnackbarService);
|
||||
public events$: WritableSignal<Array<Event>> = signal([]);
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
|
@ -41,22 +44,41 @@ export class EventService extends ApiUtils {
|
|||
this.httpClient.post<AddEventRequest>(url, JSON.stringify(request), options)
|
||||
.pipe(
|
||||
catchError(error => {
|
||||
console.log(error);
|
||||
this.snackbar.showError(error.error);
|
||||
return of(undefined);
|
||||
})
|
||||
).subscribe();
|
||||
}
|
||||
|
||||
public searchEvents(startDate: Date, endDate: Date): void {
|
||||
public searchAllEvents(): void {
|
||||
const options = this.setHttpRequestOptions();
|
||||
const url = environment.apiBase + Endpoints.EVENT;
|
||||
|
||||
this.httpClient.get(url, options)
|
||||
.pipe(
|
||||
map((response: any) => response.body),
|
||||
catchError(error => {
|
||||
console.log(error);
|
||||
this.snackbar.showError(error.error);
|
||||
return of(undefined);
|
||||
})
|
||||
).subscribe();
|
||||
).subscribe(res => {
|
||||
this.events$.set(res);
|
||||
});
|
||||
}
|
||||
|
||||
public searchEvents(startDate: Date, endDate: Date): void {
|
||||
const options = this.setHttpRequestOptions();
|
||||
const url = environment.apiBase + Endpoints.EVENT_DATE_SEARCH(startDate, endDate);
|
||||
|
||||
this.httpClient.get(url, options)
|
||||
.pipe(
|
||||
map((response: any) => response.body),
|
||||
catchError(error => {
|
||||
this.snackbar.showError(error.error);
|
||||
return of(undefined);
|
||||
})
|
||||
).subscribe(res => {
|
||||
this.events$.set(res);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import {Endpoints} from '../../models/endpoints';
|
|||
import {TicketSearch} from '../../models/response/ticket-search';
|
||||
import {catchError, map, of} from 'rxjs';
|
||||
import {ApiUtils} from './api-utils';
|
||||
import {SnackbarService} from './snackbar.service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
|
|
@ -15,6 +16,7 @@ export class ScanService extends ApiUtils {
|
|||
public ticketValid$: WritableSignal<TicketValidity> = signal(TicketValidity.Null);
|
||||
public ticketType$: WritableSignal<TicketTypeEnum> = signal(TicketTypeEnum.Null);
|
||||
private httpClient = inject(HttpClient);
|
||||
private snackbar = inject(SnackbarService);
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
|
@ -28,7 +30,7 @@ export class ScanService extends ApiUtils {
|
|||
.pipe(
|
||||
map((response: any) => response.body),
|
||||
catchError(error => {
|
||||
console.log(error);
|
||||
this.snackbar.showError(error.error);
|
||||
return of(undefined);
|
||||
})
|
||||
).subscribe((res: TicketSearch) => {
|
||||
|
|
|
|||
66
source/ticketUI/src/app/services/season.service.ts
Normal file
66
source/ticketUI/src/app/services/season.service.ts
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
import {inject, Injectable, signal, WritableSignal} from '@angular/core';
|
||||
import {HttpClient} from '@angular/common/http';
|
||||
import {SnackbarService} from './snackbar.service';
|
||||
import {ApiUtils} from './api-utils';
|
||||
import {Season} from '../../models/core/season';
|
||||
import {environment} from '../../environments/environment';
|
||||
import {Endpoints} from '../../models/endpoints';
|
||||
import {catchError, map, of} from 'rxjs';
|
||||
import {AddSeason} from '../../models/request/add-season';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class SeasonService extends ApiUtils {
|
||||
private httpClient = inject(HttpClient);
|
||||
private snackbar = inject(SnackbarService);
|
||||
public seasons$: WritableSignal<Array<Season>> = signal([]);
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
public getSeasons(): void {
|
||||
const options = this.setHttpRequestOptions();
|
||||
const url = environment.apiBase + Endpoints.SEASON;
|
||||
|
||||
this.httpClient.get(url, options)
|
||||
.pipe(
|
||||
map((response: any) => response.body),
|
||||
catchError(error => {
|
||||
this.snackbar.showError(error.error);
|
||||
return of(undefined);
|
||||
})
|
||||
).subscribe(res => {
|
||||
if (res !== null) {
|
||||
this.seasons$.set(res);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
public saveSeason(request: AddSeason): void {
|
||||
const options = this.setHttpRequestOptions(request);
|
||||
const url = environment.apiBase + Endpoints.SEASON;
|
||||
|
||||
this.httpClient.post(url, JSON.stringify(request), options)
|
||||
.pipe(
|
||||
catchError(error => {
|
||||
this.snackbar.showError(error.error);
|
||||
return of(undefined);
|
||||
})
|
||||
).subscribe();
|
||||
}
|
||||
|
||||
public addEventToSeason(eventId: string, seasonId: string): void {
|
||||
const options = this.setHttpRequestOptions();
|
||||
const url = environment.apiBase + Endpoints.SEASON_ADD_EVENT(eventId, seasonId);
|
||||
|
||||
this.httpClient.put(url, options)
|
||||
.pipe(
|
||||
catchError(error => {
|
||||
this.snackbar.showError(error.error);
|
||||
return of(undefined);
|
||||
})
|
||||
).subscribe();
|
||||
}
|
||||
}
|
||||
19
source/ticketUI/src/app/services/snackbar.service.ts
Normal file
19
source/ticketUI/src/app/services/snackbar.service.ts
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
import {Injectable, signal, WritableSignal} from '@angular/core';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class SnackbarService {
|
||||
public showSnackbar$: WritableSignal<boolean> = signal(false);
|
||||
public snackbarMessage$: WritableSignal<string> = signal('');
|
||||
|
||||
public showError(message: string): void {
|
||||
this.showSnackbar$.set(true);
|
||||
this.snackbarMessage$.set(message);
|
||||
|
||||
setTimeout(() => {
|
||||
this.showSnackbar$.set(false);
|
||||
this.snackbarMessage$.set('');
|
||||
}, 5000);
|
||||
}
|
||||
}
|
||||
|
|
@ -4,9 +4,10 @@ import {catchError, map, of} from 'rxjs';
|
|||
import {environment} from '../../environments/environment';
|
||||
import {MintResponse} from '../../models/response/mint-response';
|
||||
import {Endpoints} from '../../models/endpoints';
|
||||
import {MintRequest} from '../../models/request/mint-request';
|
||||
import {AddTicket} from '../../models/request/add-ticket';
|
||||
import {ApiUtils} from './api-utils';
|
||||
import {TicketSearch} from '../../models/response/ticket-search';
|
||||
import {SnackbarService} from './snackbar.service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
|
|
@ -14,12 +15,13 @@ import {TicketSearch} from '../../models/response/ticket-search';
|
|||
export class TicketService extends ApiUtils {
|
||||
public dataSignal$: WritableSignal<string> = signal('');
|
||||
private httpClient = inject(HttpClient);
|
||||
private snackbar = inject(SnackbarService);
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
public addTicket(request: MintRequest): void {
|
||||
public addTicket(request: AddTicket): void {
|
||||
const options = this.setHttpRequestOptions();
|
||||
const url = environment.apiBase + Endpoints.TICKET;
|
||||
|
||||
|
|
@ -27,7 +29,7 @@ export class TicketService extends ApiUtils {
|
|||
.pipe(
|
||||
map((response: any) => response.body),
|
||||
catchError(error => {
|
||||
console.log(error);
|
||||
this.snackbar.showError(error.error);
|
||||
return of(undefined);
|
||||
})
|
||||
).subscribe((res: MintResponse) => {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<div class="column">
|
||||
<button class="sidebar-button" [routerLink]="['/ticket']">Generate Tickets</button>
|
||||
<button class="sidebar-button" [routerLink]="['/scan']">Scan Tickets</button>
|
||||
<button class="sidebar-button" [routerLink]="['/event']">Manage Events</button>
|
||||
<button class="sidebar-button" [routerLink]="['/event']">Manage</button>
|
||||
@if(!environment.production) {
|
||||
<button class="sidebar-button" [routerLink]="['/debug']">Debug</button>
|
||||
}
|
||||
|
|
|
|||
3
source/ticketUI/src/app/snackbar/snackbar.component.html
Normal file
3
source/ticketUI/src/app/snackbar/snackbar.component.html
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
@if(showSnackbar$()) {
|
||||
<div class="snackbar">{{snackbarMessage$()}}</div>
|
||||
}
|
||||
16
source/ticketUI/src/app/snackbar/snackbar.component.scss
Normal file
16
source/ticketUI/src/app/snackbar/snackbar.component.scss
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
.snackbar {
|
||||
min-width: 250px; /* Set a default minimum width */
|
||||
margin-left: -125px; /* Divide value of min-width by 2 */
|
||||
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);
|
||||
font-size: 28px;
|
||||
text-align: center; /* Centered text */
|
||||
padding: 16px; /* Padding */
|
||||
position: fixed; /* Sit on top of the screen */
|
||||
z-index: 1; /* Add a z-index if needed */
|
||||
left: 50%; /* Center the snackbar */
|
||||
bottom: 30px; /* 30px from the bottom */
|
||||
}
|
||||
14
source/ticketUI/src/app/snackbar/snackbar.component.ts
Normal file
14
source/ticketUI/src/app/snackbar/snackbar.component.ts
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
import {Component, inject} from '@angular/core';
|
||||
import {SnackbarService} from '../services/snackbar.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-snackbar',
|
||||
imports: [],
|
||||
templateUrl: './snackbar.component.html',
|
||||
styleUrl: './snackbar.component.scss'
|
||||
})
|
||||
export class SnackbarComponent {
|
||||
public snackbar = inject(SnackbarService);
|
||||
public showSnackbar$ = this.snackbar.showSnackbar$;
|
||||
public snackbarMessage$ = this.snackbar.snackbarMessage$;
|
||||
}
|
||||
13
source/ticketUI/src/models/core/event.ts
Normal file
13
source/ticketUI/src/models/core/event.ts
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
import {Talent} from './talent';
|
||||
import {Venue} from './venue';
|
||||
|
||||
export interface Event {
|
||||
id: string,
|
||||
seasonId: string,
|
||||
date: Date,
|
||||
name: string,
|
||||
description: string | null,
|
||||
venue: Venue,
|
||||
talent: Talent,
|
||||
ticketIds: Array<string>
|
||||
}
|
||||
7
source/ticketUI/src/models/core/season.ts
Normal file
7
source/ticketUI/src/models/core/season.ts
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
export interface Season {
|
||||
id: string;
|
||||
name: string,
|
||||
description: string | null,
|
||||
startDate: Date,
|
||||
endDate: Date
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
export interface Talent {
|
||||
name: string;
|
||||
description: string;
|
||||
description: string | null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
export interface Venue {
|
||||
name: string,
|
||||
description: string,
|
||||
description: string | null,
|
||||
addressOne: string,
|
||||
addressTwo: string | null,
|
||||
city: string,
|
||||
|
|
|
|||
|
|
@ -15,10 +15,18 @@ export class Endpoints {
|
|||
}
|
||||
|
||||
/* Event Routes */
|
||||
public static readonly EVENT: string = 'events';
|
||||
public static readonly EVENT: string = 'event';
|
||||
|
||||
/* Calculated Routes */
|
||||
public static EVENT_DATE_SEARCH(startDate: Date, endDate: Date): string {
|
||||
return `${Endpoints.EVENT}?startDate=${startDate}&endDate=${endDate}`;
|
||||
}
|
||||
|
||||
/* Season Routes */
|
||||
public static readonly SEASON: string = 'season';
|
||||
|
||||
/* Calculated Routes */
|
||||
public static SEASON_ADD_EVENT(eventId: string, seasonId: string): string {
|
||||
return `${Endpoints.SEASON}?eventId=${eventId}&seasonId=${seasonId}`;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@ import {Talent} from '../core/talent';
|
|||
|
||||
export interface AddEventRequest {
|
||||
date: Date,
|
||||
eventName: string,
|
||||
eventDescription: string,
|
||||
name: string,
|
||||
description: string,
|
||||
venue: Venue,
|
||||
talent: Talent,
|
||||
}
|
||||
|
|
|
|||
6
source/ticketUI/src/models/request/add-season.ts
Normal file
6
source/ticketUI/src/models/request/add-season.ts
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
export interface AddSeason {
|
||||
name: string,
|
||||
description: string | null,
|
||||
startDate: Date,
|
||||
endDate: Date
|
||||
}
|
||||
6
source/ticketUI/src/models/request/add-ticket.ts
Normal file
6
source/ticketUI/src/models/request/add-ticket.ts
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
import {TicketTypeEnum} from '../enums/ticket-type.enum';
|
||||
|
||||
export interface AddTicket {
|
||||
ticketType: TicketTypeEnum,
|
||||
eventId: string
|
||||
}
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
import {TicketTypeEnum} from '../enums/ticket-type.enum';
|
||||
|
||||
export interface MintRequest {
|
||||
ticketType: TicketTypeEnum
|
||||
}
|
||||
|
|
@ -4,8 +4,8 @@ import {Talent} from '../core/talent';
|
|||
export interface PatchEvent {
|
||||
id: string,
|
||||
date: Date,
|
||||
eventName: string,
|
||||
eventDescription: string,
|
||||
name: string,
|
||||
description: string,
|
||||
venue: Venue,
|
||||
talent: Talent
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,6 +43,10 @@ body {
|
|||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
|
||||
&-space-between {
|
||||
justify-content: space-between;
|
||||
}
|
||||
}
|
||||
|
||||
.column {
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user