@propbinder/mobile-design 0.2.50 → 0.2.53

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.
Files changed (221) hide show
  1. package/fesm2022/propbinder-mobile-design.mjs +26206 -0
  2. package/fesm2022/propbinder-mobile-design.mjs.map +1 -0
  3. package/index.d.ts +8193 -0
  4. package/package.json +39 -3
  5. package/ng-package.json +0 -24
  6. package/src/animations/page-transitions.ts +0 -165
  7. package/src/components/action-list-item/ds-mobile-action-list-item.ts +0 -102
  8. package/src/components/action-list-item/index.ts +0 -2
  9. package/src/components/app-icon/ds-app-icon.ts +0 -133
  10. package/src/components/app-icon/index.ts +0 -2
  11. package/src/components/attachment-preview/ds-mobile-attachment-preview.css +0 -139
  12. package/src/components/attachment-preview/ds-mobile-attachment-preview.ts +0 -164
  13. package/src/components/attachment-preview/index.ts +0 -1
  14. package/src/components/avatar-with-badge/ds-avatar-with-badge.ts +0 -142
  15. package/src/components/avatar-with-badge/index.ts +0 -2
  16. package/src/components/booking-modal/ds-mobile-booking-confirmation-wrapper.ts +0 -71
  17. package/src/components/booking-modal/ds-mobile-booking-modal.service.ts +0 -121
  18. package/src/components/booking-modal/ds-mobile-booking-modal.ts +0 -598
  19. package/src/components/booking-modal/ds-mobile-booking-summary.ts +0 -161
  20. package/src/components/booking-modal/index.ts +0 -4
  21. package/src/components/bottom-sheet/ds-mobile-actions-bottom-sheet.ts +0 -266
  22. package/src/components/bottom-sheet/ds-mobile-bottom-sheet-header.ts +0 -146
  23. package/src/components/bottom-sheet/ds-mobile-bottom-sheet-wrapper.ts +0 -156
  24. package/src/components/bottom-sheet/ds-mobile-bottom-sheet.css +0 -101
  25. package/src/components/bottom-sheet/ds-mobile-bottom-sheet.service.ts +0 -169
  26. package/src/components/bottom-sheet/ds-mobile-confirmation-sheet.ts +0 -211
  27. package/src/components/bottom-sheet/ds-mobile-post-create-bottom-sheet.ts +0 -578
  28. package/src/components/bottom-sheet/ds-mobile-profile-actions-sheet.ts +0 -614
  29. package/src/components/bottom-sheet/index.ts +0 -8
  30. package/src/components/bottom-sheet/modal-shadow-fix.ts +0 -42
  31. package/src/components/card-inline/ds-mobile-card-inline.ts +0 -301
  32. package/src/components/card-inline/index.ts +0 -2
  33. package/src/components/card-inline-banner/ds-mobile-card-inline-banner.ts +0 -118
  34. package/src/components/card-inline-banner/index.ts +0 -1
  35. package/src/components/card-inline-contact/ds-mobile-card-inline-contact.ts +0 -120
  36. package/src/components/card-inline-contact/index.ts +0 -1
  37. package/src/components/card-inline-file/ds-mobile-card-inline-file.ts +0 -141
  38. package/src/components/card-inline-file/index.ts +0 -1
  39. package/src/components/chat-modal/ds-mobile-chat-modal.css +0 -159
  40. package/src/components/chat-modal/ds-mobile-chat-modal.service.ts +0 -105
  41. package/src/components/chat-modal/ds-mobile-chat-modal.ts +0 -918
  42. package/src/components/chat-modal/index.ts +0 -8
  43. package/src/components/comment/ds-mobile-comment.ts +0 -568
  44. package/src/components/comment/index.ts +0 -2
  45. package/src/components/contact-list-item/ds-mobile-contact-list-item.ts +0 -182
  46. package/src/components/contact-list-item/index.ts +0 -2
  47. package/src/components/content/ds-mobile-content.ts +0 -139
  48. package/src/components/content/index.ts +0 -2
  49. package/src/components/dropdown/ds-mobile-dropdown.css +0 -199
  50. package/src/components/dropdown/ds-mobile-dropdown.ts +0 -340
  51. package/src/components/dropdown/index.ts +0 -2
  52. package/src/components/ds-mobile-tabs.css +0 -407
  53. package/src/components/ds-mobile-tabs.ts +0 -216
  54. package/src/components/empty-state/ds-mobile-empty-state.ts +0 -120
  55. package/src/components/empty-state/index.ts +0 -2
  56. package/src/components/fab/ds-mobile-fab.ts +0 -315
  57. package/src/components/fab/index.ts +0 -1
  58. package/src/components/facility-creation-modal/ds-mobile-facility-creation-confirmation-wrapper.ts +0 -121
  59. package/src/components/facility-creation-modal/ds-mobile-facility-creation-modal.css +0 -189
  60. package/src/components/facility-creation-modal/ds-mobile-facility-creation-modal.service.ts +0 -135
  61. package/src/components/facility-creation-modal/ds-mobile-facility-creation-modal.ts +0 -656
  62. package/src/components/facility-creation-modal/index.ts +0 -9
  63. package/src/components/facility-creation-modal/sheets/ds-mobile-access-sheet.ts +0 -105
  64. package/src/components/facility-creation-modal/sheets/ds-mobile-price-sheet.ts +0 -188
  65. package/src/components/facility-creation-modal/sheets/ds-mobile-when-can-book-sheet.ts +0 -460
  66. package/src/components/facility-creation-modal/sheets/ds-mobile-who-can-book-sheet.ts +0 -134
  67. package/src/components/facility-detail-modal/ds-mobile-facility-detail-modal.service.ts +0 -69
  68. package/src/components/facility-detail-modal/ds-mobile-facility-detail-modal.ts +0 -379
  69. package/src/components/facility-detail-modal/index.ts +0 -2
  70. package/src/components/file-attachment/ds-mobile-file-attachment.ts +0 -164
  71. package/src/components/file-attachment/index.ts +0 -2
  72. package/src/components/handbook-detail-modal/ds-mobile-handbook-detail-modal.css +0 -214
  73. package/src/components/handbook-detail-modal/ds-mobile-handbook-detail-modal.service.ts +0 -84
  74. package/src/components/handbook-detail-modal/ds-mobile-handbook-detail-modal.ts +0 -424
  75. package/src/components/handbook-detail-modal/index.ts +0 -3
  76. package/src/components/handbook-folder/ds-mobile-handbook-folder-mini.ts +0 -175
  77. package/src/components/handbook-folder/ds-mobile-handbook-folder.ts +0 -533
  78. package/src/components/handbook-folder/index.ts +0 -4
  79. package/src/components/header-content/ds-mobile-header-content.ts +0 -222
  80. package/src/components/header-content/index.ts +0 -2
  81. package/src/components/illustration/ds-mobile-illustration.ts +0 -124
  82. package/src/components/illustration/index.ts +0 -2
  83. package/src/components/index.ts +0 -124
  84. package/src/components/inline-photo/ds-mobile-inline-photo.ts +0 -361
  85. package/src/components/inline-photo/index.ts +0 -1
  86. package/src/components/inline-tabs/ds-mobile-inline-tabs.ts +0 -132
  87. package/src/components/inline-tabs/index.ts +0 -2
  88. package/src/components/interactive-list-item-booking/ds-mobile-interactive-list-item-booking.ts +0 -350
  89. package/src/components/interactive-list-item-booking/index.ts +0 -1
  90. package/src/components/interactive-list-item-inquiry/ds-mobile-interactive-list-item-inquiry.ts +0 -321
  91. package/src/components/interactive-list-item-inquiry/index.ts +0 -2
  92. package/src/components/interactive-list-item-message/ds-mobile-interactive-list-item-message.ts +0 -237
  93. package/src/components/interactive-list-item-message/index.ts +0 -2
  94. package/src/components/interactive-list-item-post/ds-mobile-interactive-list-item-post.ts +0 -549
  95. package/src/components/interactive-list-item-post/ds-mobile-post-pdf-attachment.ts +0 -124
  96. package/src/components/interactive-list-item-post/index.ts +0 -13
  97. package/src/components/lightbox/ds-mobile-lightbox-footer.ts +0 -315
  98. package/src/components/lightbox/ds-mobile-lightbox-header.ts +0 -202
  99. package/src/components/lightbox/ds-mobile-lightbox-image.ts +0 -484
  100. package/src/components/lightbox/ds-mobile-lightbox-pdf.css +0 -377
  101. package/src/components/lightbox/ds-mobile-lightbox-pdf.ts +0 -374
  102. package/src/components/lightbox/ds-mobile-lightbox.css +0 -587
  103. package/src/components/lightbox/ds-mobile-lightbox.service.ts +0 -296
  104. package/src/components/lightbox/ds-mobile-lightbox.ts +0 -529
  105. package/src/components/lightbox/index.ts +0 -22
  106. package/src/components/list-item/ds-mobile-list-item.ts +0 -603
  107. package/src/components/list-item/index.ts +0 -2
  108. package/src/components/list-item-static/ds-mobile-list-item-static.ts +0 -133
  109. package/src/components/list-item-static/index.ts +0 -2
  110. package/src/components/loader-overlay/ds-mobile-loader-overlay.css +0 -49
  111. package/src/components/loader-overlay/ds-mobile-loader-overlay.ts +0 -77
  112. package/src/components/loader-overlay/index.ts +0 -1
  113. package/src/components/logo/ds-logo.ts +0 -95
  114. package/src/components/logo/index.ts +0 -2
  115. package/src/components/message-bubble/ds-mobile-message-bubble.ts +0 -633
  116. package/src/components/message-bubble/index.ts +0 -7
  117. package/src/components/message-composer/ds-mobile-message-composer.ts +0 -1146
  118. package/src/components/message-composer/index.ts +0 -7
  119. package/src/components/modal/ds-mobile-modal.css +0 -163
  120. package/src/components/modal/ds-mobile-modal.service.ts +0 -329
  121. package/src/components/modal/index.ts +0 -8
  122. package/src/components/modal-base/ds-mobile-modal-base.css +0 -378
  123. package/src/components/modal-base/ds-mobile-modal-base.ts +0 -261
  124. package/src/components/modal-base/index.ts +0 -2
  125. package/src/components/new-inquiry-modal/ds-mobile-new-inquiry-modal.css +0 -112
  126. package/src/components/new-inquiry-modal/ds-mobile-new-inquiry-modal.service.ts +0 -93
  127. package/src/components/new-inquiry-modal/ds-mobile-new-inquiry-modal.ts +0 -442
  128. package/src/components/new-inquiry-modal/index.ts +0 -4
  129. package/src/components/offline-banner/ds-mobile-offline-banner.ts +0 -135
  130. package/src/components/offline-banner/index.ts +0 -1
  131. package/src/components/page-details/ds-mobile-page-details.css +0 -83
  132. package/src/components/page-details/ds-mobile-page-details.ts +0 -282
  133. package/src/components/page-details/index.ts +0 -2
  134. package/src/components/page-main/ds-mobile-page-main.css +0 -68
  135. package/src/components/page-main/ds-mobile-page-main.ts +0 -421
  136. package/src/components/page-main/index.ts +0 -2
  137. package/src/components/post-composer/ds-mobile-post-composer.ts +0 -140
  138. package/src/components/post-composer/index.ts +0 -2
  139. package/src/components/post-detail-modal/ds-mobile-post-detail-modal.css +0 -390
  140. package/src/components/post-detail-modal/ds-mobile-post-detail-modal.service.ts +0 -108
  141. package/src/components/post-detail-modal/ds-mobile-post-detail-modal.ts +0 -722
  142. package/src/components/post-detail-modal/index.ts +0 -9
  143. package/src/components/property-banner/ds-mobile-property-banner.ts +0 -95
  144. package/src/components/property-banner/index.ts +0 -2
  145. package/src/components/section/ds-mobile-section.ts +0 -263
  146. package/src/components/section/index.ts +0 -2
  147. package/src/components/shared/directives/index.ts +0 -2
  148. package/src/components/shared/directives/long-press.directive.ts +0 -212
  149. package/src/components/shared/index.ts +0 -3
  150. package/src/components/shared/mobile-modal-base.ts +0 -457
  151. package/src/components/shared/mobile-page-base.ts +0 -204
  152. package/src/components/swiper/ds-mobile-swiper-with-nav.ts +0 -160
  153. package/src/components/swiper/ds-mobile-swiper.ts +0 -327
  154. package/src/components/swiper/index.ts +0 -3
  155. package/src/components/system-message-banner/ds-mobile-system-message-banner.ts +0 -129
  156. package/src/components/system-message-banner/index.ts +0 -2
  157. package/src/components/tab-bar/ds-mobile-tab-bar.css +0 -533
  158. package/src/components/tab-bar/ds-mobile-tab-bar.ts +0 -735
  159. package/src/components/tab-bar/index.ts +0 -2
  160. package/src/components/tabs/ds-mobile-tabs.css +0 -25
  161. package/src/components/tabs/ds-mobile-tabs.ts +0 -89
  162. package/src/components/tabs/index.ts +0 -2
  163. package/src/components/text-input/ds-text-input.ts +0 -287
  164. package/src/components/text-input/index.ts +0 -2
  165. package/src/examples/booking.page.ts +0 -434
  166. package/src/examples/community.page.ts +0 -776
  167. package/src/examples/handbook.page.ts +0 -324
  168. package/src/examples/home.page.ts +0 -347
  169. package/src/examples/index.ts +0 -12
  170. package/src/examples/inquiries.example.ts +0 -273
  171. package/src/examples/inquiry-detail.example.css +0 -189
  172. package/src/examples/inquiry-detail.example.ts +0 -415
  173. package/src/examples/mobile-tabs-example.component.ts +0 -208
  174. package/src/examples/post-create.page.ts +0 -311
  175. package/src/examples/post-detail.page.ts +0 -296
  176. package/src/examples/sign-in.page.ts +0 -291
  177. package/src/examples/whitelabel-demo-modal.component.ts +0 -1094
  178. package/src/examples/whitelabel-demo-modal.service.ts +0 -77
  179. package/src/models/index.ts +0 -7
  180. package/src/models/post.model.ts +0 -41
  181. package/src/pages/community.page.ts +0 -769
  182. package/src/pages/handbook.page.ts +0 -388
  183. package/src/pages/home.page.ts +0 -303
  184. package/src/pages/index.ts +0 -11
  185. package/src/pages/inquiries.example.ts +0 -273
  186. package/src/pages/inquiry-detail.example.css +0 -189
  187. package/src/pages/inquiry-detail.example.ts +0 -415
  188. package/src/pages/mobile-tabs-example.component.ts +0 -179
  189. package/src/pages/post-create.page.ts +0 -311
  190. package/src/pages/post-detail.page.ts +0 -296
  191. package/src/pages/sign-in.page.ts +0 -291
  192. package/src/pages/whitelabel-demo-modal.component.ts +0 -1094
  193. package/src/pages/whitelabel-demo-modal.service.ts +0 -77
  194. package/src/public-api.ts +0 -6
  195. package/src/services/base-modal.service.ts +0 -101
  196. package/src/services/index.ts +0 -11
  197. package/src/services/posts.service.ts +0 -542
  198. package/src/services/tracking-permission.service.ts +0 -88
  199. package/src/services/user.service.ts +0 -60
  200. package/src/services/whitelabel.service.ts +0 -675
  201. package/tsconfig.lib.json +0 -17
  202. package/tsconfig.lib.prod.json +0 -9
  203. package/tsconfig.spec.json +0 -13
  204. /package/{src/assets → assets}/fonts/Brockmann-Bold.otf +0 -0
  205. /package/{src/assets → assets}/fonts/Brockmann-BoldItalic.otf +0 -0
  206. /package/{src/assets → assets}/fonts/Brockmann-Medium.otf +0 -0
  207. /package/{src/assets → assets}/fonts/Brockmann-MediumItalic.otf +0 -0
  208. /package/{src/assets → assets}/fonts/Brockmann-Regular.otf +0 -0
  209. /package/{src/assets → assets}/fonts/Brockmann-RegularItalic.otf +0 -0
  210. /package/{src/assets → assets}/fonts/Brockmann-SemiBold.otf +0 -0
  211. /package/{src/assets → assets}/fonts/Brockmann-SemiBoldItalic.otf +0 -0
  212. /package/{src/assets → assets}/fonts/Brockmann_desktop_license.pdf +0 -0
  213. /package/{src/assets → assets}/fonts/brockmann-medium-webfont.woff2 +0 -0
  214. /package/{src/assets → assets}/fonts/brockmann-mediumitalic-webfont.woff2 +0 -0
  215. /package/{src/assets → assets}/fonts/brockmann-regular-webfont.woff2 +0 -0
  216. /package/{src/assets → assets}/fonts/brockmann-regularitalic-webfont.woff2 +0 -0
  217. /package/{src/assets → assets}/fonts/brockmann-semibold-webfont.woff2 +0 -0
  218. /package/{src/assets → assets}/fonts/brockmann-semibolditalic-webfont.woff2 +0 -0
  219. /package/{src/styles → styles}/ionic.css +0 -0
  220. /package/{src/components/shared → styles}/mobile-common.css +0 -0
  221. /package/{src/components/shared → styles}/mobile-page-base.css +0 -0
