From 46b267d6729c63d0f4fa41dff68c52f7850b502d Mon Sep 17 00:00:00 2001 From: Toast Date: Tue, 28 Jan 2025 11:58:09 +0100 Subject: [PATCH 01/10] Pages/shows: show shows in a grid --- src/pages/shows/shows.component.html | 14 +++++++++++++- src/pages/shows/shows.component.ts | 18 +++++++++++++++++- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/pages/shows/shows.component.html b/src/pages/shows/shows.component.html index 5e41d99..2287da8 100644 --- a/src/pages/shows/shows.component.html +++ b/src/pages/shows/shows.component.html @@ -1 +1,13 @@ -

shows works!

+
+
+ @for (show of shows; track show._id) { +
+ +
+
{{ show.title }}
+

{{ show.year }}

+
+
+ } +
+
diff --git a/src/pages/shows/shows.component.ts b/src/pages/shows/shows.component.ts index acd48bd..d210ea2 100644 --- a/src/pages/shows/shows.component.ts +++ b/src/pages/shows/shows.component.ts @@ -1,4 +1,6 @@ -import { Component } from '@angular/core'; +import {Component, inject} from '@angular/core'; +import {ShowsApiService} from '../../shows/shows-api.service'; +import {Show, ShowsApiResponse} from '../../shows/shows-api'; @Component({ selector: 'app-shows', @@ -7,5 +9,19 @@ import { Component } from '@angular/core'; styleUrl: './shows.component.css' }) export class ShowsComponent { + private api: ShowsApiService = inject(ShowsApiService); + shows: Show[] = []; + + constructor() { + this.api.getShows().subscribe({ + next: (response: ShowsApiResponse) => { + this.shows = response.shows; + }, error: (err: any) => { + console.error("Error: ", err); + }, complete: () => { + console.log("Loaded shows") + } + }) + } } From 0a6fda151279b8405d5554a38f3f96b490e8000b Mon Sep 17 00:00:00 2001 From: Toast Date: Tue, 28 Jan 2025 12:03:53 +0100 Subject: [PATCH 02/10] Services: create and move shows-api service --- src/pages/shows/shows.component.ts | 4 ++-- src/{ => services}/shows/shows-api.service.spec.ts | 0 src/{ => services}/shows/shows-api.service.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) rename src/{ => services}/shows/shows-api.service.spec.ts (100%) rename src/{ => services}/shows/shows-api.service.ts (91%) diff --git a/src/pages/shows/shows.component.ts b/src/pages/shows/shows.component.ts index d210ea2..fdda5de 100644 --- a/src/pages/shows/shows.component.ts +++ b/src/pages/shows/shows.component.ts @@ -1,6 +1,6 @@ import {Component, inject} from '@angular/core'; -import {ShowsApiService} from '../../shows/shows-api.service'; -import {Show, ShowsApiResponse} from '../../shows/shows-api'; +import {ShowsApiService} from '../../services/shows/shows-api.service'; +import {Show, ShowsApiResponse} from '../../shows-api'; @Component({ selector: 'app-shows', diff --git a/src/shows/shows-api.service.spec.ts b/src/services/shows/shows-api.service.spec.ts similarity index 100% rename from src/shows/shows-api.service.spec.ts rename to src/services/shows/shows-api.service.spec.ts diff --git a/src/shows/shows-api.service.ts b/src/services/shows/shows-api.service.ts similarity index 91% rename from src/shows/shows-api.service.ts rename to src/services/shows/shows-api.service.ts index 9cba14c..2884a19 100644 --- a/src/shows/shows-api.service.ts +++ b/src/services/shows/shows-api.service.ts @@ -1,7 +1,7 @@ import {inject, Injectable} from '@angular/core'; import {HttpClient} from '@angular/common/http'; import {Observable} from 'rxjs'; -import {ShowsApiResponse} from './shows-api'; +import {ShowsApiResponse} from '../../shows-api'; @Injectable({ providedIn: 'root' From 22cc1dcc01222637624eb3900febf3ff4fb64e13 Mon Sep 17 00:00:00 2001 From: Toast Date: Tue, 28 Jan 2025 12:07:44 +0100 Subject: [PATCH 03/10] Interfaces: create and split shows-api.ts --- src/{shows/shows-api.ts => interfaces/show.ts} | 6 ------ src/interfaces/shows-api-response.ts | 7 +++++++ src/pages/shows/shows.component.ts | 3 ++- src/services/shows/shows-api.service.ts | 2 +- 4 files changed, 10 insertions(+), 8 deletions(-) rename src/{shows/shows-api.ts => interfaces/show.ts} (58%) create mode 100644 src/interfaces/shows-api-response.ts diff --git a/src/shows/shows-api.ts b/src/interfaces/show.ts similarity index 58% rename from src/shows/shows-api.ts rename to src/interfaces/show.ts index c3d81d9..3618e03 100644 --- a/src/shows/shows-api.ts +++ b/src/interfaces/show.ts @@ -1,9 +1,3 @@ -export interface ShowsApiResponse { - status: string - shows: Show[] - totalShows: number -} - export interface Show { _id: string title: string diff --git a/src/interfaces/shows-api-response.ts b/src/interfaces/shows-api-response.ts new file mode 100644 index 0000000..f0bf994 --- /dev/null +++ b/src/interfaces/shows-api-response.ts @@ -0,0 +1,7 @@ +import {Show} from './show'; + +export interface ShowsApiResponse { + status: string + shows: Show[] + totalShows: number +} diff --git a/src/pages/shows/shows.component.ts b/src/pages/shows/shows.component.ts index fdda5de..5fceef1 100644 --- a/src/pages/shows/shows.component.ts +++ b/src/pages/shows/shows.component.ts @@ -1,6 +1,7 @@ import {Component, inject} from '@angular/core'; import {ShowsApiService} from '../../services/shows/shows-api.service'; -import {Show, ShowsApiResponse} from '../../shows-api'; +import {Show} from '../../interfaces/show'; +import {ShowsApiResponse} from '../../interfaces/shows-api-response'; @Component({ selector: 'app-shows', diff --git a/src/services/shows/shows-api.service.ts b/src/services/shows/shows-api.service.ts index 2884a19..e89f7bf 100644 --- a/src/services/shows/shows-api.service.ts +++ b/src/services/shows/shows-api.service.ts @@ -1,7 +1,7 @@ import {inject, Injectable} from '@angular/core'; import {HttpClient} from '@angular/common/http'; import {Observable} from 'rxjs'; -import {ShowsApiResponse} from '../../shows-api'; +import {ShowsApiResponse} from '../../interfaces/shows-api-response'; @Injectable({ providedIn: 'root' From 7ee8e7e3edbf8a1ffcb08003300cf3e22dc3ba40 Mon Sep 17 00:00:00 2001 From: Toast Date: Wed, 29 Jan 2025 10:33:53 +0100 Subject: [PATCH 04/10] Services: add toast --- src/app/app.component.html | 1 + src/app/app.component.ts | 3 ++- .../toast-container.component.css | 7 ++++++ .../toast-container.component.html | 7 ++++++ .../toast-container.component.spec.ts | 23 +++++++++++++++++++ .../toast-container.component.ts | 15 ++++++++++++ src/interfaces/toast.ts | 6 +++++ src/services/toast/toast.service.spec.ts | 16 +++++++++++++ src/services/toast/toast.service.ts | 17 ++++++++++++++ 9 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 src/components/toast-container/toast-container/toast-container.component.css create mode 100644 src/components/toast-container/toast-container/toast-container.component.html create mode 100644 src/components/toast-container/toast-container/toast-container.component.spec.ts create mode 100644 src/components/toast-container/toast-container/toast-container.component.ts create mode 100644 src/interfaces/toast.ts create mode 100644 src/services/toast/toast.service.spec.ts create mode 100644 src/services/toast/toast.service.ts diff --git a/src/app/app.component.html b/src/app/app.component.html index 7dd570e..caeea25 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -1 +1,2 @@ + diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 776287c..42eed63 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -1,9 +1,10 @@ import { Component } from '@angular/core'; import { RouterOutlet } from '@angular/router'; +import {ToastContainerComponent} from '../components/toast-container/toast-container/toast-container.component'; @Component({ selector: 'app-root', - imports: [RouterOutlet], + imports: [RouterOutlet, ToastContainerComponent], templateUrl: './app.component.html', styleUrl: './app.component.css' }) diff --git a/src/components/toast-container/toast-container/toast-container.component.css b/src/components/toast-container/toast-container/toast-container.component.css new file mode 100644 index 0000000..4d1c95f --- /dev/null +++ b/src/components/toast-container/toast-container/toast-container.component.css @@ -0,0 +1,7 @@ +:host { + position: fixed; + top: 0; + right: 0; + margin: 0.5em; + z-index: 1200; +} diff --git a/src/components/toast-container/toast-container/toast-container.component.html b/src/components/toast-container/toast-container/toast-container.component.html new file mode 100644 index 0000000..35b3224 --- /dev/null +++ b/src/components/toast-container/toast-container/toast-container.component.html @@ -0,0 +1,7 @@ +@for (toast of toastService.toasts; track toast) { + {{ toast.body }} +} diff --git a/src/components/toast-container/toast-container/toast-container.component.spec.ts b/src/components/toast-container/toast-container/toast-container.component.spec.ts new file mode 100644 index 0000000..d052b36 --- /dev/null +++ b/src/components/toast-container/toast-container/toast-container.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ToastContainerComponent } from './toast-container.component'; + +describe('ToastContainerComponent', () => { + let component: ToastContainerComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ToastContainerComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(ToastContainerComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/components/toast-container/toast-container/toast-container.component.ts b/src/components/toast-container/toast-container/toast-container.component.ts new file mode 100644 index 0000000..c1eac7a --- /dev/null +++ b/src/components/toast-container/toast-container/toast-container.component.ts @@ -0,0 +1,15 @@ +import {Component, inject} from '@angular/core'; +import {ToastService} from '../../../services/toast/toast.service'; +import {NgbToast} from '@ng-bootstrap/ng-bootstrap'; + +@Component({ + selector: 'app-toast-container', + imports: [ + NgbToast + ], + templateUrl: './toast-container.component.html', + styleUrl: './toast-container.component.css' +}) +export class ToastContainerComponent { + toastService: ToastService = inject(ToastService); +} diff --git a/src/interfaces/toast.ts b/src/interfaces/toast.ts new file mode 100644 index 0000000..cb029c4 --- /dev/null +++ b/src/interfaces/toast.ts @@ -0,0 +1,6 @@ +export interface Toast { + header?: string; + body: string; + delay?: number; + htmlClass?: string; +} diff --git a/src/services/toast/toast.service.spec.ts b/src/services/toast/toast.service.spec.ts new file mode 100644 index 0000000..e0413db --- /dev/null +++ b/src/services/toast/toast.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { ToastService } from './toast.service'; + +describe('ToastService', () => { + let service: ToastService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(ToastService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/src/services/toast/toast.service.ts b/src/services/toast/toast.service.ts new file mode 100644 index 0000000..d760383 --- /dev/null +++ b/src/services/toast/toast.service.ts @@ -0,0 +1,17 @@ +import { Injectable } from '@angular/core'; +import {Toast} from '../../interfaces/toast'; + +@Injectable({ + providedIn: 'root' +}) +export class ToastService { + toasts: Toast[] = []; + + show(toast: Toast) { + this.toasts.push(toast); + } + + remove(toast: Toast) { + this.toasts = this.toasts.filter(t => t != toast); + } +} From 68c7c8e1b8e4b4f2b59b21c1bddf8df8225ad576 Mon Sep 17 00:00:00 2001 From: Toast Date: Wed, 29 Jan 2025 10:34:30 +0100 Subject: [PATCH 05/10] Pages/shows: show toasts when loading --- src/pages/shows/shows.component.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/pages/shows/shows.component.ts b/src/pages/shows/shows.component.ts index 5fceef1..32a985e 100644 --- a/src/pages/shows/shows.component.ts +++ b/src/pages/shows/shows.component.ts @@ -2,6 +2,8 @@ import {Component, inject} from '@angular/core'; import {ShowsApiService} from '../../services/shows/shows-api.service'; import {Show} from '../../interfaces/show'; import {ShowsApiResponse} from '../../interfaces/shows-api-response'; +import {Toast} from '../../interfaces/toast'; +import {ToastService} from '../../services/toast/toast.service'; @Component({ selector: 'app-shows', @@ -11,17 +13,24 @@ import {ShowsApiResponse} from '../../interfaces/shows-api-response'; }) export class ShowsComponent { private api: ShowsApiService = inject(ShowsApiService); + private toastService: ToastService = inject(ToastService); shows: Show[] = []; constructor() { + let loadToast: Toast = {body: "Loading shows..."}; + this.toastService.show(loadToast); this.api.getShows().subscribe({ next: (response: ShowsApiResponse) => { this.shows = response.shows; }, error: (err: any) => { console.error("Error: ", err); }, complete: () => { - console.log("Loaded shows") + let successToast: Toast = { + body: "Shows have been loaded!", + htmlClass: "bg-success text-light" + } + this.toastService.show(successToast); } }) } From 0c0adb08ba4ed611eb28468a699d09a9128945a6 Mon Sep 17 00:00:00 2001 From: Toast Date: Wed, 29 Jan 2025 10:56:00 +0100 Subject: [PATCH 06/10] Pages/shows: add create show button --- src/pages/shows/shows.component.html | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/pages/shows/shows.component.html b/src/pages/shows/shows.component.html index 2287da8..0184096 100644 --- a/src/pages/shows/shows.component.html +++ b/src/pages/shows/shows.component.html @@ -10,4 +10,10 @@ } +
+
+ +
+
+ From 8fa6f48b654bf7a19d3604800c4df04b443bd895 Mon Sep 17 00:00:00 2001 From: Toast Date: Wed, 29 Jan 2025 16:03:04 +0100 Subject: [PATCH 07/10] Components: add new show modal --- .../create-modal/create-modal.component.css | 0 .../create-modal/create-modal.component.html | 7 ++++++ .../create-modal.component.spec.ts | 23 +++++++++++++++++++ .../create-modal/create-modal.component.ts | 16 +++++++++++++ 4 files changed, 46 insertions(+) create mode 100644 src/components/create-modal/create-modal/create-modal.component.css create mode 100644 src/components/create-modal/create-modal/create-modal.component.html create mode 100644 src/components/create-modal/create-modal/create-modal.component.spec.ts create mode 100644 src/components/create-modal/create-modal/create-modal.component.ts diff --git a/src/components/create-modal/create-modal/create-modal.component.css b/src/components/create-modal/create-modal/create-modal.component.css new file mode 100644 index 0000000..e69de29 diff --git a/src/components/create-modal/create-modal/create-modal.component.html b/src/components/create-modal/create-modal/create-modal.component.html new file mode 100644 index 0000000..45660c2 --- /dev/null +++ b/src/components/create-modal/create-modal/create-modal.component.html @@ -0,0 +1,7 @@ + + diff --git a/src/components/create-modal/create-modal/create-modal.component.spec.ts b/src/components/create-modal/create-modal/create-modal.component.spec.ts new file mode 100644 index 0000000..c52da61 --- /dev/null +++ b/src/components/create-modal/create-modal/create-modal.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { CreateModalComponent } from './create-modal.component'; + +describe('CreateModalComponent', () => { + let component: CreateModalComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [CreateModalComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(CreateModalComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/components/create-modal/create-modal/create-modal.component.ts b/src/components/create-modal/create-modal/create-modal.component.ts new file mode 100644 index 0000000..5811767 --- /dev/null +++ b/src/components/create-modal/create-modal/create-modal.component.ts @@ -0,0 +1,16 @@ +import {Component, inject} from '@angular/core'; +import {NgbActiveModal} from '@ng-bootstrap/ng-bootstrap'; + +@Component({ + selector: 'app-create-modal', + imports: [], + templateUrl: './create-modal.component.html', + styleUrl: './create-modal.component.css' +}) +export class CreateModalComponent { + private activeModal = inject(NgbActiveModal) + + protected dismiss() { + this.activeModal.dismiss() + } +} From b92e54beab302551403a2b458642c6b5f11ebd50 Mon Sep 17 00:00:00 2001 From: Toast Date: Wed, 29 Jan 2025 17:50:16 +0100 Subject: [PATCH 08/10] Components/create-modal: add form --- .../create-modal/create-modal.component.html | 22 +++++++++++++++- .../create-modal/create-modal.component.ts | 25 ++++++++++++++++++- 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/src/components/create-modal/create-modal/create-modal.component.html b/src/components/create-modal/create-modal/create-modal.component.html index 45660c2..5a7d0cc 100644 --- a/src/components/create-modal/create-modal/create-modal.component.html +++ b/src/components/create-modal/create-modal/create-modal.component.html @@ -3,5 +3,25 @@ diff --git a/src/components/create-modal/create-modal/create-modal.component.ts b/src/components/create-modal/create-modal/create-modal.component.ts index 5811767..24931c2 100644 --- a/src/components/create-modal/create-modal/create-modal.component.ts +++ b/src/components/create-modal/create-modal/create-modal.component.ts @@ -1,16 +1,39 @@ import {Component, inject} from '@angular/core'; import {NgbActiveModal} from '@ng-bootstrap/ng-bootstrap'; +import {FormControl, FormGroup, ReactiveFormsModule, Validators} from '@angular/forms'; @Component({ selector: 'app-create-modal', - imports: [], + imports: [ + ReactiveFormsModule + ], templateUrl: './create-modal.component.html', styleUrl: './create-modal.component.css' }) export class CreateModalComponent { private activeModal = inject(NgbActiveModal) + protected newShowForm: FormGroup + + constructor() { + this.newShowForm = new FormGroup({ + title: new FormControl("", Validators.required), + year: new FormControl("", [Validators.required, Validators.min(1900)]), + seasons: new FormControl("", [Validators.required, Validators.min(1)]), + description: new FormControl("", Validators.required) + }) + } protected dismiss() { this.activeModal.dismiss() } + + protected formSubmitted(form: FormGroup) { + let show: {} = { + title: form.get("title")?.value, + year: form.get("year")?.value, + seasons: form.get("seasons")?.value, + description: form.get("description")?.value + } + console.log(show) + } } From 35ce5710791553ed2a1f24d04f4b9fe720dd63ff Mon Sep 17 00:00:00 2001 From: Toast Date: Thu, 30 Jan 2025 09:38:50 +0100 Subject: [PATCH 09/10] Services/shows: add sending show functionally --- src/services/shows/shows-api.service.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/services/shows/shows-api.service.ts b/src/services/shows/shows-api.service.ts index e89f7bf..78b3ad8 100644 --- a/src/services/shows/shows-api.service.ts +++ b/src/services/shows/shows-api.service.ts @@ -19,4 +19,8 @@ export class ShowsApiService { getShows(): Observable { return this.http.get(this.showsEndpoint) } + + sendShow(newShow: {}) { + return this.http.post(this.showsEndpoint, newShow) + } } From 93b82aedbab9b56b720d1688da0fa8f5ecb454e3 Mon Sep 17 00:00:00 2001 From: Toast Date: Thu, 30 Jan 2025 09:42:54 +0100 Subject: [PATCH 10/10] Pages/shows: add new show button --- src/pages/shows/shows.component.html | 2 +- src/pages/shows/shows.component.ts | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/pages/shows/shows.component.html b/src/pages/shows/shows.component.html index 0184096..cf63025 100644 --- a/src/pages/shows/shows.component.html +++ b/src/pages/shows/shows.component.html @@ -12,7 +12,7 @@
- +
diff --git a/src/pages/shows/shows.component.ts b/src/pages/shows/shows.component.ts index 32a985e..c37ef3b 100644 --- a/src/pages/shows/shows.component.ts +++ b/src/pages/shows/shows.component.ts @@ -4,6 +4,8 @@ import {Show} from '../../interfaces/show'; import {ShowsApiResponse} from '../../interfaces/shows-api-response'; import {Toast} from '../../interfaces/toast'; import {ToastService} from '../../services/toast/toast.service'; +import {NgbModal} from '@ng-bootstrap/ng-bootstrap'; +import {CreateModalComponent} from '../../components/create-modal/create-modal/create-modal.component'; @Component({ selector: 'app-shows', @@ -14,6 +16,7 @@ import {ToastService} from '../../services/toast/toast.service'; export class ShowsComponent { private api: ShowsApiService = inject(ShowsApiService); private toastService: ToastService = inject(ToastService); + private modalService: NgbModal = inject(NgbModal); shows: Show[] = []; @@ -34,4 +37,8 @@ export class ShowsComponent { } }) } + + createNewShow() { + this.modalService.open(CreateModalComponent) + } }