diff --git a/booklore-api/src/main/java/com/adityachandel/booklore/controller/BookController.java b/booklore-api/src/main/java/com/adityachandel/booklore/controller/BookController.java index 0eb466523..54fa57209 100644 --- a/booklore-api/src/main/java/com/adityachandel/booklore/controller/BookController.java +++ b/booklore-api/src/main/java/com/adityachandel/booklore/controller/BookController.java @@ -36,7 +36,6 @@ public class BookController { private final BookService bookService; private final BookRecommendationService bookRecommendationService; - private final BookMetadataService bookMetadataService; @GetMapping public ResponseEntity> getBooks(@RequestParam(required = false, defaultValue = "false") boolean withDescription) { diff --git a/booklore-ui/angular.json b/booklore-ui/angular.json index 6e7c65fa1..f6fe3f088 100644 --- a/booklore-ui/angular.json +++ b/booklore-ui/angular.json @@ -71,13 +71,13 @@ "budgets": [ { "type": "initial", - "maximumWarning": "500kB", - "maximumError": "4.5MB" + "maximumWarning": "5MB", + "maximumError": "5MB" }, { "type": "anyComponentStyle", - "maximumWarning": "4kB", - "maximumError": "8kB" + "maximumWarning": "25kB", + "maximumError": "25kB" } ], "outputHashing": "all" diff --git a/booklore-ui/package-lock.json b/booklore-ui/package-lock.json index b64d804c2..47d63c9ad 100644 --- a/booklore-ui/package-lock.json +++ b/booklore-ui/package-lock.json @@ -9,6 +9,7 @@ "version": "0.0.0", "dependencies": { "@angular/animations": "^20.1.6", + "@angular/cdk": "^20.2.2", "@angular/common": "^20.1.6", "@angular/compiler": "^20.1.6", "@angular/core": "^20.1.6", @@ -23,9 +24,12 @@ "@tailwindcss/postcss": "^4.1.8", "@tweenjs/tween.js": "^25.0.0", "angular-oauth2-oidc": "^20.0.0", + "chart.js": "^4.5.0", + "chartjs-plugin-datalabels": "^2.2.0", "epubjs": "^0.3.93", "jwt-decode": "^4.0.0", "ng-lazyload-image": "^9.1.3", + "ng2-charts": "^8.0.0", "ngx-extended-pdf-viewer": "^23.3.1", "ngx-infinite-scroll": "^20.0.0", "primeicons": "^7.0.0", @@ -55,7 +59,7 @@ "karma-jasmine": "^5.1.0", "karma-jasmine-html-reporter": "^2.1.0", "tailwindcss": "3.4.17", - "typescript": "^5.8.2", + "typescript": "~5.8.2", "typescript-eslint": "^8.39.0" } }, @@ -714,11 +718,10 @@ } }, "node_modules/@angular/cdk": { - "version": "20.1.5", - "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-20.1.5.tgz", - "integrity": "sha512-uJezXaVPAbumxTCv5JA7oIuWCgPlz9/Fj6dJl6bxcRD7DfMyHGq3dtoLhthuU/uk+OfK0FlTklR92Yss5frFUw==", + "version": "20.2.2", + "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-20.2.2.tgz", + "integrity": "sha512-jLvIMmFI8zoi6vAu1Aszua59GmhqBOtsVfkwLUGg5Hi86DI/inJr9BznNX2EKDtaulYMGZCmDgsltXQXeqP5Lg==", "license": "MIT", - "peer": true, "dependencies": { "parse5": "^8.0.0", "tslib": "^2.3.0" @@ -3962,6 +3965,12 @@ "tslib": "2" } }, + "node_modules/@kurkle/color": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.4.tgz", + "integrity": "sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w==", + "license": "MIT" + }, "node_modules/@leichtgewicht/ip-codec": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", @@ -7429,6 +7438,27 @@ "dev": true, "license": "MIT" }, + "node_modules/chart.js": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.5.0.tgz", + "integrity": "sha512-aYeC/jDgSEx8SHWZvANYMioYMZ2KX02W6f6uVfyteuCGcadDLcYVHdfdygsTQkQ4TKn5lghoojAsPj5pu0SnvQ==", + "license": "MIT", + "dependencies": { + "@kurkle/color": "^0.3.0" + }, + "engines": { + "pnpm": ">=8" + } + }, + "node_modules/chartjs-plugin-datalabels": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/chartjs-plugin-datalabels/-/chartjs-plugin-datalabels-2.2.0.tgz", + "integrity": "sha512-14ZU30lH7n89oq+A4bWaJPnAG8a7ZTk7dKf48YAzMvJjQtjrgg5Dpk9f+LbjCF6bpx3RAGTeL13IXpKQYyRvlw==", + "license": "MIT", + "peerDependencies": { + "chart.js": ">=3.0.0" + } + }, "node_modules/chokidar": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", @@ -12498,6 +12528,24 @@ "rxjs": ">=6.0.0" } }, + "node_modules/ng2-charts": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/ng2-charts/-/ng2-charts-8.0.0.tgz", + "integrity": "sha512-nofsNHI2Zt+EAwT+BJBVg0kgOhNo9ukO4CxULlaIi7VwZSr7I1km38kWSoU41Oq6os6qqIh5srnL+CcV+RFPFA==", + "license": "MIT", + "dependencies": { + "lodash-es": "^4.17.15", + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@angular/cdk": ">=19.0.0", + "@angular/common": ">=19.0.0", + "@angular/core": ">=19.0.0", + "@angular/platform-browser": ">=19.0.0", + "chart.js": "^3.4.0 || ^4.0.0", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, "node_modules/ngx-extended-pdf-viewer": { "version": "23.3.1", "resolved": "https://registry.npmjs.org/ngx-extended-pdf-viewer/-/ngx-extended-pdf-viewer-23.3.1.tgz", @@ -13222,7 +13270,6 @@ "resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.0.tgz", "integrity": "sha512-9m4m5GSgXjL4AjumKzq1Fgfp3Z8rsvjRNbnkVwfu2ImRqE5D0LnY2QfDen18FSY9C573YU5XxSapdHZTZ2WolA==", "license": "MIT", - "peer": true, "dependencies": { "entities": "^6.0.0" }, @@ -13315,7 +13362,6 @@ "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", "license": "BSD-2-Clause", - "peer": true, "engines": { "node": ">=0.12" }, @@ -16277,6 +16323,7 @@ "https://github.com/sponsors/ctavan" ], "license": "MIT", + "peer": true, "bin": { "uuid": "dist/esm/bin/uuid" } diff --git a/booklore-ui/package.json b/booklore-ui/package.json index 62786daa0..69d969918 100644 --- a/booklore-ui/package.json +++ b/booklore-ui/package.json @@ -27,9 +27,12 @@ "@tailwindcss/postcss": "^4.1.8", "@tweenjs/tween.js": "^25.0.0", "angular-oauth2-oidc": "^20.0.0", + "chart.js": "^4.5.0", + "chartjs-plugin-datalabels": "^2.2.0", "epubjs": "^0.3.93", "jwt-decode": "^4.0.0", "ng-lazyload-image": "^9.1.3", + "ng2-charts": "^8.0.0", "ngx-extended-pdf-viewer": "^23.3.1", "ngx-infinite-scroll": "^20.0.0", "primeicons": "^7.0.0", @@ -40,7 +43,8 @@ "tailwindcss-primeui": "^0.6.1", "tslib": "^2.8.1", "ws": "^8.18.2", - "zone.js": "^0.15.1" + "zone.js": "^0.15.1", + "@angular/cdk": "^20.2.2" }, "devDependencies": { "@angular-devkit/build-angular": "^20.1.5", diff --git a/booklore-ui/src/app/app.routes.ts b/booklore-ui/src/app/app.routes.ts index b63c34b5d..714a68229 100644 --- a/booklore-ui/src/app/app.routes.ts +++ b/booklore-ui/src/app/app.routes.ts @@ -16,8 +16,8 @@ import {LoginGuard} from './core/setup/ login.guard'; import {OidcCallbackComponent} from './core/security/oidc-callback/oidc-callback.component'; import {CbxReaderComponent} from './book/components/cbx-reader/cbx-reader.component'; import {BookdropFileReviewComponent} from './bookdrop/bookdrop-file-review-component/bookdrop-file-review.component'; -import {MagicShelfComponent} from './magic-shelf-component/magic-shelf-component'; import {MainDashboardComponent} from './dashboard/components/main-dashboard/main-dashboard.component'; +import {StatsComponent} from './stats-component/stats-component'; export const routes: Routes = [ { @@ -44,7 +44,8 @@ export const routes: Routes = [ {path: 'unshelved-books', component: BookBrowserComponent, canActivate: [AuthGuard]}, { path: 'magic-shelf/:magicShelfId/books', component: BookBrowserComponent, canActivate: [AuthGuard] }, {path: 'book/:bookId', component: BookMetadataCenterComponent, canActivate: [AuthGuard]}, - {path: 'bookdrop', component: BookdropFileReviewComponent, canActivate: [AuthGuard]} + {path: 'bookdrop', component: BookdropFileReviewComponent, canActivate: [AuthGuard]}, + {path: 'stats', component: StatsComponent, canActivate: [AuthGuard]}, ] }, { diff --git a/booklore-ui/src/app/book/service/book.service.ts b/booklore-ui/src/app/book/service/book.service.ts index f88d83cc3..ba6a32e0c 100644 --- a/booklore-ui/src/app/book/service/book.service.ts +++ b/booklore-ui/src/app/book/service/book.service.ts @@ -67,6 +67,10 @@ export class BookService { }) ); + getCurrentBookState(): BookState { + return this.bookStateSubject.value; + } + private fetchBooks(): Observable { return this.http.get(this.url).pipe( tap(books => { diff --git a/booklore-ui/src/app/layout/component/layout-topbar/app.topbar.component.html b/booklore-ui/src/app/layout/component/layout-topbar/app.topbar.component.html index 759a19bd0..f5b9d3965 100644 --- a/booklore-ui/src/app/layout/component/layout-topbar/app.topbar.component.html +++ b/booklore-ui/src/app/layout/component/layout-topbar/app.topbar.component.html @@ -28,7 +28,7 @@