@@ -1,722 +0,0 @@
1
- import { Component, signal, computed, CUSTOM_ELEMENTS_SCHEMA, Input, ViewChild, ElementRef, OnInit, AfterViewInit } from '@angular/core';
2
- import { CommonModule } from '@angular/common';
3
- import { FormsModule } from '@angular/forms';
4
- import { Keyboard } from '@capacitor/keyboard';
5
- import { DsIconComponent, DsIconButtonComponent } from '@propbinder/design-system';
6
- import { DsAvatarComponent } from '@propbinder/design-system';
7
- import { PostContentComponent, PostTextComponent, PostMediaComponent, PostActionsComponent, ActionLikeComponent, ActionCommentComponent } from '../interactive-list-item-post';
8
- import { DsMobileCommentComponent } from '../comment/ds-mobile-comment';
9
- import { DsMobileLightboxService, LightboxAuthor } from '../lightbox';
10
- import { DsMobileBottomSheetService, DsMobileCommentActionsBottomSheetComponent, CommentActionResult } from '../bottom-sheet';
11
- import { DsMobileModalBaseComponent } from '../modal-base/ds-mobile-modal-base';
12
- import { DsMobileEmptyStateComponent } from '../empty-state';
13
- import { DsMobileSectionComponent } from '../section';
14
-
15
- /**
16
- * Post data interface for the modal
17
- *
18
- * Represents a post with its content, author info, and comments.
19
- * Use this interface to map your API response data to the component.
20
- *
21
- * @example
22
- * ```typescript
23
- * const postData: PostDetailData = {
24
- * postId: '123',
25
- * authorName: 'John Doe',
26
- * authorRole: 'Tenant',
27
- * timestamp: '2h ago',
28
- * avatarInitials: 'JD',
29
- * content: 'Post content here...',
30
- * likeCount: 42,
31
- * commentCount: 12,
32
- * comments: [...]
33
- * };
34
- * ```
35
- */
36
- export interface PostDetailData {
37
- /** Unique post identifier */
38
- postId: string;
39
- /** Post author name */
40
- authorName: string;
41
- /** Author role (e.g., 'Tenant', 'Manager') */
42
- authorRole: string;
43
- /** Post timestamp (e.g., '2h ago', 'Yesterday') */
44
- timestamp: string;
45
- /** Author avatar initials (1-2 letters) */
46
- avatarInitials?: string;
47
- /** Avatar display type */
48
- avatarType?: 'photo' | 'initials';
49
- /** Author avatar image URL */
50
- avatarSrc?: string;
51
- /** Post text content */
52
- content: string;
53
- /** Optional post image URL */
54
- imageSrc?: string;
55
- /** Image alt text */
56
- imageAlt?: string;
57
- /** Whether the current user has liked this post */
58
- isLiked?: boolean;
59
- /** Number of likes */
60
- likeCount?: number;
61
- /** Number of comments */
62
- commentCount?: number;
63
- /** Array of comments */
64
- comments?: CommentData[];
65
- /** Auto-focus comment input when modal opens */
66
- focusComment?: boolean;
67
- }
68
-
69
- /**
70
- * Comment data interface
71
- *
72
- * Represents a single comment on a post.
73
- *
74
- * @example
75
- * ```typescript
76
- * const comment: CommentData = {
77
- * authorName: 'Jane Smith',
78
- * authorRole: 'Tenant',
79
- * timestamp: '1h ago',
80
- * avatarInitials: 'JS',
81
- * content: 'Great post!',
82
- * isLiked: false,
83
- * likeCount: 5,
84
- * isOwnComment: false
85
- * };
86
- * ```
87
- */
88
- export interface CommentData {
89
- /** Unique comment identifier */
90
- id?: string;
91
- /** Comment author name */
92
- authorName: string;
93
- /** Author role */
94
- authorRole: string;
95
- /** Comment timestamp */
96
- timestamp: string;
97
- /** Author avatar initials */
98
- avatarInitials: string;
99
- /** Comment text content */
100
- content: string;
101
- /** Whether the current user has liked this comment */
102
- isLiked?: boolean;
103
- /** Number of likes on this comment */
104
- likeCount?: number;
105
- /** Whether this comment belongs to the current user */
106
- isOwnComment?: boolean;
107
- }
108
-
109
- /**
110
- * DsMobilePostDetailModalComponent
111
- *
112
- * Modal wrapper for displaying post details with comments.
113
- * Follows the same pattern as the lightbox modal for consistent behavior.
114
- *
115
- * Features:
116
- * - Full post content display
117
- * - Comments section
118
- * - Image lightbox integration
119
- * - Native modal controls (close, swipe down)
120
- * - Safe area support
121
- *
122
- * This component is typically not used directly - use DsMobilePostDetailModalService instead.
123
- *
124
- * @example
125
- * ```typescript
126
- * // Don't instantiate directly - use the service:
127
- * constructor(private postModal: DsMobilePostDetailModalService) {}
128
- *
129
- * openPost() {
130
- * this.postModal.open({
131
- * postId: '123',
132
- * authorName: 'John Doe',
133
- * content: 'Post content...'
134
- * });
135
- * }
136
- * ```
137
- */
138
- @Component({
139
- selector: 'ds-mobile-post-detail-modal',
140
- standalone: true,
141
- imports: [
142
- CommonModule,
143
- FormsModule,
144
- DsIconComponent,
145
- DsIconButtonComponent,
146
- DsAvatarComponent,
147
- PostTextComponent,
148
- PostMediaComponent,
149
- ActionLikeComponent,
150
- ActionCommentComponent,
151
- DsMobileCommentComponent,
152
- DsMobileModalBaseComponent,
153
- DsMobileEmptyStateComponent,
154
- DsMobileSectionComponent
155
- ],
156
- styleUrls: ['../shared/mobile-common.css', './ds-mobile-post-detail-modal.css'],
157
- schemas: [CUSTOM_ELEMENTS_SCHEMA],
158
- template: `
159
- <ds-mobile-modal-base
160
- [loading]="loading"
161
- [error]="error"
162
- [headerTitle]="post().authorName"
163
- [headerMeta]="post().authorRole + ' · ' + post().timestamp"
164
- [hasFixedBottom]="true"
165
- [enableKeyboardHandling]="true"
166
- closeButtonLabel="Luk opslag"
167
- >
168
- <!-- Header Avatar -->
169
- <ds-avatar header-leading [initials]="post().avatarInitials || ''" [type]="post().avatarType || 'initials'" [src]="post().avatarSrc || ''" size="md" />
170
-
171
- <!-- Post Section -->
172
- <ds-mobile-section>
173
- <div class="post-content-only">
174
- <post-text>
175
- <div [innerHTML]="post().content"></div>
176
- </post-text>
177
- @if (post().imageSrc) {
178
- <post-media>
179
- <img [src]="post().imageSrc" [alt]="post().imageAlt || 'Post image'" class="clickable-image" (click)="openImageLightbox()" />
180
- </post-media>
181
- }
182
- </div>
183
-
184
- <!-- Post actions -->
185
- <div class="post-actions">
186
- <action-like
187
- [active]="post().isLiked || false"
188
- [count]="post().likeCount || 0"
189
- (likeClick)="handlePostLikeToggle($event)"
190
- />
191
- <action-comment [count]="post().commentCount || 0" (commentClick)="focusCommentInput()" />
192
- </div>
193
- </ds-mobile-section>
194
-
195
- <!-- Comments Section -->
196
- <ds-mobile-section
197
- [headline]="post().comments && post().comments!.length > 0 ? (post().comments!.length + ' ' + (post().comments!.length === 1 ? 'reply' : 'replies')) : ''">
198
- @if (post().comments && post().comments!.length > 0) {
199
- <div class="comments-list">
200
- @for (comment of post().comments!; track comment.id) {
201
- <ds-mobile-comment
202
- [authorName]="comment.authorName"
203
- [authorRole]="comment.authorRole"
204
- [timestamp]="comment.timestamp"
205
- [avatarInitials]="comment.avatarInitials"
206
- [content]="comment.content"
207
- [isLiked]="comment.isLiked || false"
208
- [likeCount]="comment.likeCount || 0"
209
- [clickable]="true"
210
- [isOwnComment]="comment.isOwnComment || false"
211
- (likeToggled)="handleCommentLikeToggle(comment, $event)"
212
- (replyClick)="handleReply(comment.authorName, comment.content)"
213
- (editClick)="handleEditComment(comment)"
214
- (longPress)="handleCommentLongPress(comment.authorName, comment.content, comment.isOwnComment || false)" />
215
- }
216
- </div>
217
- } @else {
218
- <!-- Empty State -->
219
- <ds-mobile-empty-state
220
- [imageSrc]="'/Assets/empty-state-inquiry.svg'"
221
- [imageAlt]="'Ingen kommentarer endnu'"
222
- [title]="'Ingen svar endnu'"
223
- [description]="'Vær den første til at svare på dette opslag'">
224
- </ds-mobile-empty-state>
225
- }
226
- </ds-mobile-section>
227
-
228
- <!-- Fixed comment composer -->
229
- <div fixed-bottom>
230
- <div class="comment-composer">
231
- <!-- Edit indicator -->
232
- @if (editingComment()) {
233
- <div class="edit-indicator">
234
- <div class="edit-indicator-content">
235
- <ds-icon name="remixEditLine" size="16px" />
236
- <span class="edit-text">Redigerer kommentar</span>
237
- </div>
238
- <button class="cancel-edit" (click)="cancelEdit()">
239
- <ds-icon name="remixCloseLine" size="16px" />
240
- </button>
241
- </div>
242
- } @else if (replyingTo()) {
243
- <!-- Reply indicator -->
244
- <div class="reply-indicator">
245
- <div class="reply-indicator-content">
246
- <ds-icon name="remixReplyLine" size="16px" />
247
- <span class="reply-to-text">
248
- Svarer til <span class="reply-author">{{ replyingTo()!.authorName }}</span>
249
- </span>
250
- </div>
251
- <button class="cancel-reply" (click)="cancelReply()">
252
- <ds-icon name="remixCloseLine" size="16px" />
253
- </button>
254
- </div>
255
- }
256
-
257
- <div class="composer-content">
258
- <ds-avatar [initials]="currentUserInitials()" [type]="'initials'" size="md" />
259
- <div class="composer-input-wrapper">
260
- <textarea
261
- #commentInput
262
- class="composer-input"
263
- [placeholder]="editingComment() ? 'Rediger din kommentar...' : replyingTo() ? 'Tilføj et svar...' : 'Tilføj et svar...'"
264
- [ngModel]="commentText()"
265
- (ngModelChange)="commentText.set($event)"
266
- (input)="handleInput($event)"
267
- (focus)="showKeyboard()"
268
- (click)="showKeyboard()"
269
- rows="1"
270
- ></textarea>
271
- </div>
272
- <ds-icon-button
273
- icon="remixCheckLine"
274
- variant="primary"
275
- size="sm"
276
- (clicked)="submitComment()"
277
- aria-label="Send kommentar"
278
- [class.send-button-fixed]="true"
279
- [class.show]="commentText().trim().length > 0"
280
- >
281
- </ds-icon-button>
282
- </div>
283
- </div>
284
- </div>
285
- </ds-mobile-modal-base>
286
- `,
287
- })
288
- export class DsMobilePostDetailModalComponent implements OnInit, AfterViewInit {
289
- // Post data passed from service
290
- @Input() postData!: PostDetailData;
291
-
292
- // Current user info for comment composer
293
- @Input() currentUserName: string = '';
294
- @Input() currentUserInitialsInput: string = '';
295
-
296
- // State management inputs (passed to modal base)
297
- @Input() loading: boolean = false;
298
- @Input() error: string | undefined;
299
-
300
- // Callback for toggling like on the main post
301
- @Input() onTogglePostLike?: (payload: { postId: string; active: boolean }) => void;
302
-
303
- // Callback for submitting a new comment
304
- @Input() onSubmitComment?: (payload: { postId: string; text: string }) => void;
305
-
306
- // Callback for liking/unliking a comment
307
- @Input() onToggleCommentLike?: (payload: { commentId: string; active: boolean }) => void;
308
-
309
- // Callback for editing a comment
310
- @Input() onEditComment?: (payload: { commentId: string; newText: string }) => void;
311
-
312
- // Callback for deleting a comment
313
- @Input() onDeleteComment?: (payload: { commentId: string }) => void;
314
-
315
- // ViewChild for comment input
316
- @ViewChild('commentInput') commentInput?: ElementRef<HTMLTextAreaElement>;
317
-
318
- // Signal for reactive post data
319
- post = signal<PostDetailData>({
320
- postId: '',
321
- authorName: '',
322
- authorRole: '',
323
- timestamp: '',
324
- content: '',
325
- comments: [],
326
- });
327
-
328
- // Comment composer state
329
- commentText = signal('');
330
- currentUserInitials = signal('');
331
- replyingTo = signal<{ authorName: string; content: string } | null>(null);
332
- editingComment = signal<{ id?: string; authorName: string; originalContent: string; timestamp: string } | null>(null);
333
-
334
- constructor(private lightbox: DsMobileLightboxService, private bottomSheet: DsMobileBottomSheetService) {}
335
-
336
- ngOnInit(): void {
337
- // Initialize post data from input
338
- if (this.postData) {
339
- this.post.set(this.postData);
340
- }
341
-
342
- // Set current user initials
343
- if (this.currentUserInitialsInput) {
344
- this.currentUserInitials.set(this.currentUserInitialsInput);
345
- } else if (this.currentUserName) {
346
- // fallback: derive from name
347
- const initials = this.currentUserName
348
- .trim()
349
- .split(/\s+/)
350
- .map((p) => p[0])
351
- .join('')
352
- .substring(0, 2)
353
- .toUpperCase();
354
- this.currentUserInitials.set(initials);
355
- }
356
- }
357
-
358
- ngAfterViewInit(): void {
359
- // Auto-focus comment input if requested
360
- if (this.postData?.focusComment) {
361
- // Small delay to ensure modal animation is complete
362
- setTimeout(() => {
363
- this.commentInput?.nativeElement.focus();
364
- // Show keyboard on mobile
365
- this.showKeyboard();
366
- }, 300);
367
- }
368
- }
369
-
370
- /**
371
- * Show the keyboard when user interacts with input
372
- */
373
- showKeyboard(): void {
374
- Keyboard.show().catch((e) => {
375
- // console.log('Keyboard.show() not available')
376
- });
377
- }
378
-
379
- /**
380
- * Focus the comment input when comment icon is tapped
381
- */
382
- focusCommentInput(): void {
383
- // Focus the input
384
- this.commentInput?.nativeElement.focus();
385
- // Show keyboard on mobile
386
- this.showKeyboard();
387
- }
388
-
389
- /**
390
- * Handle input changes for auto-resize
391
- */
392
- handleInput(event: Event): void {
393
- const textarea = event.target as HTMLTextAreaElement;
394
-
395
- // Auto-resize textarea
396
- textarea.style.height = 'auto';
397
- textarea.style.height = textarea.scrollHeight + 'px';
398
- }
399
-
400
- /**
401
- * Handle reply to a comment
402
- */
403
- handleReply(authorName: string, content: string): void {
404
- this.replyingTo.set({ authorName, content });
405
- // Focus the input and show keyboard
406
- setTimeout(() => {
407
- this.commentInput?.nativeElement.focus();
408
- this.showKeyboard();
409
- }, 100);
410
- }
411
-
412
- /**
413
- * Cancel reply
414
- */
415
- cancelReply(): void {
416
- this.replyingTo.set(null);
417
- }
418
-
419
- /**
420
- * Cancel edit
421
- */
422
- cancelEdit(): void {
423
- this.editingComment.set(null);
424
- this.commentText.set('');
425
- }
426
-
427
- /**
428
- * Handle edit comment
429
- */
430
- handleEditComment(comment: CommentData): void {
431
- // Clear reply state if active
432
- this.replyingTo.set(null);
433
-
434
- // Set edit state
435
- this.editingComment.set({
436
- id: comment.id,
437
- authorName: comment.authorName,
438
- originalContent: comment.content,
439
- timestamp: comment.timestamp,
440
- });
441
-
442
- // Populate the input with existing content
443
- this.commentText.set(comment.content);
444
-
445
- // Focus the input, show keyboard, and auto-resize
446
- setTimeout(() => {
447
- if (this.commentInput?.nativeElement) {
448
- const textarea = this.commentInput.nativeElement;
449
- textarea.focus();
450
-
451
- // Auto-resize textarea to fit content
452
- textarea.style.height = 'auto';
453
- textarea.style.height = textarea.scrollHeight + 'px';
454
-
455
- this.showKeyboard();
456
- }
457
- }, 100);
458
- }
459
-
460
- /**
461
- * Handle post like/unlike toggle
462
- */
463
- handlePostLikeToggle(ev: { active: boolean; count: number }): void {
464
- const currentPost = this.post();
465
-
466
- // Update local state immediately for responsiveness
467
- this.post.set({
468
- ...currentPost,
469
- isLiked: ev.active,
470
- likeCount: ev.count
471
- });
472
-
473
- // Call the callback if provided
474
- if (this.onTogglePostLike) {
475
- this.onTogglePostLike({
476
- postId: currentPost.postId,
477
- active: ev.active
478
- });
479
- }
480
- }
481
-
482
- /**
483
- * Handle comment like/unlike toggle
484
- * @param comment The comment being liked/unliked
485
- * @param ev Event data with active state and new count
486
- */
487
- handleCommentLikeToggle(comment: CommentData, ev: { active: boolean; count: number }): void {
488
- // Update local state immediately for responsiveness
489
- const currentPost = this.post();
490
- const updatedComments = currentPost.comments?.map((c) => (c.id === comment.id ? { ...c, isLiked: ev.active, likeCount: ev.count } : c));
491
-
492
- this.post.set({
493
- ...currentPost,
494
- comments: updatedComments,
495
- });
496
-
497
- // Call the callback if provided
498
- if (this.onToggleCommentLike) {
499
- this.onToggleCommentLike({
500
- commentId: comment.id!,
501
- active: ev.active,
502
- });
503
- }
504
- }
505
-
506
- // Note: close() method is inherited from MobileModalBase
507
-
508
- /**
509
- * Submit a comment
510
- */
511
- submitComment(): void {
512
- const text = this.commentText().trim();
513
- if (!text) return;
514
-
515
- const currentPost = this.post();
516
- const postId = currentPost.postId;
517
-
518
- // Create new comment
519
- const finalText = this.replyingTo() ? `@${this.replyingTo()!.authorName} ${text}` : text;
520
-
521
- // Check if we're editing an existing comment
522
- if (this.editingComment()) {
523
- // console.log('[PostDetailModal] Updating comment:', text);
524
-
525
- const editing = this.editingComment()!;
526
-
527
- const updatedComments = currentPost.comments?.map((comment) => {
528
- if (comment.id && editing.id && comment.id === editing.id) {
529
- return {
530
- ...comment,
531
- content: text,
532
- timestamp: 'Just now (edited)',
533
- };
534
- }
535
- return comment;
536
- });
537
-
538
- this.post.set({
539
- ...currentPost,
540
- comments: updatedComments,
541
- });
542
-
543
- // Call the edit callback
544
- if (this.onEditComment && editing.id) {
545
- this.onEditComment({
546
- commentId: editing.id,
547
- newText: finalText, // or finalText if you want to include @mention
548
- });
549
- }
550
-
551
- this.editingComment.set(null);
552
- } else {
553
- // console.log('[PostDetailModal] Submitting comment:', finalText);
554
- // console.log('[PostDetailModal] onSubmitComment =', this.onSubmitComment);
555
-
556
- const newComment: CommentData = {
557
- authorName: this.currentUserName || 'Dig',
558
- authorRole: 'Dig',
559
- timestamp: 'Just now',
560
- avatarInitials: this.currentUserInitials(),
561
- content: finalText,
562
- isLiked: false,
563
- likeCount: 0,
564
- isOwnComment: true,
565
- };
566
-
567
- // Add comment to the list
568
- const updatedComments = [...(currentPost.comments || []), newComment];
569
-
570
- this.post.set({
571
- ...currentPost,
572
- comments: updatedComments,
573
- commentCount: updatedComments.length,
574
- });
575
-
576
- // Clear reply state
577
- this.replyingTo.set(null);
578
- }
579
-
580
- // Clear the input
581
- this.commentText.set('');
582
-
583
- if (this.commentInput?.nativeElement) {
584
- // Reset textarea height to initial state
585
- this.commentInput.nativeElement.style.height = 'auto';
586
- // Blur the input to hide the keyboard
587
- this.commentInput?.nativeElement.blur();
588
- }
589
-
590
- // Hide keyboard explicitly
591
- Keyboard.hide().catch(() => {});
592
-
593
- // In a real app, you would also send this to your backend
594
- // this.commentService.addComment(currentPost.postId, text);
595
- if (this.onSubmitComment) {
596
- this.onSubmitComment({ postId, text: finalText });
597
- }
598
- }
599
-
600
- /**
601
- * Open image in lightbox
602
- */
603
- openImageLightbox(): void {
604
- const postData = this.post();
605
-
606
- if (!postData.imageSrc) return;
607
-
608
- const authorMeta: LightboxAuthor = {
609
- name: postData.authorName,
610
- role: postData.authorRole,
611
- avatarInitials: postData.avatarInitials || '',
612
- avatarType: postData.avatarType || 'initials',
613
- avatarSrc: postData.avatarSrc || '',
614
- timestamp: postData.timestamp,
615
- };
616
-
617
- this.lightbox.open({
618
- images: [
619
- {
620
- type: 'image',
621
- src: postData.imageSrc,
622
- alt: postData.imageAlt || 'Post image',
623
- title: postData.imageAlt || '',
624
- description: postData.content,
625
- isLiked: postData.isLiked || false,
626
- likeCount: postData.likeCount || 0,
627
- commentCount: postData.commentCount || 0,
628
- },
629
- ],
630
- author: authorMeta,
631
- enableZoom: true,
632
- showControls: false,
633
- showInfo: true,
634
- });
635
- }
636
-
637
- /**
638
- * Handle long press on a comment to show action sheet
639
- */
640
- async handleCommentLongPress(authorName: string, content: string, isOwnComment: boolean): Promise<void> {
641
- const sheet = await this.bottomSheet.create({
642
- component: DsMobileCommentActionsBottomSheetComponent,
643
- componentProps: {
644
- isOwnContent: isOwnComment,
645
- },
646
- breakpoints: [0, 1],
647
- initialBreakpoint: 1,
648
- handle: true,
649
- backdropDismiss: true,
650
- cssClass: 'auto-height',
651
- });
652
-
653
- const result = await sheet.onWillDismiss();
654
-
655
- if (result.role === 'select' && result.data) {
656
- const action = (result.data as CommentActionResult).action;
657
- const currentPost = this.post();
658
-
659
- switch (action) {
660
- case 'like':
661
- // console.log('Like comment by', authorName);
662
- let toggledCommentId: string | null = null;
663
- let newActive = false;
664
- // Update the comment like state locally
665
- const updatedComments = currentPost.comments?.map((comment) => {
666
- if (comment.authorName === authorName && comment.content === content) {
667
- newActive = !comment.isLiked;
668
- toggledCommentId = comment.id!;
669
-
670
- return {
671
- ...comment,
672
- isLiked: newActive,
673
- likeCount: newActive ? (comment.likeCount || 0) + 1 : Math.max(0, (comment.likeCount || 0) - 1),
674
- };
675
- }
676
- return comment;
677
- });
678
-
679
- this.post.set({ ...currentPost, comments: updatedComments });
680
-
681
- // Call the like callback
682
- if (toggledCommentId && this.onToggleCommentLike) {
683
- this.onToggleCommentLike({
684
- commentId: toggledCommentId,
685
- active: newActive,
686
- });
687
- }
688
- break;
689
- case 'reply':
690
- // console.log('Reply to comment by', authorName);
691
- this.handleReply(authorName, content);
692
- break;
693
- case 'edit':
694
- // console.log('Edit comment by', authorName);
695
- // Find the full comment data to get timestamp
696
- const commentToEdit = currentPost.comments?.find((comment) => comment.authorName === authorName && comment.content === content);
697
- if (commentToEdit) {
698
- this.handleEditComment(commentToEdit);
699
- }
700
- break;
701
- case 'delete':
702
- // console.log('Delete comment by', authorName);
703
- // Show confirmation before deleting
704
- if (confirm('Are you sure you want to delete this comment?')) {
705
- const commentToDelete = currentPost.comments?.find((comment) => comment.authorName === authorName && comment.content === content);
706
- const updatedCommentsAfterDelete = currentPost.comments?.filter((comment) => !(comment.authorName === authorName && comment.content === content));
707
- this.post.set({
708
- ...currentPost,
709
- comments: updatedCommentsAfterDelete,
710
- commentCount: updatedCommentsAfterDelete?.length || 0,
711
- });
712
-
713
- // Call the delete callback
714
- if (commentToDelete?.id && this.onDeleteComment) {
715
- this.onDeleteComment({ commentId: commentToDelete.id });
716
- }
717
- }
718
- break;
719
- }
720
- }
721
- }
722
- }