diff --git a/kontor-angular/src/app/kontor/comic/comic-artists/comic-artists.component.html b/kontor-angular/src/app/kontor/comic/comic-artists/comic-artists.component.html
index 041fe37..af4861d 100644
--- a/kontor-angular/src/app/kontor/comic/comic-artists/comic-artists.component.html
+++ b/kontor-angular/src/app/kontor/comic/comic-artists/comic-artists.component.html
@@ -8,29 +8,28 @@
{{ artist().name }}
{{ artist().name }}
+
@for (work of artist().comic_works; track work.worktype.id) {
-
@for (comic of work.comics; track comic.id) {
}
-
}
+
+
@for (work of artist().issue_works; track work.worktype.id) {
-
@for (issue of work.issues; track issue.id) {
}
-
}
+
} @else {
Artist Details
}
-
diff --git a/kontor-angular/src/app/kontor/comic/comic-comics/comic-comics.component.html b/kontor-angular/src/app/kontor/comic/comic-comics/comic-comics.component.html
index 455589b..7f8a5ac 100644
--- a/kontor-angular/src/app/kontor/comic/comic-comics/comic-comics.component.html
+++ b/kontor-angular/src/app/kontor/comic/comic-comics/comic-comics.component.html
@@ -7,17 +7,23 @@
+
+ @for (issue of comic().issues; track issue.id) {
+
+ }
+
+
@for (work of comic().works; track work.worktype.id) {
-
@for (artist of work.artists; track artist.id) {
}
-
}
+
} @else {
Comic Details
}
diff --git a/kontor-angular/src/app/kontor/comic/comic-comics/comic-comics.component.ts b/kontor-angular/src/app/kontor/comic/comic-comics/comic-comics.component.ts
index e1caf57..983f1a1 100644
--- a/kontor-angular/src/app/kontor/comic/comic-comics/comic-comics.component.ts
+++ b/kontor-angular/src/app/kontor/comic/comic-comics/comic-comics.component.ts
@@ -5,10 +5,12 @@ import { ActivatedRouteSnapshot, ResolveFn, RouterStateSnapshot } from '@angular
import { ComicService } from './comic.service';
import { ComicWorktypeComponent } from '../comic-worktype/comic-worktype.component';
import { ComicArtistComponent } from '../comic-artist/comic-artist.component';
+import { ComicIssueComponent } from '../comic-issue/comic-issue.component';
+import { ComicPublisherComponent } from "../comic-publisher/comic-publisher.component";
@Component({
selector: 'app-comic-comics',
- imports: [ComicComicsListComponent, ComicWorktypeComponent, ComicArtistComponent],
+ imports: [ComicComicsListComponent, ComicWorktypeComponent, ComicArtistComponent, ComicIssueComponent, ComicPublisherComponent],
templateUrl: './comic-comics.component.html',
styleUrl: './comic-comics.component.css'
})
diff --git a/kontor-angular/src/app/kontor/comic/comic-issue/comic-issue.component.css b/kontor-angular/src/app/kontor/comic/comic-issue/comic-issue.component.css
new file mode 100644
index 0000000..e69de29
diff --git a/kontor-angular/src/app/kontor/comic/comic-issue/comic-issue.component.html b/kontor-angular/src/app/kontor/comic/comic-issue/comic-issue.component.html
new file mode 100644
index 0000000..a96f8c1
--- /dev/null
+++ b/kontor-angular/src/app/kontor/comic/comic-issue/comic-issue.component.html
@@ -0,0 +1,5 @@
+
diff --git a/kontor-angular/src/app/kontor/comic/comic-issue/comic-issue.component.spec.ts b/kontor-angular/src/app/kontor/comic/comic-issue/comic-issue.component.spec.ts
new file mode 100644
index 0000000..51c1fb0
--- /dev/null
+++ b/kontor-angular/src/app/kontor/comic/comic-issue/comic-issue.component.spec.ts
@@ -0,0 +1,23 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { ComicIssueComponent } from './comic-issue.component';
+
+describe('ComicIssueComponent', () => {
+ let component: ComicIssueComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ imports: [ComicIssueComponent]
+ })
+ .compileComponents();
+
+ fixture = TestBed.createComponent(ComicIssueComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/kontor-angular/src/app/kontor/comic/comic-issue/comic-issue.component.ts b/kontor-angular/src/app/kontor/comic/comic-issue/comic-issue.component.ts
new file mode 100644
index 0000000..ec004e6
--- /dev/null
+++ b/kontor-angular/src/app/kontor/comic/comic-issue/comic-issue.component.ts
@@ -0,0 +1,13 @@
+import { Component, input } from '@angular/core';
+import { Issue } from '../comic.model';
+import { RouterLink, RouterLinkActive } from '@angular/router';
+
+@Component({
+ selector: 'app-comic-issue',
+ imports: [RouterLink, RouterLinkActive],
+ templateUrl: './comic-issue.component.html',
+ styleUrl: './comic-issue.component.css'
+})
+export class ComicIssueComponent {
+ issue = input.required();
+}
diff --git a/kontor-angular/src/app/kontor/comic/comic-publisher/comic-publisher.component.css b/kontor-angular/src/app/kontor/comic/comic-publisher/comic-publisher.component.css
new file mode 100644
index 0000000..e69de29
diff --git a/kontor-angular/src/app/kontor/comic/comic-publisher/comic-publisher.component.html b/kontor-angular/src/app/kontor/comic/comic-publisher/comic-publisher.component.html
new file mode 100644
index 0000000..e964901
--- /dev/null
+++ b/kontor-angular/src/app/kontor/comic/comic-publisher/comic-publisher.component.html
@@ -0,0 +1,5 @@
+
diff --git a/kontor-angular/src/app/kontor/comic/comic-publisher/comic-publisher.component.spec.ts b/kontor-angular/src/app/kontor/comic/comic-publisher/comic-publisher.component.spec.ts
new file mode 100644
index 0000000..10036f5
--- /dev/null
+++ b/kontor-angular/src/app/kontor/comic/comic-publisher/comic-publisher.component.spec.ts
@@ -0,0 +1,23 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { ComicPublisherComponent } from './comic-publisher.component';
+
+describe('ComicPublisherComponent', () => {
+ let component: ComicPublisherComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ imports: [ComicPublisherComponent]
+ })
+ .compileComponents();
+
+ fixture = TestBed.createComponent(ComicPublisherComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/kontor-angular/src/app/kontor/comic/comic-publisher/comic-publisher.component.ts b/kontor-angular/src/app/kontor/comic/comic-publisher/comic-publisher.component.ts
new file mode 100644
index 0000000..33d903b
--- /dev/null
+++ b/kontor-angular/src/app/kontor/comic/comic-publisher/comic-publisher.component.ts
@@ -0,0 +1,13 @@
+import { Component, input } from '@angular/core';
+import { Publisher } from '../comic.model';
+import { RouterLink, RouterLinkActive } from '@angular/router';
+
+@Component({
+ selector: 'app-comic-publisher',
+ imports: [RouterLink, RouterLinkActive],
+ templateUrl: './comic-publisher.component.html',
+ styleUrl: './comic-publisher.component.css'
+})
+export class ComicPublisherComponent {
+ publisher = input.required();
+}
diff --git a/kontor-angular/src/app/kontor/comic/comic-publishers-list/comic-publishers-list.component.css b/kontor-angular/src/app/kontor/comic/comic-publishers-list/comic-publishers-list.component.css
new file mode 100644
index 0000000..d95c44d
--- /dev/null
+++ b/kontor-angular/src/app/kontor/comic/comic-publishers-list/comic-publishers-list.component.css
@@ -0,0 +1,14 @@
+ul {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+ display: flex;
+ gap: 0.5rem;
+ overflow: auto;
+}
+
+@media (min-width: 768px) {
+ ul {
+ flex-direction: column;
+ }
+}
diff --git a/kontor-angular/src/app/kontor/comic/comic-publishers-list/comic-publishers-list.component.html b/kontor-angular/src/app/kontor/comic/comic-publishers-list/comic-publishers-list.component.html
new file mode 100644
index 0000000..6592f11
--- /dev/null
+++ b/kontor-angular/src/app/kontor/comic/comic-publishers-list/comic-publishers-list.component.html
@@ -0,0 +1,7 @@
+
+ @for (publisher of publishers(); track publisher.id) {
+ -
+
+
+ }
+
diff --git a/kontor-angular/src/app/kontor/comic/comic-publishers-list/comic-publishers-list.component.spec.ts b/kontor-angular/src/app/kontor/comic/comic-publishers-list/comic-publishers-list.component.spec.ts
new file mode 100644
index 0000000..c83a6fe
--- /dev/null
+++ b/kontor-angular/src/app/kontor/comic/comic-publishers-list/comic-publishers-list.component.spec.ts
@@ -0,0 +1,23 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { ComicPublishersListComponent } from './comic-publishers-list.component';
+
+describe('ComicPublishersListComponent', () => {
+ let component: ComicPublishersListComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ imports: [ComicPublishersListComponent]
+ })
+ .compileComponents();
+
+ fixture = TestBed.createComponent(ComicPublishersListComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/kontor-angular/src/app/kontor/comic/comic-publishers-list/comic-publishers-list.component.ts b/kontor-angular/src/app/kontor/comic/comic-publishers-list/comic-publishers-list.component.ts
new file mode 100644
index 0000000..6f47536
--- /dev/null
+++ b/kontor-angular/src/app/kontor/comic/comic-publishers-list/comic-publishers-list.component.ts
@@ -0,0 +1,37 @@
+import { Component, DestroyRef, inject, OnInit, signal } from '@angular/core';
+import { Publisher } from '../comic.model';
+import { PublisherService } from '../comic-publishers/publisher.service';
+import { ComicPublisherComponent } from "../comic-publisher/comic-publisher.component";
+
+@Component({
+ selector: 'app-comic-publishers-list',
+ imports: [ComicPublisherComponent],
+ templateUrl: './comic-publishers-list.component.html',
+ styleUrl: './comic-publishers-list.component.css'
+})
+export class ComicPublishersListComponent implements OnInit {
+ publishers = signal([]);
+ isFetching = signal(false);
+ error = signal('');
+ private publisherService = inject(PublisherService);
+ private destroyRef = inject(DestroyRef);
+
+ ngOnInit() {
+ this.isFetching.set(true);
+ const subscription = this.publisherService.loadPublishers().subscribe({
+ next: (publishers) => {
+ this.publishers.set(publishers);
+ },
+ error: (error: Error) => {
+ this.error.set(error.message);
+ },
+ complete: () => {
+ this.isFetching.set(false);
+ },
+ });
+
+ this.destroyRef.onDestroy(() => {
+ subscription.unsubscribe();
+ });
+ }
+}
diff --git a/kontor-angular/src/app/kontor/comic/comic-publishers/comic-publishers.component.html b/kontor-angular/src/app/kontor/comic/comic-publishers/comic-publishers.component.html
index 5917b28..3507aff 100644
--- a/kontor-angular/src/app/kontor/comic/comic-publishers/comic-publishers.component.html
+++ b/kontor-angular/src/app/kontor/comic/comic-publishers/comic-publishers.component.html
@@ -1 +1,14 @@
-comic-publishers works!
+
+
+
+ @if (publisher()) {
+
+ {{ publisher().name }}
+
+ } @else {
+
Publisher Details
+ }
+
+
diff --git a/kontor-angular/src/app/kontor/comic/comic-publishers/comic-publishers.component.ts b/kontor-angular/src/app/kontor/comic/comic-publishers/comic-publishers.component.ts
index 2b01fcc..068d81c 100644
--- a/kontor-angular/src/app/kontor/comic/comic-publishers/comic-publishers.component.ts
+++ b/kontor-angular/src/app/kontor/comic/comic-publishers/comic-publishers.component.ts
@@ -1,11 +1,23 @@
-import { Component } from '@angular/core';
+import { Component, inject, input } from '@angular/core';
+import { Publisher, PublisherDetails } from '../comic.model';
+import { ComicPublishersListComponent } from '../comic-publishers-list/comic-publishers-list.component';
+import { ActivatedRouteSnapshot, ResolveFn, RouterStateSnapshot } from '@angular/router';
+import { PublisherService } from './publisher.service';
@Component({
selector: 'app-comic-publishers',
- imports: [],
+ imports: [ComicPublishersListComponent],
templateUrl: './comic-publishers.component.html',
styleUrl: './comic-publishers.component.css'
})
export class ComicPublishersComponent {
-
+ publisher = input.required();
}
+
+export const publisherResolver: ResolveFn = (route: ActivatedRouteSnapshot, state: RouterStateSnapshot) => {
+ const publisherService = inject(PublisherService);
+ const publisherId = route.paramMap.get('publisherId');
+ const publisherDetails = publisherService.loadPublisherDetails(publisherId);
+ console.log(publisherDetails);
+ return publisherDetails;
+};
diff --git a/kontor-angular/src/app/kontor/comic/comic-publishers/publisher.service.ts b/kontor-angular/src/app/kontor/comic/comic-publishers/publisher.service.ts
new file mode 100644
index 0000000..7ff0bff
--- /dev/null
+++ b/kontor-angular/src/app/kontor/comic/comic-publishers/publisher.service.ts
@@ -0,0 +1,47 @@
+import { inject, Injectable, signal } from "@angular/core";
+import { HttpClient } from "@angular/common/http";
+import { catchError, map, throwError } from "rxjs";
+import { ErrorService } from "../../../shared/error.service";
+import { Publisher, PublisherDetails } from "../comic.model";
+
+@Injectable({
+ providedIn: 'root',
+})
+export class PublisherService {
+ private errorService = inject(ErrorService);
+ private httpClient = inject(HttpClient);
+ private publishers = signal([]);
+
+ loadedPublishers = this.publishers.asReadonly();
+
+ loadPublishers() {
+ return this.fetchPublishers('http://127.0.0.1:8800/api/comics/publishers', 'Someting went wrong fetching artists. Please try again later-');
+ }
+
+ loadPublisherDetails(artistId: string | null) {
+ return this.fetchPublisherDetails('http://127.0.0.1:8800/api/comics/publishers/' + artistId, 'Someting went wrong fetching comic artists. Please try again later.');
+ }
+
+ private fetchPublishers(url: string, errorMessage: string) {
+ return this.httpClient.get(url).pipe(
+ map((resData) => resData),
+ catchError((error) => {
+ console.log(error);
+ return throwError(() => new Error(errorMessage));
+ })
+ );
+ }
+
+ private fetchPublisherDetails(url: string, errorMessage: string) {
+ return this.httpClient.get(url).pipe(
+ map((resData) => {
+ console.log(resData);
+ return resData;
+ }),
+ catchError((error) => {
+ console.log(error);
+ return throwError(() => new Error(errorMessage));
+ })
+ );
+ }
+}
diff --git a/kontor-angular/src/app/kontor/comic/comic-section/comic-section.routes.ts b/kontor-angular/src/app/kontor/comic/comic-section/comic-section.routes.ts
index 06d5f0d..cc57991 100644
--- a/kontor-angular/src/app/kontor/comic/comic-section/comic-section.routes.ts
+++ b/kontor-angular/src/app/kontor/comic/comic-section/comic-section.routes.ts
@@ -1,6 +1,6 @@
import { Routes } from "@angular/router";
import { artistResolver, ComicArtistsComponent } from "../comic-artists/comic-artists.component";
-import { ComicPublishersComponent } from './../comic-publishers/comic-publishers.component';
+import { ComicPublishersComponent, publisherResolver } from './../comic-publishers/comic-publishers.component';
import { ComicComicsComponent, comicResolver } from "../comic-comics/comic-comics.component";
export const comicRoutes: Routes = [
@@ -20,8 +20,11 @@ export const comicRoutes: Routes = [
component: ComicPublishersComponent
},
{
- path: 'publishers/:publisherId',
+ path: 'publisher/:publisherId',
component: ComicPublishersComponent,
+ resolve: {
+ publisher: publisherResolver
+ }
},
{
path: 'artist',
diff --git a/kontor-angular/src/app/kontor/comic/comic.model.ts b/kontor-angular/src/app/kontor/comic/comic.model.ts
index 5eb3e9f..16ec960 100644
--- a/kontor-angular/src/app/kontor/comic/comic.model.ts
+++ b/kontor-angular/src/app/kontor/comic/comic.model.ts
@@ -1,5 +1,3 @@
-
-
export interface Artist {
id: string;
name: string;
@@ -10,6 +8,16 @@ export interface Worktype {
name: string;
}
+export interface Publisher {
+ id: string;
+ name: string;
+}
+
+export interface PublisherDetails {
+ id: string;
+ name: string;
+
+}
export interface Comic {
id: string;
title: string;
@@ -22,18 +30,16 @@ export interface Volume {
}
export interface Issue {
- id: string;
- issue_number: string;
- in_stock: boolean;
- is_read: boolean;
- comic: Comic;
- volume: Volume | undefined
-
+ id: string;
+ issue_number: string;
+ in_stock: boolean;
+ is_read: boolean;
+ comic: Comic;
+ volume: Volume;
}
export interface ComicWork {
worktype: string;
-
}
export interface ComicWorktypeArtists {
@@ -48,10 +54,9 @@ export interface ComicDetails {
completed: boolean;
current_order: boolean;
weblink: string;
- publisher: string;
- volumes: [
- name: string,
- ];
+ publisher: Publisher;
+ issues: Issue[];
+ volumes: Volume[];
works: ComicWorktypeArtists[];
}
diff --git a/kontor-api/src/apis/version1/comic.py b/kontor-api/src/apis/version1/comic.py
index 95fd271..3d3446a 100644
--- a/kontor-api/src/apis/version1/comic.py
+++ b/kontor-api/src/apis/version1/comic.py
@@ -1,16 +1,25 @@
from typing import List
+
from fastapi import APIRouter, HTTPException, status
from src.apis.utils import SessionDep
from src.core.log_conf import logger
+from src.db.models.comic import Artist, Comic, Issue, Publisher
from src.db.repository.comics.artist import get_artist_details
-from src.db.repository.comics.comic import get_comic_details, get_short_info, list_comics, get_issue_details
-from src.schema.comics.artist_details import ArtistDetailResponse
-from src.schema.comics.comic import ComicResponse
+from src.db.repository.comics.comic import (
+ get_comic_details,
+ get_issue_details,
+ get_short_info,
+ list_comics,
+)
+from src.db.repository.comics.publisher import get_publisher_details
from src.schema.comics.artist import ArtistCreation, ArtistResponse
-from src.db.models.comic import Comic, Artist, Issue
+from src.schema.comics.artist_details import ArtistDetailResponse
+from src.schema.comics.comic import ComicResponse
from src.schema.comics.comic_details import ComicDetailsResponse
from src.schema.comics.issue_details import IssueDetailsResponse
+from src.schema.comics.publisher import PublisherResponse
+from src.schema.comics.publisher_details import PublisherDetailsResponse
router = APIRouter()
@@ -24,6 +33,7 @@ def get_all_comics(db: SessionDep) -> List[ComicResponse]:
results.append(response)
return results
+
@router.get("/comics/{comic_id}", response_model=ComicDetailsResponse)
def get_comic(comic_id: str, db: SessionDep) -> ComicDetailsResponse:
comic = db.get(Comic, comic_id)
@@ -34,14 +44,16 @@ def get_comic(comic_id: str, db: SessionDep) -> ComicDetailsResponse:
logger.info(f"ComicDetailsResponse: {response}")
return response
+
@router.get("/artists", response_model=List[ArtistResponse])
def get_all_artists(db: SessionDep) -> List[ArtistResponse]:
results: List[ArtistResponse] = []
artists = db.query(Artist).all()
for artist in artists:
- results.append(ArtistResponse(id=artist.id, name=str(artist.name)))
+ results.append(ArtistResponse(id=artist.id, name=str(artist.name))) # type: ignore
return results
+
@router.get("/artists/{artist_id}", response_model=ArtistDetailResponse)
def get_artist(artist_id: str, db: SessionDep) -> ArtistDetailResponse:
artist = db.get(Artist, artist_id)
@@ -50,6 +62,7 @@ def get_artist(artist_id: str, db: SessionDep) -> ArtistDetailResponse:
response: ArtistDetailResponse = get_artist_details(artist)
return response
+
@router.post("/artists", status_code=status.HTTP_201_CREATED)
def add_artist(db: SessionDep, artist_creation: ArtistCreation) -> ArtistResponse:
artist: Artist = Artist()
@@ -62,6 +75,25 @@ def add_artist(db: SessionDep, artist_creation: ArtistCreation) -> ArtistRespons
response = ArtistResponse(id=artist.id, name=str(artist.name))
return response
+
+@router.get("/publishers", response_model=List[PublisherResponse])
+def get_all_publishers(db: SessionDep) -> List[PublisherResponse]:
+ results: List[PublisherResponse] = []
+ publishers = db.query(Publisher).all()
+ for publisher in publishers:
+ results.append(PublisherResponse(id=publisher.id, name=str(publisher.name)))
+ return results
+
+
+@router.get("/publishers/{publisher_id}", response_model=PublisherDetailsResponse)
+def get_publisher(publisher_id: str, db: SessionDep) -> PublisherDetailsResponse:
+ publisher = db.get(Publisher, publisher_id)
+ if publisher is None:
+ raise HTTPException(status_code=404, detail="Publisher could not be found")
+ response: PublisherDetailsResponse = get_publisher_details(publisher)
+ return response
+
+
@router.get("/issues", response_model=List[IssueDetailsResponse])
def get_issues(db: SessionDep) -> List[IssueDetailsResponse]:
results: List[IssueDetailsResponse] = []
diff --git a/kontor-api/src/db/repository/comics/publisher.py b/kontor-api/src/db/repository/comics/publisher.py
new file mode 100644
index 0000000..0b62a24
--- /dev/null
+++ b/kontor-api/src/db/repository/comics/publisher.py
@@ -0,0 +1,7 @@
+from src.db.models.comic import Publisher
+from src.schema.comics.publisher_details import PublisherDetailsResponse
+
+
+def get_publisher_details(publisher: Publisher):
+ response: PublisherDetailsResponse = PublisherDetailsResponse(id=publisher.id, name=str(publisher.name))
+ return response
diff --git a/kontor-api/src/schema/comics/publisher_details.py b/kontor-api/src/schema/comics/publisher_details.py
new file mode 100644
index 0000000..d62303a
--- /dev/null
+++ b/kontor-api/src/schema/comics/publisher_details.py
@@ -0,0 +1,5 @@
+from pydantic import BaseModel
+
+class PublisherDetailsResponse(BaseModel):
+ id: str
+ name: str