dhomie-app 0.0.7 → 0.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +273 -273
- package/fesm2022/{dhomie-app-all-polls.page-C4KixPzj.mjs → dhomie-app-all-polls.page-CHDJPbQ1.mjs} +10 -18
- package/fesm2022/dhomie-app-all-polls.page-CHDJPbQ1.mjs.map +1 -0
- package/fesm2022/{dhomie-app-all-polls.routes-PQj6MzRg.mjs → dhomie-app-all-polls.routes-DgpANHVz.mjs} +2 -2
- package/fesm2022/dhomie-app-all-polls.routes-DgpANHVz.mjs.map +1 -0
- package/fesm2022/{dhomie-app-all-schedules.page-Ddzmws9b.mjs → dhomie-app-all-schedules.page-Dkl-JtDx.mjs} +6 -6
- package/fesm2022/dhomie-app-all-schedules.page-Dkl-JtDx.mjs.map +1 -0
- package/fesm2022/{dhomie-app-all-schedules.routes-CIQfknrS.mjs → dhomie-app-all-schedules.routes-51FStFVU.mjs} +2 -2
- package/fesm2022/dhomie-app-all-schedules.routes-51FStFVU.mjs.map +1 -0
- package/fesm2022/{dhomie-app-apartment.page-C3iAYxmx.mjs → dhomie-app-apartment.page-BjLVJ9Pb.mjs} +13 -13
- package/fesm2022/dhomie-app-apartment.page-BjLVJ9Pb.mjs.map +1 -0
- package/fesm2022/{dhomie-app-apartment.routes-BT-QQjCc.mjs → dhomie-app-apartment.routes-DQAxpJcz.mjs} +2 -2
- package/fesm2022/dhomie-app-apartment.routes-DQAxpJcz.mjs.map +1 -0
- package/fesm2022/{dhomie-app-apartment.service-D80oK8mY.mjs → dhomie-app-apartment.service-CrRN-HiQ.mjs} +2 -2
- package/fesm2022/dhomie-app-apartment.service-CrRN-HiQ.mjs.map +1 -0
- package/fesm2022/{dhomie-app-chat-create.page-BlttwdJX.mjs → dhomie-app-chat-create.page-IeGCgLak.mjs} +9 -9
- package/fesm2022/dhomie-app-chat-create.page-IeGCgLak.mjs.map +1 -0
- package/fesm2022/{dhomie-app-chat.page-dc3ic19h.mjs → dhomie-app-chat.page-m4r5VFYF.mjs} +11 -11
- package/fesm2022/dhomie-app-chat.page-m4r5VFYF.mjs.map +1 -0
- package/fesm2022/{dhomie-app-chat.routes-BKOlvP3Z.mjs → dhomie-app-chat.routes-DqGBN8yd.mjs} +4 -4
- package/fesm2022/dhomie-app-chat.routes-DqGBN8yd.mjs.map +1 -0
- package/fesm2022/{dhomie-app-chat.service-XCaGObkk.mjs → dhomie-app-chat.service-ZzNV_eLL.mjs} +2 -2
- package/fesm2022/dhomie-app-chat.service-ZzNV_eLL.mjs.map +1 -0
- package/fesm2022/{dhomie-app-construction-updates.page-DWnUfrmq.mjs → dhomie-app-construction-updates.page-Co8-wuzt.mjs} +7 -7
- package/fesm2022/dhomie-app-construction-updates.page-Co8-wuzt.mjs.map +1 -0
- package/fesm2022/{dhomie-app-construction-updates.routes-DazakF3d.mjs → dhomie-app-construction-updates.routes-BvUmW9z2.mjs} +2 -2
- package/fesm2022/dhomie-app-construction-updates.routes-BvUmW9z2.mjs.map +1 -0
- package/fesm2022/{dhomie-app-construction-updates.service-La7hyNbH.mjs → dhomie-app-construction-updates.service-aNpgZ3EF.mjs} +2 -2
- package/fesm2022/dhomie-app-construction-updates.service-aNpgZ3EF.mjs.map +1 -0
- package/fesm2022/{dhomie-app-dhomie-app-D398ZdDA.mjs → dhomie-app-dhomie-app-D-S4W0r6.mjs} +67 -36
- package/fesm2022/dhomie-app-dhomie-app-D-S4W0r6.mjs.map +1 -0
- package/fesm2022/{dhomie-app-documents.page-D6Z-bBJU.mjs → dhomie-app-documents.page-Dk8VNzqR.mjs} +6 -6
- package/fesm2022/dhomie-app-documents.page-Dk8VNzqR.mjs.map +1 -0
- package/fesm2022/{dhomie-app-documents.routes-mhJqJ15p.mjs → dhomie-app-documents.routes-BEeuNuoK.mjs} +2 -2
- package/fesm2022/dhomie-app-documents.routes-BEeuNuoK.mjs.map +1 -0
- package/fesm2022/dhomie-app-edit-profile.page-_xHK2XvA.mjs +119 -0
- package/fesm2022/dhomie-app-edit-profile.page-_xHK2XvA.mjs.map +1 -0
- package/fesm2022/{dhomie-app-edit-profile.routes-rhqFhnp8.mjs → dhomie-app-edit-profile.routes-reHPipp8.mjs} +2 -2
- package/fesm2022/dhomie-app-edit-profile.routes-reHPipp8.mjs.map +1 -0
- package/fesm2022/{dhomie-app-icon.component-DS9P4GWG.mjs → dhomie-app-icon.component-COAtvd9B.mjs} +209 -209
- package/fesm2022/dhomie-app-icon.component-COAtvd9B.mjs.map +1 -0
- package/fesm2022/{dhomie-app-index-opgBKfPr.mjs → dhomie-app-index-DuuNmDzN.mjs} +63 -60
- package/fesm2022/dhomie-app-index-DuuNmDzN.mjs.map +1 -0
- package/fesm2022/{dhomie-app-language-selection.page-BPzfoyYc.mjs → dhomie-app-language-selection.page-8PW7_Bvu.mjs} +6 -6
- package/fesm2022/dhomie-app-language-selection.page-8PW7_Bvu.mjs.map +1 -0
- package/fesm2022/{dhomie-app-language-selection.routes-e7grvD6i.mjs → dhomie-app-language-selection.routes-93XvW66N.mjs} +2 -2
- package/fesm2022/dhomie-app-language-selection.routes-93XvW66N.mjs.map +1 -0
- package/fesm2022/dhomie-app-layout-action.service-FCahocPH.mjs.map +1 -1
- package/fesm2022/dhomie-app-layout-title.service-sNCGba1f.mjs.map +1 -1
- package/fesm2022/{dhomie-app-loading.component-BUk3sOe8.mjs → dhomie-app-loading.component-DIlT_dl5.mjs} +3 -3
- package/fesm2022/dhomie-app-loading.component-DIlT_dl5.mjs.map +1 -0
- package/fesm2022/{dhomie-app-main-layout.component-YSEUIffq.mjs → dhomie-app-main-layout.component-CtB15Cla.mjs} +6 -6
- package/fesm2022/dhomie-app-main-layout.component-CtB15Cla.mjs.map +1 -0
- package/fesm2022/dhomie-app-new-request.page-DN8O_Xse.mjs +117 -0
- package/fesm2022/dhomie-app-new-request.page-DN8O_Xse.mjs.map +1 -0
- package/fesm2022/{dhomie-app-new-request.routes-VOyDSZP3.mjs → dhomie-app-new-request.routes-BzMkjies.mjs} +2 -2
- package/fesm2022/dhomie-app-new-request.routes-BzMkjies.mjs.map +1 -0
- package/fesm2022/{dhomie-app-notifications.page-C5ulrqTq.mjs → dhomie-app-notifications.page-CqrK3Z67.mjs} +7 -7
- package/fesm2022/dhomie-app-notifications.page-CqrK3Z67.mjs.map +1 -0
- package/fesm2022/{dhomie-app-notifications.routes-nyJGUyAZ.mjs → dhomie-app-notifications.routes-DKYHHmZB.mjs} +2 -2
- package/fesm2022/dhomie-app-notifications.routes-DKYHHmZB.mjs.map +1 -0
- package/fesm2022/{dhomie-app-pdf-viewer.page-UpiOuN3L.mjs → dhomie-app-pdf-viewer.page-B-Qt6zC8.mjs} +6 -6
- package/fesm2022/dhomie-app-pdf-viewer.page-B-Qt6zC8.mjs.map +1 -0
- package/fesm2022/{dhomie-app-pdf-viewer.routes-CWjKohDO.mjs → dhomie-app-pdf-viewer.routes-DLvQC5th.mjs} +2 -2
- package/fesm2022/dhomie-app-pdf-viewer.routes-DLvQC5th.mjs.map +1 -0
- package/fesm2022/{dhomie-app-poll-card.component-BUyBeXNY.mjs → dhomie-app-poll-card.component-C9b51S8V.mjs} +7 -7
- package/fesm2022/dhomie-app-poll-card.component-C9b51S8V.mjs.map +1 -0
- package/fesm2022/dhomie-app-profile.page-BQTsogMh.mjs +159 -0
- package/fesm2022/dhomie-app-profile.page-BQTsogMh.mjs.map +1 -0
- package/fesm2022/{dhomie-app-profile.routes-CA1sUclX.mjs → dhomie-app-profile.routes-XTgBQNUH.mjs} +2 -2
- package/fesm2022/dhomie-app-profile.routes-XTgBQNUH.mjs.map +1 -0
- package/fesm2022/dhomie-app-request-detail.page-JNnuTngG.mjs +200 -0
- package/fesm2022/dhomie-app-request-detail.page-JNnuTngG.mjs.map +1 -0
- package/fesm2022/{dhomie-app-request-detail.routes-CMe1mA7I.mjs → dhomie-app-request-detail.routes-CGejD2C6.mjs} +2 -2
- package/fesm2022/dhomie-app-request-detail.routes-CGejD2C6.mjs.map +1 -0
- package/fesm2022/{dhomie-app-requests.page-DkPF4jxY.mjs → dhomie-app-requests.page-CddiMcTM.mjs} +15 -15
- package/fesm2022/dhomie-app-requests.page-CddiMcTM.mjs.map +1 -0
- package/fesm2022/{dhomie-app-requests.routes-BetidN1k.mjs → dhomie-app-requests.routes-Bug74pwf.mjs} +2 -2
- package/fesm2022/dhomie-app-requests.routes-Bug74pwf.mjs.map +1 -0
- package/fesm2022/{dhomie-app-requests.service-Boe4_VEq.mjs → dhomie-app-requests.service-Co3SJ-P_.mjs} +2 -2
- package/fesm2022/dhomie-app-requests.service-Co3SJ-P_.mjs.map +1 -0
- package/fesm2022/dhomie-app-select.component-DfdX6oA0.mjs +48 -0
- package/fesm2022/dhomie-app-select.component-DfdX6oA0.mjs.map +1 -0
- package/fesm2022/{dhomie-app-top-header.component-DqkZjgM1.mjs → dhomie-app-top-header.component-BOpYaP1f.mjs} +8 -8
- package/fesm2022/dhomie-app-top-header.component-BOpYaP1f.mjs.map +1 -0
- package/fesm2022/dhomie-app.mjs +1 -1
- package/package.json +1 -1
- package/styles/index.css +1 -1
- package/fesm2022/dhomie-app-all-polls.page-C4KixPzj.mjs.map +0 -1
- package/fesm2022/dhomie-app-all-polls.routes-PQj6MzRg.mjs.map +0 -1
- package/fesm2022/dhomie-app-all-schedules.page-Ddzmws9b.mjs.map +0 -1
- package/fesm2022/dhomie-app-all-schedules.routes-CIQfknrS.mjs.map +0 -1
- package/fesm2022/dhomie-app-apartment.page-C3iAYxmx.mjs.map +0 -1
- package/fesm2022/dhomie-app-apartment.routes-BT-QQjCc.mjs.map +0 -1
- package/fesm2022/dhomie-app-apartment.service-D80oK8mY.mjs.map +0 -1
- package/fesm2022/dhomie-app-chat-create.page-BlttwdJX.mjs.map +0 -1
- package/fesm2022/dhomie-app-chat.page-dc3ic19h.mjs.map +0 -1
- package/fesm2022/dhomie-app-chat.routes-BKOlvP3Z.mjs.map +0 -1
- package/fesm2022/dhomie-app-chat.service-XCaGObkk.mjs.map +0 -1
- package/fesm2022/dhomie-app-construction-updates.page-DWnUfrmq.mjs.map +0 -1
- package/fesm2022/dhomie-app-construction-updates.routes-DazakF3d.mjs.map +0 -1
- package/fesm2022/dhomie-app-construction-updates.service-La7hyNbH.mjs.map +0 -1
- package/fesm2022/dhomie-app-dhomie-app-D398ZdDA.mjs.map +0 -1
- package/fesm2022/dhomie-app-documents.page-D6Z-bBJU.mjs.map +0 -1
- package/fesm2022/dhomie-app-documents.routes-mhJqJ15p.mjs.map +0 -1
- package/fesm2022/dhomie-app-edit-profile.page-Di1u1zrr.mjs +0 -119
- package/fesm2022/dhomie-app-edit-profile.page-Di1u1zrr.mjs.map +0 -1
- package/fesm2022/dhomie-app-edit-profile.routes-rhqFhnp8.mjs.map +0 -1
- package/fesm2022/dhomie-app-icon.component-DS9P4GWG.mjs.map +0 -1
- package/fesm2022/dhomie-app-index-opgBKfPr.mjs.map +0 -1
- package/fesm2022/dhomie-app-language-selection.page-BPzfoyYc.mjs.map +0 -1
- package/fesm2022/dhomie-app-language-selection.routes-e7grvD6i.mjs.map +0 -1
- package/fesm2022/dhomie-app-loading.component-BUk3sOe8.mjs.map +0 -1
- package/fesm2022/dhomie-app-main-layout.component-YSEUIffq.mjs.map +0 -1
- package/fesm2022/dhomie-app-new-request.page-DRT_t7aC.mjs +0 -117
- package/fesm2022/dhomie-app-new-request.page-DRT_t7aC.mjs.map +0 -1
- package/fesm2022/dhomie-app-new-request.routes-VOyDSZP3.mjs.map +0 -1
- package/fesm2022/dhomie-app-notifications.page-C5ulrqTq.mjs.map +0 -1
- package/fesm2022/dhomie-app-notifications.routes-nyJGUyAZ.mjs.map +0 -1
- package/fesm2022/dhomie-app-pdf-viewer.page-UpiOuN3L.mjs.map +0 -1
- package/fesm2022/dhomie-app-pdf-viewer.routes-CWjKohDO.mjs.map +0 -1
- package/fesm2022/dhomie-app-poll-card.component-BUyBeXNY.mjs.map +0 -1
- package/fesm2022/dhomie-app-profile.page-BX8kXTDT.mjs +0 -159
- package/fesm2022/dhomie-app-profile.page-BX8kXTDT.mjs.map +0 -1
- package/fesm2022/dhomie-app-profile.routes-CA1sUclX.mjs.map +0 -1
- package/fesm2022/dhomie-app-request-detail.page-DOxZ4oek.mjs +0 -200
- package/fesm2022/dhomie-app-request-detail.page-DOxZ4oek.mjs.map +0 -1
- package/fesm2022/dhomie-app-request-detail.routes-CMe1mA7I.mjs.map +0 -1
- package/fesm2022/dhomie-app-requests.page-DkPF4jxY.mjs.map +0 -1
- package/fesm2022/dhomie-app-requests.routes-BetidN1k.mjs.map +0 -1
- package/fesm2022/dhomie-app-requests.service-Boe4_VEq.mjs.map +0 -1
- package/fesm2022/dhomie-app-select.component-B8-K6prI.mjs +0 -48
- package/fesm2022/dhomie-app-select.component-B8-K6prI.mjs.map +0 -1
- package/fesm2022/dhomie-app-top-header.component-DqkZjgM1.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -1,273 +1,273 @@
|
|
|
1
|
-
# dhomie-app
|
|
2
|
-
|
|
3
|
-
A self-contained Angular library that delivers the full DHomie feature set — OIDC authentication (PKCE), apartment management, chat, documents, schedules, and more. Works in both a Capacitor native shell (iOS / Android) and a plain Angular web app.
|
|
4
|
-
|
|
5
|
-
The consumer supplies a `MicroEnv` configuration object at route registration time. The library self-provisions all providers (OAuth, HTTP interceptor, SignalR, storage, i18n, fonts) inside a child `EnvironmentInjector` — nothing leaks into the host application.
|
|
6
|
-
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
## Table of Contents
|
|
10
|
-
|
|
11
|
-
1. [Requirements](#1-requirements)
|
|
12
|
-
2. [Installation](#2-installation)
|
|
13
|
-
3. [Styles setup](#3-styles-setup)
|
|
14
|
-
4. [Configure the environment](#4-configure-the-environment)
|
|
15
|
-
5. [Register routes in the host app](#5-register-routes-in-the-host-app)
|
|
16
|
-
6. [Trigger login](#6-trigger-login)
|
|
17
|
-
7. [Register the custom URL scheme (native only)](#7-register-the-custom-url-scheme-native-only)
|
|
18
|
-
8. [How authentication works](#8-how-authentication-works)
|
|
19
|
-
9. [Available routes](#9-available-routes)
|
|
20
|
-
10. [Publishing a new version](#10-publishing-a-new-version)
|
|
21
|
-
|
|
22
|
-
---
|
|
23
|
-
|
|
24
|
-
## 1. Requirements
|
|
25
|
-
|
|
26
|
-
| Peer dependency | Version |
|
|
27
|
-
|----------------------------------|-----------|
|
|
28
|
-
| `@angular/common` | `^20.3.0` |
|
|
29
|
-
| `@angular/core` | `^20.3.0` |
|
|
30
|
-
| `@angular/forms` | `^20.3.0` |
|
|
31
|
-
| `@angular/platform-browser` | `^20.3.0` |
|
|
32
|
-
| `@angular/router` | `^20.3.0` |
|
|
33
|
-
| `@capacitor/app` | `^7.0.0` |
|
|
34
|
-
| `@capacitor/browser` | `^7.0.0` |
|
|
35
|
-
| `@capacitor/core` | `^7.0.0` |
|
|
36
|
-
| `@capacitor/device` | `^7.0.0` |
|
|
37
|
-
| `@capacitor/preferences` | `^7.0.0` |
|
|
38
|
-
| `@capacitor/push-notifications` | `^7.0.0` |
|
|
39
|
-
| `@ionic/angular` | `^8.0.0` |
|
|
40
|
-
| `@microsoft/signalr` | `^8.0.0` |
|
|
41
|
-
| `@ngx-translate/core` | `^17.0.0` |
|
|
42
|
-
| `angular-oauth2-oidc` | `^20.0.0` |
|
|
43
|
-
|
|
44
|
-
---
|
|
45
|
-
|
|
46
|
-
## 2. Installation
|
|
47
|
-
|
|
48
|
-
```bash
|
|
49
|
-
npm install dhomie-app
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
Install any peer dependencies your host app does not already have:
|
|
53
|
-
|
|
54
|
-
```bash
|
|
55
|
-
npm install \
|
|
56
|
-
@capacitor/app @capacitor/browser @capacitor/core \
|
|
57
|
-
@capacitor/device @capacitor/preferences @capacitor/push-notifications \
|
|
58
|
-
@ionic/angular @microsoft/signalr @ngx-translate/core angular-oauth2-oidc
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
For native platforms, sync after installation:
|
|
62
|
-
|
|
63
|
-
```bash
|
|
64
|
-
npx cap sync
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
---
|
|
68
|
-
|
|
69
|
-
## 3. Styles setup
|
|
70
|
-
|
|
71
|
-
The library ships pre-compiled CSS (Tailwind utilities + design tokens + fonts) inside the npm package. Add one line to your `angular.json`:
|
|
72
|
-
|
|
73
|
-
```json
|
|
74
|
-
"styles": [
|
|
75
|
-
"src/global.scss",
|
|
76
|
-
"node_modules/dhomie-app/styles/index.css"
|
|
77
|
-
]
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
No Tailwind installation, no PostCSS config, and no `@font-face` declarations are needed in the host app. The `Montserrat arm` font is bundled inside `node_modules/dhomie-app/styles/fonts/`.
|
|
81
|
-
|
|
82
|
-
---
|
|
83
|
-
|
|
84
|
-
## 4. Configure the environment
|
|
85
|
-
|
|
86
|
-
Create an environment file that implements `MicroEnv`:
|
|
87
|
-
|
|
88
|
-
```ts
|
|
89
|
-
// src/environments/environment.ts
|
|
90
|
-
import type { MicroEnv } from 'dhomie-app';
|
|
91
|
-
|
|
92
|
-
export const environment: MicroEnv = {
|
|
93
|
-
production: false,
|
|
94
|
-
oidc: {
|
|
95
|
-
issuer: 'https://your-oidc-server.com',
|
|
96
|
-
clientId: 'web',
|
|
97
|
-
scope: 'openid profile offline_access app',
|
|
98
|
-
redirectUri: 'https://localhost:3001/login-callback', // web OAuth callback
|
|
99
|
-
responseType: 'code',
|
|
100
|
-
showDebugInformation: true,
|
|
101
|
-
useSilentRefresh: false,
|
|
102
|
-
android: {
|
|
103
|
-
clientId: 'android',
|
|
104
|
-
redirectUri: 'com.your.app:/callback',
|
|
105
|
-
},
|
|
106
|
-
ios: {
|
|
107
|
-
clientId: 'ios',
|
|
108
|
-
redirectUri: 'yourapp:/callback',
|
|
109
|
-
},
|
|
110
|
-
},
|
|
111
|
-
microApiBaseUrl: 'https://your-api.com',
|
|
112
|
-
routes: {
|
|
113
|
-
homePath: 'app', // authenticated shell: /microapp/app/...
|
|
114
|
-
callbackPath: 'login-callback', // OAuth callback: /microapp/login-callback
|
|
115
|
-
},
|
|
116
|
-
defaultLanguage: 'am', // 'am' | 'en' | 'ru'
|
|
117
|
-
};
|
|
118
|
-
```
|
|
119
|
-
|
|
120
|
-
Create a matching production file at `src/environments/environment.prod.ts` with `production: true` and your production URLs.
|
|
121
|
-
|
|
122
|
-
---
|
|
123
|
-
|
|
124
|
-
## 5. Register routes in the host app
|
|
125
|
-
|
|
126
|
-
Two routes are required: one for the web OAuth callback and one that lazy-loads the library.
|
|
127
|
-
|
|
128
|
-
```ts
|
|
129
|
-
// src/app/app.routes.ts
|
|
130
|
-
import { Routes } from '@angular/router';
|
|
131
|
-
import { OAuthCallbackComponent } from 'dhomie-app';
|
|
132
|
-
import { environment } from '../environments/environment';
|
|
133
|
-
|
|
134
|
-
export const routes: Routes = [
|
|
135
|
-
{
|
|
136
|
-
path: '',
|
|
137
|
-
loadComponent: () => import('./login/login.page').then(m => m.LoginPage),
|
|
138
|
-
},
|
|
139
|
-
{
|
|
140
|
-
// Web OAuth: the IdP redirects here, then this component forwards
|
|
141
|
-
// query params to the library's internal callback route.
|
|
142
|
-
path: 'login-callback',
|
|
143
|
-
component: OAuthCallbackComponent,
|
|
144
|
-
data: { callbackRoute: `/microapp/${environment.routes.callbackPath}` },
|
|
145
|
-
},
|
|
146
|
-
{
|
|
147
|
-
// All library routes + providers are mounted here.
|
|
148
|
-
path: 'microapp',
|
|
149
|
-
loadChildren: () => import('dhomie-app').then(m => m.MICRO_APP_ROUTES(environment)),
|
|
150
|
-
},
|
|
151
|
-
];
|
|
152
|
-
```
|
|
153
|
-
|
|
154
|
-
`MICRO_APP_ROUTES(environment)` returns the full route tree and registers all library providers inside a scoped child injector — no `providers` array changes are needed in the host `AppModule` or `bootstrapApplication`.
|
|
155
|
-
|
|
156
|
-
---
|
|
157
|
-
|
|
158
|
-
## 6. Trigger login
|
|
159
|
-
|
|
160
|
-
Navigate to the library mount path from anywhere in the host app:
|
|
161
|
-
|
|
162
|
-
```ts
|
|
163
|
-
this.router.navigate(['/microapp']);
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
The library's guard handles the rest automatically:
|
|
167
|
-
|
|
168
|
-
- **Web** — redirects `window.location` to the OIDC authorization endpoint.
|
|
169
|
-
- **Native (iOS / Android)** — opens the system browser via `@capacitor/browser`, then listens for the `appUrlOpen` deep link.
|
|
170
|
-
|
|
171
|
-
---
|
|
172
|
-
|
|
173
|
-
## 7. Register the custom URL scheme (native only)
|
|
174
|
-
|
|
175
|
-
The native OAuth callback uses a custom URL scheme. Register it in both native projects.
|
|
176
|
-
|
|
177
|
-
### iOS — `ios/App/App/Info.plist`
|
|
178
|
-
|
|
179
|
-
```xml
|
|
180
|
-
<key>CFBundleURLTypes</key>
|
|
181
|
-
<array>
|
|
182
|
-
<dict>
|
|
183
|
-
<key>CFBundleURLSchemes</key>
|
|
184
|
-
<array>
|
|
185
|
-
<string>yourapp</string>
|
|
186
|
-
</array>
|
|
187
|
-
</dict>
|
|
188
|
-
</array>
|
|
189
|
-
```
|
|
190
|
-
|
|
191
|
-
### Android — `android/app/src/main/AndroidManifest.xml`
|
|
192
|
-
|
|
193
|
-
Inside the main `<activity>` tag:
|
|
194
|
-
|
|
195
|
-
```xml
|
|
196
|
-
<intent-filter>
|
|
197
|
-
<action android:name="android.intent.action.VIEW" />
|
|
198
|
-
<category android:name="android.intent.category.DEFAULT" />
|
|
199
|
-
<category android:name="android.intent.category.BROWSABLE" />
|
|
200
|
-
<data android:scheme="com.your.app" />
|
|
201
|
-
</intent-filter>
|
|
202
|
-
```
|
|
203
|
-
|
|
204
|
-
Replace the scheme with the value you set in `oidc.android.redirectUri` and `oidc.ios.redirectUri`.
|
|
205
|
-
|
|
206
|
-
---
|
|
207
|
-
|
|
208
|
-
## 8. How authentication works
|
|
209
|
-
|
|
210
|
-
The `microAuthGuard` runs before every protected route under `/microapp/app`.
|
|
211
|
-
|
|
212
|
-
| Step | What happens |
|
|
213
|
-
|------|--------------|
|
|
214
|
-
| 1 | **Hydrate storage** — tokens are loaded from `@capacitor/preferences` into RAM (memoized). |
|
|
215
|
-
| 2 | **Check token** — if `hasValidAccessToken()` is true, navigation proceeds immediately. |
|
|
216
|
-
| 3 | **Load discovery document** — fetched once from `oidc.issuer/.well-known/openid-configuration`. |
|
|
217
|
-
| 4a | **Native** — generates PKCE URL → opens `@capacitor/browser` → listens for `appUrlOpen`. |
|
|
218
|
-
| 4b | **Web** — calls `initCodeFlow()` → browser redirects to the IdP authorization page. |
|
|
219
|
-
| 5 | **Callback** — `OAuthCallbackComponent` (web) or `appUrlOpen` (native) delivers `code` + `state` to `/microapp/login-callback`, which exchanges them for tokens. |
|
|
220
|
-
| 6 | **Token lifecycle** — proactive refresh 60 s before expiry; concurrent 401s share a single refresh lock. |
|
|
221
|
-
|
|
222
|
-
> **Cold-start edge case (native):** if the OS kills the app while the browser is open, the PKCE `code_verifier` in RAM is lost. The callback detects this and restarts the login flow from scratch. This is the accepted behavior — synchronous secure storage is not available on Capacitor.
|
|
223
|
-
|
|
224
|
-
---
|
|
225
|
-
|
|
226
|
-
## 9. Available routes
|
|
227
|
-
|
|
228
|
-
After a successful login the library serves these routes under `/microapp/app/`:
|
|
229
|
-
|
|
230
|
-
| Route | Feature |
|
|
231
|
-
|-------------------------------|--------------------------|
|
|
232
|
-
| `apartment` | Apartment overview |
|
|
233
|
-
| `chat` | Real-time chat |
|
|
234
|
-
| `requests` | Service requests list |
|
|
235
|
-
| `new-request` | Create a request |
|
|
236
|
-
| `request-detail` | Request details |
|
|
237
|
-
| `all-schedules` | Payment schedules |
|
|
238
|
-
| `all-polls` | Community polls |
|
|
239
|
-
| `documents` | Document library |
|
|
240
|
-
| `construction-updates` | Construction news |
|
|
241
|
-
| `notifications` | Push notifications list |
|
|
242
|
-
| `profile` | User profile |
|
|
243
|
-
| `edit-profile` | Edit profile |
|
|
244
|
-
| `language-selection` | Change app language |
|
|
245
|
-
| `pdf-viewer` | In-app PDF viewer |
|
|
246
|
-
|
|
247
|
-
---
|
|
248
|
-
|
|
249
|
-
## 10. Publishing a new version
|
|
250
|
-
|
|
251
|
-
Run from the **project root**:
|
|
252
|
-
|
|
253
|
-
```bash
|
|
254
|
-
# Without 2FA OTP
|
|
255
|
-
npm run publish:dhomie-app
|
|
256
|
-
|
|
257
|
-
# With 2FA OTP
|
|
258
|
-
npm run publish:dhomie-app -- 123456
|
|
259
|
-
```
|
|
260
|
-
|
|
261
|
-
The script runs these steps automatically:
|
|
262
|
-
|
|
263
|
-
| Step | Action |
|
|
264
|
-
|------|--------|
|
|
265
|
-
| 0 | Bumps the **patch** version in `projects/dhomie-app/package.json` |
|
|
266
|
-
| 1 | Builds the library (`ng build dhomie-app --configuration production`) |
|
|
267
|
-
| 1b | Compiles Tailwind CSS → `dist/dhomie-app/styles/index.css` |
|
|
268
|
-
| 1c | Copies fonts → `dist/dhomie-app/styles/fonts/` |
|
|
269
|
-
| 2 | _(no-op)_ Environment is injected at runtime via `MICRO_ENV` DI token |
|
|
270
|
-
| 3 | Removes stale source map and `.npmrc` from `dist/dhomie-app` |
|
|
271
|
-
| 4 | Publishes `./dist/dhomie-app` to npm with `--access public` |
|
|
272
|
-
|
|
273
|
-
To bump **minor** or **major** version, edit `projects/dhomie-app/package.json` manually before running the script.
|
|
1
|
+
# dhomie-app
|
|
2
|
+
|
|
3
|
+
A self-contained Angular library that delivers the full DHomie feature set — OIDC authentication (PKCE), apartment management, chat, documents, schedules, and more. Works in both a Capacitor native shell (iOS / Android) and a plain Angular web app.
|
|
4
|
+
|
|
5
|
+
The consumer supplies a `MicroEnv` configuration object at route registration time. The library self-provisions all providers (OAuth, HTTP interceptor, SignalR, storage, i18n, fonts) inside a child `EnvironmentInjector` — nothing leaks into the host application.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Table of Contents
|
|
10
|
+
|
|
11
|
+
1. [Requirements](#1-requirements)
|
|
12
|
+
2. [Installation](#2-installation)
|
|
13
|
+
3. [Styles setup](#3-styles-setup)
|
|
14
|
+
4. [Configure the environment](#4-configure-the-environment)
|
|
15
|
+
5. [Register routes in the host app](#5-register-routes-in-the-host-app)
|
|
16
|
+
6. [Trigger login](#6-trigger-login)
|
|
17
|
+
7. [Register the custom URL scheme (native only)](#7-register-the-custom-url-scheme-native-only)
|
|
18
|
+
8. [How authentication works](#8-how-authentication-works)
|
|
19
|
+
9. [Available routes](#9-available-routes)
|
|
20
|
+
10. [Publishing a new version](#10-publishing-a-new-version)
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## 1. Requirements
|
|
25
|
+
|
|
26
|
+
| Peer dependency | Version |
|
|
27
|
+
|----------------------------------|-----------|
|
|
28
|
+
| `@angular/common` | `^20.3.0` |
|
|
29
|
+
| `@angular/core` | `^20.3.0` |
|
|
30
|
+
| `@angular/forms` | `^20.3.0` |
|
|
31
|
+
| `@angular/platform-browser` | `^20.3.0` |
|
|
32
|
+
| `@angular/router` | `^20.3.0` |
|
|
33
|
+
| `@capacitor/app` | `^7.0.0` |
|
|
34
|
+
| `@capacitor/browser` | `^7.0.0` |
|
|
35
|
+
| `@capacitor/core` | `^7.0.0` |
|
|
36
|
+
| `@capacitor/device` | `^7.0.0` |
|
|
37
|
+
| `@capacitor/preferences` | `^7.0.0` |
|
|
38
|
+
| `@capacitor/push-notifications` | `^7.0.0` |
|
|
39
|
+
| `@ionic/angular` | `^8.0.0` |
|
|
40
|
+
| `@microsoft/signalr` | `^8.0.0` |
|
|
41
|
+
| `@ngx-translate/core` | `^17.0.0` |
|
|
42
|
+
| `angular-oauth2-oidc` | `^20.0.0` |
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## 2. Installation
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
npm install dhomie-app
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Install any peer dependencies your host app does not already have:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
npm install \
|
|
56
|
+
@capacitor/app @capacitor/browser @capacitor/core \
|
|
57
|
+
@capacitor/device @capacitor/preferences @capacitor/push-notifications \
|
|
58
|
+
@ionic/angular @microsoft/signalr @ngx-translate/core angular-oauth2-oidc
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
For native platforms, sync after installation:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
npx cap sync
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## 3. Styles setup
|
|
70
|
+
|
|
71
|
+
The library ships pre-compiled CSS (Tailwind utilities + design tokens + fonts) inside the npm package. Add one line to your `angular.json`:
|
|
72
|
+
|
|
73
|
+
```json
|
|
74
|
+
"styles": [
|
|
75
|
+
"src/global.scss",
|
|
76
|
+
"node_modules/dhomie-app/styles/index.css"
|
|
77
|
+
]
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
No Tailwind installation, no PostCSS config, and no `@font-face` declarations are needed in the host app. The `Montserrat arm` font is bundled inside `node_modules/dhomie-app/styles/fonts/`.
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## 4. Configure the environment
|
|
85
|
+
|
|
86
|
+
Create an environment file that implements `MicroEnv`:
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
// src/environments/environment.ts
|
|
90
|
+
import type { MicroEnv } from 'dhomie-app';
|
|
91
|
+
|
|
92
|
+
export const environment: MicroEnv = {
|
|
93
|
+
production: false,
|
|
94
|
+
oidc: {
|
|
95
|
+
issuer: 'https://your-oidc-server.com',
|
|
96
|
+
clientId: 'web',
|
|
97
|
+
scope: 'openid profile offline_access app',
|
|
98
|
+
redirectUri: 'https://localhost:3001/login-callback', // web OAuth callback
|
|
99
|
+
responseType: 'code',
|
|
100
|
+
showDebugInformation: true,
|
|
101
|
+
useSilentRefresh: false,
|
|
102
|
+
android: {
|
|
103
|
+
clientId: 'android',
|
|
104
|
+
redirectUri: 'com.your.app:/callback',
|
|
105
|
+
},
|
|
106
|
+
ios: {
|
|
107
|
+
clientId: 'ios',
|
|
108
|
+
redirectUri: 'yourapp:/callback',
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
microApiBaseUrl: 'https://your-api.com',
|
|
112
|
+
routes: {
|
|
113
|
+
homePath: 'app', // authenticated shell: /microapp/app/...
|
|
114
|
+
callbackPath: 'login-callback', // OAuth callback: /microapp/login-callback
|
|
115
|
+
},
|
|
116
|
+
defaultLanguage: 'am', // 'am' | 'en' | 'ru'
|
|
117
|
+
};
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Create a matching production file at `src/environments/environment.prod.ts` with `production: true` and your production URLs.
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## 5. Register routes in the host app
|
|
125
|
+
|
|
126
|
+
Two routes are required: one for the web OAuth callback and one that lazy-loads the library.
|
|
127
|
+
|
|
128
|
+
```ts
|
|
129
|
+
// src/app/app.routes.ts
|
|
130
|
+
import { Routes } from '@angular/router';
|
|
131
|
+
import { OAuthCallbackComponent } from 'dhomie-app';
|
|
132
|
+
import { environment } from '../environments/environment';
|
|
133
|
+
|
|
134
|
+
export const routes: Routes = [
|
|
135
|
+
{
|
|
136
|
+
path: '',
|
|
137
|
+
loadComponent: () => import('./login/login.page').then(m => m.LoginPage),
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
// Web OAuth: the IdP redirects here, then this component forwards
|
|
141
|
+
// query params to the library's internal callback route.
|
|
142
|
+
path: 'login-callback',
|
|
143
|
+
component: OAuthCallbackComponent,
|
|
144
|
+
data: { callbackRoute: `/microapp/${environment.routes.callbackPath}` },
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
// All library routes + providers are mounted here.
|
|
148
|
+
path: 'microapp',
|
|
149
|
+
loadChildren: () => import('dhomie-app').then(m => m.MICRO_APP_ROUTES(environment)),
|
|
150
|
+
},
|
|
151
|
+
];
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
`MICRO_APP_ROUTES(environment)` returns the full route tree and registers all library providers inside a scoped child injector — no `providers` array changes are needed in the host `AppModule` or `bootstrapApplication`.
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
## 6. Trigger login
|
|
159
|
+
|
|
160
|
+
Navigate to the library mount path from anywhere in the host app:
|
|
161
|
+
|
|
162
|
+
```ts
|
|
163
|
+
this.router.navigate(['/microapp']);
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
The library's guard handles the rest automatically:
|
|
167
|
+
|
|
168
|
+
- **Web** — redirects `window.location` to the OIDC authorization endpoint.
|
|
169
|
+
- **Native (iOS / Android)** — opens the system browser via `@capacitor/browser`, then listens for the `appUrlOpen` deep link.
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## 7. Register the custom URL scheme (native only)
|
|
174
|
+
|
|
175
|
+
The native OAuth callback uses a custom URL scheme. Register it in both native projects.
|
|
176
|
+
|
|
177
|
+
### iOS — `ios/App/App/Info.plist`
|
|
178
|
+
|
|
179
|
+
```xml
|
|
180
|
+
<key>CFBundleURLTypes</key>
|
|
181
|
+
<array>
|
|
182
|
+
<dict>
|
|
183
|
+
<key>CFBundleURLSchemes</key>
|
|
184
|
+
<array>
|
|
185
|
+
<string>yourapp</string>
|
|
186
|
+
</array>
|
|
187
|
+
</dict>
|
|
188
|
+
</array>
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### Android — `android/app/src/main/AndroidManifest.xml`
|
|
192
|
+
|
|
193
|
+
Inside the main `<activity>` tag:
|
|
194
|
+
|
|
195
|
+
```xml
|
|
196
|
+
<intent-filter>
|
|
197
|
+
<action android:name="android.intent.action.VIEW" />
|
|
198
|
+
<category android:name="android.intent.category.DEFAULT" />
|
|
199
|
+
<category android:name="android.intent.category.BROWSABLE" />
|
|
200
|
+
<data android:scheme="com.your.app" />
|
|
201
|
+
</intent-filter>
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
Replace the scheme with the value you set in `oidc.android.redirectUri` and `oidc.ios.redirectUri`.
|
|
205
|
+
|
|
206
|
+
---
|
|
207
|
+
|
|
208
|
+
## 8. How authentication works
|
|
209
|
+
|
|
210
|
+
The `microAuthGuard` runs before every protected route under `/microapp/app`.
|
|
211
|
+
|
|
212
|
+
| Step | What happens |
|
|
213
|
+
|------|--------------|
|
|
214
|
+
| 1 | **Hydrate storage** — tokens are loaded from `@capacitor/preferences` into RAM (memoized). |
|
|
215
|
+
| 2 | **Check token** — if `hasValidAccessToken()` is true, navigation proceeds immediately. |
|
|
216
|
+
| 3 | **Load discovery document** — fetched once from `oidc.issuer/.well-known/openid-configuration`. |
|
|
217
|
+
| 4a | **Native** — generates PKCE URL → opens `@capacitor/browser` → listens for `appUrlOpen`. |
|
|
218
|
+
| 4b | **Web** — calls `initCodeFlow()` → browser redirects to the IdP authorization page. |
|
|
219
|
+
| 5 | **Callback** — `OAuthCallbackComponent` (web) or `appUrlOpen` (native) delivers `code` + `state` to `/microapp/login-callback`, which exchanges them for tokens. |
|
|
220
|
+
| 6 | **Token lifecycle** — proactive refresh 60 s before expiry; concurrent 401s share a single refresh lock. |
|
|
221
|
+
|
|
222
|
+
> **Cold-start edge case (native):** if the OS kills the app while the browser is open, the PKCE `code_verifier` in RAM is lost. The callback detects this and restarts the login flow from scratch. This is the accepted behavior — synchronous secure storage is not available on Capacitor.
|
|
223
|
+
|
|
224
|
+
---
|
|
225
|
+
|
|
226
|
+
## 9. Available routes
|
|
227
|
+
|
|
228
|
+
After a successful login the library serves these routes under `/microapp/app/`:
|
|
229
|
+
|
|
230
|
+
| Route | Feature |
|
|
231
|
+
|-------------------------------|--------------------------|
|
|
232
|
+
| `apartment` | Apartment overview |
|
|
233
|
+
| `chat` | Real-time chat |
|
|
234
|
+
| `requests` | Service requests list |
|
|
235
|
+
| `new-request` | Create a request |
|
|
236
|
+
| `request-detail` | Request details |
|
|
237
|
+
| `all-schedules` | Payment schedules |
|
|
238
|
+
| `all-polls` | Community polls |
|
|
239
|
+
| `documents` | Document library |
|
|
240
|
+
| `construction-updates` | Construction news |
|
|
241
|
+
| `notifications` | Push notifications list |
|
|
242
|
+
| `profile` | User profile |
|
|
243
|
+
| `edit-profile` | Edit profile |
|
|
244
|
+
| `language-selection` | Change app language |
|
|
245
|
+
| `pdf-viewer` | In-app PDF viewer |
|
|
246
|
+
|
|
247
|
+
---
|
|
248
|
+
|
|
249
|
+
## 10. Publishing a new version
|
|
250
|
+
|
|
251
|
+
Run from the **project root**:
|
|
252
|
+
|
|
253
|
+
```bash
|
|
254
|
+
# Without 2FA OTP
|
|
255
|
+
npm run publish:dhomie-app
|
|
256
|
+
|
|
257
|
+
# With 2FA OTP
|
|
258
|
+
npm run publish:dhomie-app -- 123456
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
The script runs these steps automatically:
|
|
262
|
+
|
|
263
|
+
| Step | Action |
|
|
264
|
+
|------|--------|
|
|
265
|
+
| 0 | Bumps the **patch** version in `projects/dhomie-app/package.json` |
|
|
266
|
+
| 1 | Builds the library (`ng build dhomie-app --configuration production`) |
|
|
267
|
+
| 1b | Compiles Tailwind CSS → `dist/dhomie-app/styles/index.css` |
|
|
268
|
+
| 1c | Copies fonts → `dist/dhomie-app/styles/fonts/` |
|
|
269
|
+
| 2 | _(no-op)_ Environment is injected at runtime via `MICRO_ENV` DI token |
|
|
270
|
+
| 3 | Removes stale source map and `.npmrc` from `dist/dhomie-app` |
|
|
271
|
+
| 4 | Publishes `./dist/dhomie-app` to npm with `--access public` |
|
|
272
|
+
|
|
273
|
+
To bump **minor** or **major** version, edit `projects/dhomie-app/package.json` manually before running the script.
|
package/fesm2022/{dhomie-app-all-polls.page-C4KixPzj.mjs → dhomie-app-all-polls.page-CHDJPbQ1.mjs}
RENAMED
|
@@ -5,9 +5,9 @@ import { ActivatedRoute } from '@angular/router';
|
|
|
5
5
|
import { IonContent, IonInfiniteScroll, IonInfiniteScrollContent } from '@ionic/angular/standalone';
|
|
6
6
|
import { TranslatePipe } from '@ngx-translate/core';
|
|
7
7
|
import { catchError, of, map, switchMap } from 'rxjs';
|
|
8
|
-
import { D as DhLoadingComponent } from './dhomie-app-loading.component-
|
|
9
|
-
import { a as DhPollCardComponent } from './dhomie-app-poll-card.component-
|
|
10
|
-
import { d as AllPollsService, P as PollNotificationService } from './dhomie-app-dhomie-app-
|
|
8
|
+
import { D as DhLoadingComponent } from './dhomie-app-loading.component-DIlT_dl5.mjs';
|
|
9
|
+
import { a as DhPollCardComponent } from './dhomie-app-poll-card.component-C9b51S8V.mjs';
|
|
10
|
+
import { d as AllPollsService, P as PollNotificationService } from './dhomie-app-dhomie-app-D-S4W0r6.mjs';
|
|
11
11
|
|
|
12
12
|
const PAGE_SIZE = 20;
|
|
13
13
|
class AllPollsPage {
|
|
@@ -89,19 +89,11 @@ class AllPollsPage {
|
|
|
89
89
|
listenForNewPolls() {
|
|
90
90
|
this.pollNotification.pollCreated$
|
|
91
91
|
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
92
|
-
.subscribe(({
|
|
93
|
-
|
|
94
|
-
if (!communityId || !pollId) {
|
|
92
|
+
.subscribe(({ data }) => {
|
|
93
|
+
if (!data)
|
|
95
94
|
return;
|
|
96
|
-
|
|
97
|
-
this.
|
|
98
|
-
.getPoll(communityId, pollId)
|
|
99
|
-
.pipe(catchError(() => of(null)), takeUntilDestroyed(this.destroyRef))
|
|
100
|
-
.subscribe((poll) => {
|
|
101
|
-
if (poll) {
|
|
102
|
-
this.polls.update((current) => [poll, ...current]);
|
|
103
|
-
}
|
|
104
|
-
});
|
|
95
|
+
const poll = this.allPollsService.mapFromSignalR(data);
|
|
96
|
+
this.polls.update((current) => [poll, ...current]);
|
|
105
97
|
});
|
|
106
98
|
}
|
|
107
99
|
readSeedPolls() {
|
|
@@ -109,7 +101,7 @@ class AllPollsPage {
|
|
|
109
101
|
return state?.polls ?? null;
|
|
110
102
|
}
|
|
111
103
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: AllPollsPage, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
112
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.17", type: AllPollsPage, isStandalone: true, selector: "dh-all-polls-page", ngImport: i0, template: "<dh-loading [isOpen]=\"isLoading()\" />\n\n<ion-content [fullscreen]=\"true\" class=\"dh-all-polls-content\">\n <div class=\"dh-all-polls-container\">\n @if (hasError()) {\n <p class=\"dh-all-polls-state-text\">{{ 'states.loadFailed' | translate }}</p>\n } @else if (polls().length > 0) {
|
|
104
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.17", type: AllPollsPage, isStandalone: true, selector: "dh-all-polls-page", ngImport: i0, template: "<dh-loading [isOpen]=\"isLoading()\" />\r\n\r\n<ion-content [fullscreen]=\"true\" class=\"dh-all-polls-content\">\r\n <div class=\"dh-all-polls-container\">\r\n @if (hasError()) {\r\n <p class=\"dh-all-polls-state-text\">{{ 'states.loadFailed' | translate }}</p>\r\n } @else if (polls().length > 0) { @for (poll of polls(); track poll.id) {\r\n <dh-poll-card\r\n [poll]=\"poll\"\r\n (vote)=\"onVote(poll.id, $event)\"\r\n (changeAnswer)=\"onChangeAnswer(poll.id)\"\r\n ></dh-poll-card>\r\n } } @else {\r\n <p class=\"dh-all-polls-state-text\">{{ 'polls.empty' | translate }}</p>\r\n }\r\n </div>\r\n\r\n <ion-infinite-scroll\r\n [disabled]=\"!hasMore()\"\r\n (ionInfinite)=\"onIonInfinite($event)\"\r\n >\r\n <ion-infinite-scroll-content />\r\n </ion-infinite-scroll>\r\n</ion-content>\r\n", dependencies: [{ kind: "component", type: IonContent, selector: "ion-content", inputs: ["color", "fixedSlotPlacement", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type: IonInfiniteScroll, selector: "ion-infinite-scroll", inputs: ["disabled", "position", "threshold"] }, { kind: "component", type: IonInfiniteScrollContent, selector: "ion-infinite-scroll-content", inputs: ["loadingSpinner", "loadingText"] }, { kind: "component", type: DhPollCardComponent, selector: "dh-poll-card", inputs: ["poll"], outputs: ["vote", "changeAnswer"] }, { kind: "component", type: DhLoadingComponent, selector: "dh-loading", inputs: ["trigger", "isOpen", "duration", "spinner", "inline"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
113
105
|
}
|
|
114
106
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: AllPollsPage, decorators: [{
|
|
115
107
|
type: Component,
|
|
@@ -120,8 +112,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
120
112
|
TranslatePipe,
|
|
121
113
|
DhPollCardComponent,
|
|
122
114
|
DhLoadingComponent,
|
|
123
|
-
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<dh-loading [isOpen]=\"isLoading()\" />\n\n<ion-content [fullscreen]=\"true\" class=\"dh-all-polls-content\">\n <div class=\"dh-all-polls-container\">\n @if (hasError()) {\n <p class=\"dh-all-polls-state-text\">{{ 'states.loadFailed' | translate }}</p>\n } @else if (polls().length > 0) {
|
|
115
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<dh-loading [isOpen]=\"isLoading()\" />\r\n\r\n<ion-content [fullscreen]=\"true\" class=\"dh-all-polls-content\">\r\n <div class=\"dh-all-polls-container\">\r\n @if (hasError()) {\r\n <p class=\"dh-all-polls-state-text\">{{ 'states.loadFailed' | translate }}</p>\r\n } @else if (polls().length > 0) { @for (poll of polls(); track poll.id) {\r\n <dh-poll-card\r\n [poll]=\"poll\"\r\n (vote)=\"onVote(poll.id, $event)\"\r\n (changeAnswer)=\"onChangeAnswer(poll.id)\"\r\n ></dh-poll-card>\r\n } } @else {\r\n <p class=\"dh-all-polls-state-text\">{{ 'polls.empty' | translate }}</p>\r\n }\r\n </div>\r\n\r\n <ion-infinite-scroll\r\n [disabled]=\"!hasMore()\"\r\n (ionInfinite)=\"onIonInfinite($event)\"\r\n >\r\n <ion-infinite-scroll-content />\r\n </ion-infinite-scroll>\r\n</ion-content>\r\n" }]
|
|
124
116
|
}] });
|
|
125
117
|
|
|
126
118
|
export { AllPollsPage };
|
|
127
|
-
//# sourceMappingURL=dhomie-app-all-polls.page-
|
|
119
|
+
//# sourceMappingURL=dhomie-app-all-polls.page-CHDJPbQ1.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dhomie-app-all-polls.page-CHDJPbQ1.mjs","sources":["../../../projects/dhomie-app/src/lib/pages/all-polls/all-polls.page.ts","../../../projects/dhomie-app/src/lib/pages/all-polls/all-polls.page.html"],"sourcesContent":["import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n computed,\r\n DestroyRef,\r\n inject,\r\n OnInit,\r\n signal,\r\n} from '@angular/core';\r\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\r\nimport { ActivatedRoute } from '@angular/router';\r\nimport {\r\n IonContent,\r\n IonInfiniteScroll,\r\n IonInfiniteScrollContent,\r\n InfiniteScrollCustomEvent,\r\n} from '@ionic/angular/standalone';\r\nimport { TranslatePipe } from '@ngx-translate/core';\r\nimport { catchError, map, of, switchMap } from 'rxjs';\r\nimport { NewPollSignalRDto } from './all-polls.models';\r\nimport { DhLoadingComponent } from '../../components/loading/loading.component';\r\nimport { DhPollCardComponent } from '../../components/poll-card/poll-card.component';\r\nimport { DhPoll } from '../../components/poll-card/poll-card.model';\r\nimport { PollNotificationService } from '../../shared/signalr/poll-notification.service';\r\nimport { AllPollsNavigationState } from './all-polls.models';\r\nimport { AllPollsService } from './all-polls.service';\r\n\r\nconst PAGE_SIZE = 20;\r\n\r\n@Component({\r\n selector: 'dh-all-polls-page',\r\n standalone: true,\r\n imports: [\r\n IonContent,\r\n IonInfiniteScroll,\r\n IonInfiniteScrollContent,\r\n TranslatePipe,\r\n DhPollCardComponent,\r\n DhLoadingComponent,\r\n ],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n templateUrl: './all-polls.page.html',\r\n})\r\nexport class AllPollsPage implements OnInit {\r\n private readonly activatedRoute = inject(ActivatedRoute);\r\n private readonly destroyRef = inject(DestroyRef);\r\n private readonly allPollsService = inject(AllPollsService);\r\n private readonly pollNotification = inject(PollNotificationService);\r\n private readonly currentCommunityId = signal('');\r\n\r\n readonly polls = signal<DhPoll[]>(this.readSeedPolls() ?? []);\r\n readonly status = signal<'idle' | 'loading' | 'success' | 'error'>(\r\n this.polls().length ? 'success' : 'idle',\r\n );\r\n readonly isLoadingMore = signal(false);\r\n readonly hasMore = signal(false);\r\n\r\n readonly isLoading = computed(() => this.status() === 'loading');\r\n readonly hasError = computed(() => this.status() === 'error');\r\n readonly hasCommunityContext = computed(() => !!this.currentCommunityId());\r\n\r\n onVote(pollId: string, optionId: string): void {\r\n const communityId = this.currentCommunityId();\r\n if (!communityId) return;\r\n\r\n this.allPollsService\r\n .submitVote(pollId, optionId, communityId)\r\n .pipe(\r\n catchError(() => of(null)),\r\n takeUntilDestroyed(this.destroyRef),\r\n )\r\n .subscribe((result) => {\r\n if (result !== null) {\r\n this.polls.update((items) =>\r\n this.allPollsService.vote(items, pollId, optionId),\r\n );\r\n }\r\n });\r\n }\r\n\r\n onChangeAnswer(pollId: string): void {\r\n this.polls.update((items) => this.allPollsService.resetVote(items, pollId));\r\n }\r\n\r\n onIonInfinite(event: InfiniteScrollCustomEvent): void {\r\n const communityId = this.currentCommunityId();\r\n if (!communityId || this.isLoadingMore()) return;\r\n\r\n this.isLoadingMore.set(true);\r\n\r\n this.allPollsService\r\n .getPolls(communityId, { skip: this.polls().length, take: PAGE_SIZE })\r\n .pipe(\r\n catchError(() => of<DhPoll[]>([])),\r\n takeUntilDestroyed(this.destroyRef),\r\n )\r\n .subscribe((newPolls) => {\r\n this.polls.update((current) => [...current, ...newPolls]);\r\n this.hasMore.set(newPolls.length === PAGE_SIZE);\r\n this.isLoadingMore.set(false);\r\n event.target.complete();\r\n });\r\n }\r\n\r\n ngOnInit(): void {\r\n this.listenForNewPolls();\r\n\r\n this.activatedRoute.queryParamMap\r\n .pipe(\r\n map((params) => params.get('communityId') ?? ''),\r\n switchMap((communityId) => {\r\n this.currentCommunityId.set(communityId);\r\n\r\n if (!communityId) {\r\n this.status.set('idle');\r\n return of<DhPoll[] | null>(null);\r\n }\r\n\r\n this.status.set('loading');\r\n return this.allPollsService\r\n .getPolls(communityId, { skip: 0, take: PAGE_SIZE })\r\n .pipe(\r\n catchError(() => {\r\n this.status.set('error');\r\n return of<DhPoll[]>([]);\r\n }),\r\n );\r\n }),\r\n takeUntilDestroyed(this.destroyRef),\r\n )\r\n .subscribe((polls) => {\r\n if (polls === null) {\r\n this.polls.set([]);\r\n this.hasMore.set(false);\r\n return;\r\n }\r\n\r\n this.polls.set(polls);\r\n this.hasMore.set(polls.length === PAGE_SIZE);\r\n if (this.status() !== 'error') {\r\n this.status.set('success');\r\n }\r\n });\r\n }\r\n\r\n private listenForNewPolls(): void {\r\n this.pollNotification.pollCreated$\r\n .pipe(takeUntilDestroyed(this.destroyRef))\r\n .subscribe(({ data }) => {\r\n if (!data) return;\r\n const poll = this.allPollsService.mapFromSignalR(\r\n data as NewPollSignalRDto,\r\n );\r\n this.polls.update((current) => [poll, ...current]);\r\n });\r\n }\r\n\r\n private readSeedPolls(): DhPoll[] | null {\r\n const state = history.state as AllPollsNavigationState | null;\r\n return state?.polls ?? null;\r\n }\r\n}\r\n","<dh-loading [isOpen]=\"isLoading()\" />\r\n\r\n<ion-content [fullscreen]=\"true\" class=\"dh-all-polls-content\">\r\n <div class=\"dh-all-polls-container\">\r\n @if (hasError()) {\r\n <p class=\"dh-all-polls-state-text\">{{ 'states.loadFailed' | translate }}</p>\r\n } @else if (polls().length > 0) { @for (poll of polls(); track poll.id) {\r\n <dh-poll-card\r\n [poll]=\"poll\"\r\n (vote)=\"onVote(poll.id, $event)\"\r\n (changeAnswer)=\"onChangeAnswer(poll.id)\"\r\n ></dh-poll-card>\r\n } } @else {\r\n <p class=\"dh-all-polls-state-text\">{{ 'polls.empty' | translate }}</p>\r\n }\r\n </div>\r\n\r\n <ion-infinite-scroll\r\n [disabled]=\"!hasMore()\"\r\n (ionInfinite)=\"onIonInfinite($event)\"\r\n >\r\n <ion-infinite-scroll-content />\r\n </ion-infinite-scroll>\r\n</ion-content>\r\n"],"names":[],"mappings":"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"}
|