diff --git a/client/angular.json b/client/angular.json
index 421c926..92a55b1 100644
--- a/client/angular.json
+++ b/client/angular.json
@@ -59,7 +59,8 @@
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
- ]
+ ],
+ "serviceWorker": "ngsw-config.json"
},
"development": {
"optimization": false,
diff --git a/client/ngsw-config.json b/client/ngsw-config.json
new file mode 100644
index 0000000..69edd28
--- /dev/null
+++ b/client/ngsw-config.json
@@ -0,0 +1,30 @@
+{
+ "$schema": "./node_modules/@angular/service-worker/config/schema.json",
+ "index": "/index.html",
+ "assetGroups": [
+ {
+ "name": "app",
+ "installMode": "prefetch",
+ "resources": {
+ "files": [
+ "/favicon.ico",
+ "/index.csr.html",
+ "/index.html",
+ "/manifest.webmanifest",
+ "/*.css",
+ "/*.js"
+ ]
+ }
+ },
+ {
+ "name": "assets",
+ "installMode": "lazy",
+ "updateMode": "prefetch",
+ "resources": {
+ "files": [
+ "/**/*.(svg|cur|jpg|jpeg|png|apng|webp|avif|gif|otf|ttf|woff|woff2)"
+ ]
+ }
+ }
+ ]
+}
diff --git a/client/package-lock.json b/client/package-lock.json
index 298ea25..91eed1a 100644
--- a/client/package-lock.json
+++ b/client/package-lock.json
@@ -20,6 +20,7 @@
"@angular/platform-browser": "^21.1.4",
"@angular/platform-browser-dynamic": "^21.1.4",
"@angular/router": "^21.1.4",
+ "@angular/service-worker": "^21.1.4",
"@ngneat/overview": "^7.0.0",
"@ngxpert/hot-toast": "^6.1.0",
"ag-grid-angular": "^35.1.0",
@@ -1763,6 +1764,25 @@
"rxjs": "^6.5.3 || ^7.4.0"
}
},
+ "node_modules/@angular/service-worker": {
+ "version": "21.1.4",
+ "resolved": "https://registry.npmjs.org/@angular/service-worker/-/service-worker-21.1.4.tgz",
+ "integrity": "sha512-qhu/6S/mDG3R2P8QqQt7uxXf72Gc57oaHYZPg/+BGEG2t4xFdO7N0MWJacW0l5bAHJA85q/V54RBpQNGn5x6ew==",
+ "license": "MIT",
+ "dependencies": {
+ "tslib": "^2.3.0"
+ },
+ "bin": {
+ "ngsw-config": "ngsw-config.js"
+ },
+ "engines": {
+ "node": "^20.19.0 || ^22.12.0 || >=24.0.0"
+ },
+ "peerDependencies": {
+ "@angular/core": "21.1.4",
+ "rxjs": "^6.5.3 || ^7.4.0"
+ }
+ },
"node_modules/@asamuzakjp/css-color": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-4.1.2.tgz",
diff --git a/client/package.json b/client/package.json
index 01ab1a6..f8501ce 100644
--- a/client/package.json
+++ b/client/package.json
@@ -25,6 +25,7 @@
"@angular/platform-browser": "^21.1.4",
"@angular/platform-browser-dynamic": "^21.1.4",
"@angular/router": "^21.1.4",
+ "@angular/service-worker": "^21.1.4",
"@ngneat/overview": "^7.0.0",
"@ngxpert/hot-toast": "^6.1.0",
"ag-grid-angular": "^35.1.0",
@@ -49,4 +50,4 @@
"vite": "^7.3.1",
"vitest": "^4.0.18"
}
-}
+}
\ No newline at end of file
diff --git a/client/public/icons/icon-128x128.png b/client/public/icons/icon-128x128.png
new file mode 100644
index 0000000..5a9a2cc
Binary files /dev/null and b/client/public/icons/icon-128x128.png differ
diff --git a/client/public/icons/icon-144x144.png b/client/public/icons/icon-144x144.png
new file mode 100644
index 0000000..11702cd
Binary files /dev/null and b/client/public/icons/icon-144x144.png differ
diff --git a/client/public/icons/icon-152x152.png b/client/public/icons/icon-152x152.png
new file mode 100644
index 0000000..ff4e06b
Binary files /dev/null and b/client/public/icons/icon-152x152.png differ
diff --git a/client/public/icons/icon-192x192.png b/client/public/icons/icon-192x192.png
new file mode 100644
index 0000000..afd36a4
Binary files /dev/null and b/client/public/icons/icon-192x192.png differ
diff --git a/client/public/icons/icon-384x384.png b/client/public/icons/icon-384x384.png
new file mode 100644
index 0000000..613ac79
Binary files /dev/null and b/client/public/icons/icon-384x384.png differ
diff --git a/client/public/icons/icon-512x512.png b/client/public/icons/icon-512x512.png
new file mode 100644
index 0000000..7574990
Binary files /dev/null and b/client/public/icons/icon-512x512.png differ
diff --git a/client/public/icons/icon-72x72.png b/client/public/icons/icon-72x72.png
new file mode 100644
index 0000000..033724e
Binary files /dev/null and b/client/public/icons/icon-72x72.png differ
diff --git a/client/public/icons/icon-96x96.png b/client/public/icons/icon-96x96.png
new file mode 100644
index 0000000..3090dc2
Binary files /dev/null and b/client/public/icons/icon-96x96.png differ
diff --git a/client/public/manifest.webmanifest b/client/public/manifest.webmanifest
new file mode 100644
index 0000000..fc68fe9
--- /dev/null
+++ b/client/public/manifest.webmanifest
@@ -0,0 +1,57 @@
+{
+ "name": "client",
+ "short_name": "client",
+ "display": "standalone",
+ "scope": "./",
+ "start_url": "./",
+ "icons": [
+ {
+ "src": "icons/icon-72x72.png",
+ "sizes": "72x72",
+ "type": "image/png",
+ "purpose": "maskable any"
+ },
+ {
+ "src": "icons/icon-96x96.png",
+ "sizes": "96x96",
+ "type": "image/png",
+ "purpose": "maskable any"
+ },
+ {
+ "src": "icons/icon-128x128.png",
+ "sizes": "128x128",
+ "type": "image/png",
+ "purpose": "maskable any"
+ },
+ {
+ "src": "icons/icon-144x144.png",
+ "sizes": "144x144",
+ "type": "image/png",
+ "purpose": "maskable any"
+ },
+ {
+ "src": "icons/icon-152x152.png",
+ "sizes": "152x152",
+ "type": "image/png",
+ "purpose": "maskable any"
+ },
+ {
+ "src": "icons/icon-192x192.png",
+ "sizes": "192x192",
+ "type": "image/png",
+ "purpose": "maskable any"
+ },
+ {
+ "src": "icons/icon-384x384.png",
+ "sizes": "384x384",
+ "type": "image/png",
+ "purpose": "maskable any"
+ },
+ {
+ "src": "icons/icon-512x512.png",
+ "sizes": "512x512",
+ "type": "image/png",
+ "purpose": "maskable any"
+ }
+ ]
+}
diff --git a/client/src/app/app.config.ts b/client/src/app/app.config.ts
index 83078c2..30563d4 100644
--- a/client/src/app/app.config.ts
+++ b/client/src/app/app.config.ts
@@ -1,4 +1,4 @@
-import { ApplicationConfig, importProvidersFrom, provideZoneChangeDetection } from '@angular/core';
+import { ApplicationConfig, importProvidersFrom, provideZoneChangeDetection, isDevMode } from '@angular/core';
import { provideRouter } from '@angular/router';
import { provideHotToastConfig } from '@ngxpert/hot-toast';
@@ -6,6 +6,7 @@ import { routes } from './app.routes';
import { provideHttpClient, withInterceptors } from '@angular/common/http';
import { tokenInterceptor } from './core/interceptor/token.interceptor';
import { provideAnimationsAsync } from '@angular/platform-browser/animations/async';
+import { provideServiceWorker } from '@angular/service-worker';
export const appConfig: ApplicationConfig = {
providers: [provideZoneChangeDetection({ eventCoalescing: true }), provideRouter(routes), provideHttpClient(withInterceptors([tokenInterceptor]))
@@ -18,6 +19,9 @@ export const appConfig: ApplicationConfig = {
dismissible: false,
duration: 5000
}),
- provideAnimationsAsync()
+ provideAnimationsAsync(), provideServiceWorker('ngsw-worker.js', {
+ enabled: !isDevMode(),
+ registrationStrategy: 'registerWhenStable:30000'
+ })
]
};
diff --git a/client/src/index.html b/client/src/index.html
index da35e08..a6bad4e 100644
--- a/client/src/index.html
+++ b/client/src/index.html
@@ -6,10 +6,12 @@