@propbinder/mobile-design 0.2.50 → 0.2.52

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,776 +0,0 @@
1
- import { Component, computed, ViewChild } from '@angular/core';
2
- import { Router, ActivatedRoute } from '@angular/router';
3
- import { IonInfiniteScroll, IonInfiniteScrollContent } from '@ionic/angular/standalone';
4
- import { DsIconButtonComponent } from '@propbinder/design-system';
5
- import { DsMobilePageMainComponent } from '../components/page-main';
6
- import { DsMobileSectionComponent } from '../components/section';
7
- import { DsMobileSwiperComponent } from '../components/swiper/ds-mobile-swiper';
8
- import { DsMobileInteractiveListItemPostComponent } from '../components/interactive-list-item-post';
9
- import { DsMobileCardInlineFileComponent } from '../components/card-inline-file';
10
- import { DsMobileOfflineBannerComponent } from '../components/offline-banner';
11
- import {
12
- PostContentComponent,
13
- PostTextComponent,
14
- PostMediaComponent,
15
- PostAttachmentsComponent,
16
- PostActionsComponent,
17
- ActionLikeComponent,
18
- ActionCommentComponent
19
- } from '../components/interactive-list-item-post';
20
- import { DsMobilePostComposerComponent } from '../components/post-composer';
21
- import { DsMobileBottomSheetService } from '../components/bottom-sheet/ds-mobile-bottom-sheet.service';
22
- import { DsMobilePostCreateBottomSheetComponent } from '../components/bottom-sheet/ds-mobile-post-create-bottom-sheet';
23
- import { DsMobilePostActionsBottomSheetComponent, PostActionResult } from '../components/bottom-sheet';
24
- import { DsMobileLightboxService, LightboxAuthor } from '../components/lightbox';
25
- import { DsMobilePostDetailModalService } from '../components/post-detail-modal';
26
- import { DsMobileInlinePhotoComponent } from '../components/inline-photo';
27
- import { UserService } from '../services/user.service';
28
- import { PostsService } from '../services/posts.service';
29
- import { Post } from '../models/post.model';
30
-
31
- @Component({
32
- selector: 'app-mobile-community-page',
33
- standalone: true,
34
- imports: [
35
- DsMobilePageMainComponent,
36
- DsMobileSectionComponent,
37
- DsMobileInteractiveListItemPostComponent,
38
- DsMobilePostComposerComponent,
39
- DsMobileSwiperComponent,
40
- PostContentComponent,
41
- PostTextComponent,
42
- PostMediaComponent,
43
- PostAttachmentsComponent,
44
- PostActionsComponent,
45
- ActionLikeComponent,
46
- ActionCommentComponent,
47
- DsMobileCardInlineFileComponent,
48
- DsIconButtonComponent,
49
- DsMobileInlinePhotoComponent,
50
- DsMobileOfflineBannerComponent,
51
- IonInfiniteScroll,
52
- IonInfiniteScrollContent
53
- ],
54
- styles: [`
55
- /* Pinned posts swiper wrapper */
56
- .pinned-posts-swiper-wrapper {
57
- padding: 0;
58
- position: relative;
59
- }
60
-
61
- /* Navigation buttons */
62
- .swiper-nav-buttons {
63
- display: contents;
64
- }
65
-
66
- .swiper-nav-button {
67
- position: absolute;
68
- top: 50%;
69
- transform: translateY(-50%);
70
- z-index: 10;
71
- }
72
-
73
- .swiper-nav-button:first-child {
74
- left: -48px;
75
- }
76
-
77
- .swiper-nav-button:last-child {
78
- right: -48px;
79
- }
80
-
81
- /* Force buttons to be perfectly round */
82
- ::ng-deep .swiper-nav-button button {
83
- border-radius: 50% !important;
84
- width: 48px !important;
85
- height: 48px !important;
86
- padding: 0 !important;
87
- }
88
-
89
- /* Hide on mobile */
90
- @media (max-width: 767px) {
91
- .swiper-nav-buttons {
92
- display: none;
93
- }
94
- }
95
-
96
- /* Swiper slide styling for pinned posts */
97
- ::ng-deep .pinned-posts-swiper .swiper-slide {
98
- width: 100%;
99
- max-width: 600px;
100
- height: auto;
101
- }
102
-
103
- /* Desktop: Remove max-width constraint */
104
- @media (min-width: 768px) {
105
- ::ng-deep .pinned-posts-swiper .swiper-slide {
106
- max-width: 100%;
107
- }
108
- }
109
-
110
- /* Post item inside swiper slide */
111
- .swiper-post-item {
112
- width: 100%;
113
- height: auto;
114
- }
115
-
116
- /* Ensure post content doesn't get cropped */
117
- ::ng-deep .pinned-posts-swiper .swiper-slide ds-mobile-interactive-list-item-post {
118
- height: auto;
119
- }
120
-
121
- ::ng-deep .pinned-posts-swiper .swiper-wrapper {
122
- height: auto;
123
- align-items: flex-start;
124
- }
125
-
126
- .post-list-wrapper {
127
- display: flex;
128
- flex-direction: column;
129
- }
130
-
131
- .clickable-image {
132
- cursor: pointer;
133
- transition: transform 0.2s ease, opacity 0.2s ease;
134
- border-radius: 8px;
135
- display: block;
136
- width: 100%;
137
- aspect-ratio: 16/9;
138
- object-fit: cover;
139
- }
140
-
141
- .clickable-image:active {
142
- transform: scale(0.98);
143
- opacity: 0.9;
144
- }
145
-
146
- /* Empty State */
147
- .community-empty-state {
148
- display: flex;
149
- flex-direction: column;
150
- align-items: center;
151
- justify-content: center;
152
- padding: 60px 20px;
153
- text-align: center;
154
- }
155
-
156
- .empty-state-image {
157
- width: 96px;
158
- height: 96px;
159
- margin-bottom: 24px;
160
- }
161
-
162
- .empty-state-title {
163
- font-family: 'Brockmann', sans-serif;
164
- font-size: var(--font-size-base);
165
- font-weight: 600;
166
- color: var(--color-text-primary);
167
- margin: 16px 0 8px 0;
168
- }
169
-
170
- .empty-state-description {
171
- font-family: 'Brockmann', sans-serif;
172
- font-size: var(--font-size-sm);
173
- color: var(--color-text-secondary);
174
- margin: 0;
175
- }
176
-
177
- /* Infinite Scroll Spinner Styling */
178
- ion-infinite-scroll {
179
- --color: var(--color-primary-surface);
180
- }
181
-
182
- ion-infinite-scroll-content {
183
- --color: var(--color-primary-surface);
184
- }
185
-
186
- /* Target the actual spinner element */
187
- ion-infinite-scroll-content::part(spinner) {
188
- color: var(--color-primary-surface);
189
- }
190
- `],
191
- template: `
192
- <ds-mobile-page-main
193
- #pageComponent
194
- title="Fællesskab"
195
- [avatarInitials]="userService.avatarInitials()"
196
- [avatarType]="userService.avatarType()"
197
- (refresh)="handleRefresh($event)">
198
-
199
- <!-- Offline indicator -->
200
- @if (pageComponent.isOffline()) {
201
- <ds-mobile-offline-banner
202
- offline-indicator
203
- title="Ingen internetforbindelse"
204
- message="Nogle funktioner kan være utilgængelige">
205
- </ds-mobile-offline-banner>
206
- }
207
-
208
- <!-- Post Composer in header-expandable -->
209
- <ds-mobile-post-composer
210
- header-content
211
- [avatarInitials]="userService.avatarInitials()"
212
- [avatarType]="userService.avatarType()"
213
- [avatarSrc]="userService.avatarSrc()"
214
- (composerClick)="openPostCreator()"
215
- />
216
-
217
- <!-- Pinned Posts Section -->
218
- <ds-mobile-section
219
- headline="Fastgjorte opslag"
220
- icon="remixPushpinFill">
221
- <div class="pinned-posts-swiper-wrapper">
222
- <ds-mobile-swiper
223
- #pinnedSwiper
224
- class="pinned-posts-swiper"
225
- [slideWidth]="'100%'"
226
- [gap]="32"
227
- [pagination]="true"
228
- [autoHeight]="true"
229
- [progressiveOpacity]="true"
230
- [progressiveScale]="true">
231
- @for (post of pinnedPosts(); track post.id) {
232
- <div class="swiper-slide">
233
- <ds-mobile-interactive-list-item-post
234
- class="swiper-post-item"
235
- [authorName]="post.authorName"
236
- [authorRole]="post.authorRole"
237
- [timestamp]="post.timestamp"
238
- [avatarInitials]="post.avatarInitials || ''"
239
- [avatarType]="post.avatarType"
240
- [avatarSrc]="post.avatarSrc || ''"
241
- [showBadge]="true"
242
- [clickable]="true"
243
- [moreActions]="true"
244
- (postClick)="openPost(post.id)"
245
- (commentClick)="openPost(post.id, true)"
246
- (longPress)="handlePostLongPress(post.id, false)">
247
-
248
- <post-content>
249
- <post-text>{{ post.content }}</post-text>
250
-
251
- @if (post.id === 'post-4') {
252
- <post-attachments>
253
- <ds-mobile-card-inline-file
254
- [fileName]="'Husregler.pdf'"
255
- [fileSize]="'245 KB'"
256
- [variant]="'pdf'"
257
- [layout]="'compact'"
258
- (fileClick)="openHouseRulesPdf()">
259
- </ds-mobile-card-inline-file>
260
- </post-attachments>
261
- }
262
- </post-content>
263
-
264
- <post-actions>
265
- <action-like [count]="post.likeCount" [active]="post.isLiked" />
266
- <action-comment [count]="post.commentCount" (commentClick)="openPost(post.id, true)" />
267
- </post-actions>
268
- </ds-mobile-interactive-list-item-post>
269
- </div>
270
- }
271
- </ds-mobile-swiper>
272
-
273
- <!-- Navigation Buttons -->
274
- <div class="swiper-nav-buttons">
275
- <ds-icon-button
276
- class="swiper-nav-button"
277
- icon="remixArrowLeftSLine"
278
- variant="ghost"
279
- size="sm"
280
- [disabled]="isFirstSlide()"
281
- (clicked)="slidePrev()"
282
- aria-label="Previous post"
283
- />
284
- <ds-icon-button
285
- class="swiper-nav-button"
286
- icon="remixArrowRightSLine"
287
- variant="ghost"
288
- size="sm"
289
- [disabled]="isLastSlide()"
290
- (clicked)="slideNext()"
291
- aria-label="Next post"
292
- />
293
- </div>
294
- </div>
295
- </ds-mobile-section>
296
-
297
- <!-- All Posts Section -->
298
- <ds-mobile-section
299
- headline="Alle opslag">
300
- @if (hasAnyPosts()) {
301
- <div class="post-list-wrapper">
302
- <!-- All Posts Loop -->
303
- @for (post of allPosts(); track post.id) {
304
- @if (post.hasInlinePhotos && post.id === 'post-2') {
305
- <!-- Post 2: With multiple images (grid layout) -->
306
- <ds-mobile-interactive-list-item-post
307
- [authorName]="post.authorName"
308
- [authorRole]="post.authorRole"
309
- [timestamp]="post.timestamp"
310
- [avatarInitials]="post.avatarInitials || ''"
311
- [avatarType]="post.avatarType"
312
- [clickable]="true"
313
- [moreActions]="true"
314
- (postClick)="openPost(post.id)"
315
- (commentClick)="openPost(post.id, true)"
316
- (longPress)="handlePostLongPress(post.id, post.authorRole === 'Dig')">
317
-
318
- <post-content>
319
- <post-text>{{ post.content }}</post-text>
320
- <ds-mobile-inline-photo
321
- [images]="[
322
- '/Assets/Dummy-photos/balcony-view.jpg',
323
- '/Assets/Dummy-photos/staircase.jpg',
324
- '/Assets/Dummy-photos/park.jpg',
325
- '/Assets/Dummy-photos/yard.jpg'
326
- ]"
327
- [author]="{
328
- name: 'Sophie Andersen',
329
- role: 'Lejer',
330
- avatarInitials: 'SA',
331
- avatarType: 'initials',
332
- timestamp: '4t siden'
333
- }"
334
- />
335
- </post-content>
336
-
337
- <post-actions>
338
- <action-like [active]="post.isLiked" [count]="post.likeCount" />
339
- <action-comment [count]="post.commentCount" (commentClick)="openPost(post.id, true)" />
340
- </post-actions>
341
- </ds-mobile-interactive-list-item-post>
342
- } @else if (post.hasInlinePhotos && post.id === 'post-3.5') {
343
- <!-- Post 3.5: Property Manager showcase with 6+ photos -->
344
- <ds-mobile-interactive-list-item-post
345
- [authorName]="post.authorName"
346
- [authorRole]="post.authorRole"
347
- [timestamp]="post.timestamp"
348
- [avatarInitials]="post.avatarInitials || ''"
349
- [avatarType]="post.avatarType"
350
- [showBadge]="post.showBadge || false"
351
- [clickable]="true"
352
- [moreActions]="true"
353
- (postClick)="openPost(post.id)"
354
- (commentClick)="openPost(post.id, true)"
355
- (longPress)="handlePostLongPress(post.id, false)">
356
-
357
- <post-content>
358
- <post-text>{{ post.content }}</post-text>
359
- <ds-mobile-inline-photo
360
- [images]="[
361
- '/Assets/Dummy-photos/mailboxes.jpg',
362
- '/Assets/Dummy-photos/staircase.jpg',
363
- '/Assets/Dummy-photos/yard.jpg',
364
- '/Assets/Dummy-photos/park.jpg',
365
- '/Assets/Dummy-photos/balcony-view.jpg',
366
- '/Assets/Dummy-photos/handyman.jpg'
367
- ]"
368
- [author]="{
369
- name: 'Karen Nielsen',
370
- role: 'Ejendomsadministrator',
371
- avatarInitials: 'KN',
372
- avatarType: 'initials',
373
- timestamp: '2d siden'
374
- }"
375
- [maxVisible]="5"
376
- />
377
- </post-content>
378
-
379
- <post-actions>
380
- <action-like [count]="post.likeCount" />
381
- <action-comment [count]="post.commentCount" (commentClick)="openPost(post.id, true)" />
382
- </post-actions>
383
- </ds-mobile-interactive-list-item-post>
384
- } @else {
385
- <!-- Regular Post -->
386
- <ds-mobile-interactive-list-item-post
387
- [authorName]="post.authorName"
388
- [authorRole]="post.authorRole"
389
- [timestamp]="post.timestamp"
390
- [avatarType]="post.avatarType"
391
- [avatarSrc]="post.avatarSrc || ''"
392
- [avatarInitials]="post.avatarInitials || ''"
393
- [clickable]="true"
394
- [moreActions]="true"
395
- (postClick)="openPost(post.id)"
396
- (commentClick)="openPost(post.id, true)"
397
- (longPress)="handlePostLongPress(post.id, post.authorRole === 'Dig')">
398
-
399
- <post-content>
400
- @if (post.content) {
401
- <post-text>{{ post.content }}</post-text>
402
- }
403
- @if (post.imageSrc) {
404
- <post-media>
405
- <img
406
- [src]="post.imageSrc"
407
- [alt]="post.imageAlt || 'Posted image'"
408
- class="clickable-image"
409
- (click)="openImageLightbox(post.imageSrc, post.imageAlt || 'Posted image', post.content, $event)"
410
- />
411
- </post-media>
412
- }
413
- </post-content>
414
-
415
- <post-actions>
416
- <action-like [count]="post.likeCount" [active]="post.isLiked" />
417
- <action-comment [count]="post.commentCount" (commentClick)="openPost(post.id, true)" />
418
- </post-actions>
419
- </ds-mobile-interactive-list-item-post>
420
- }
421
- }
422
- </div>
423
- } @else {
424
- <!-- Empty State -->
425
- <div class="community-empty-state">
426
- <img
427
- src="/Assets/Empty%20state-chat.png"
428
- alt="Ingen opslag endnu"
429
- class="empty-state-image"
430
- />
431
- <h3 class="empty-state-title">Ingen opslag endnu</h3>
432
- <p class="empty-state-description">Vær den første til at dele noget med dit fællesskab</p>
433
- </div>
434
- }
435
-
436
- <!-- Infinite Scroll -->
437
- @if (hasAnyPosts()) {
438
- <ion-infinite-scroll
439
- threshold="100px"
440
- [disabled]="!hasMorePosts() || pageComponent.isOffline()"
441
- (ionInfinite)="onInfiniteScroll($event)">
442
- <ion-infinite-scroll-content
443
- loadingSpinner="crescent">
444
- </ion-infinite-scroll-content>
445
- </ion-infinite-scroll>
446
- }
447
- </ds-mobile-section>
448
- </ds-mobile-page-main>
449
- `
450
- })
451
- export class MobileCommunityPageComponent {
452
- @ViewChild('pageComponent') pageComponent!: DsMobilePageMainComponent;
453
- @ViewChild('pinnedSwiper') pinnedSwiper?: DsMobileSwiperComponent;
454
-
455
- // Get posts from service (using computed for safe initialization)
456
- allPosts = computed(() => this.postsService.posts());
457
-
458
- // Get pinned posts - filter by isPinned flag
459
- // In a real app, these would have a 'pinned' flag in the database
460
- pinnedPosts = computed(() => {
461
- // Get all posts that are explicitly marked as pinned
462
- const allPosts = this.postsService.posts();
463
- return allPosts.filter(post => post.isPinned === true);
464
- });
465
-
466
- // Computed to check if there are any posts to display
467
- hasAnyPosts = computed(() => {
468
- return this.allPosts().length > 0;
469
- });
470
-
471
- // Computed to check if there are more posts to load
472
- hasMorePosts = computed(() => {
473
- return this.postsService.hasMorePosts();
474
- });
475
-
476
- constructor(
477
- private router: Router,
478
- private route: ActivatedRoute,
479
- private bottomSheet: DsMobileBottomSheetService,
480
- private lightbox: DsMobileLightboxService,
481
- private postModal: DsMobilePostDetailModalService,
482
- public userService: UserService,
483
- private postsService: PostsService
484
- ) {}
485
-
486
- /**
487
- * Handle infinite scroll event
488
- * Loads more posts when user scrolls to bottom
489
- */
490
- async onInfiniteScroll(event: any): Promise<void> {
491
- console.log('[Community] Infinite scroll triggered');
492
-
493
- const hasMore = await this.postsService.loadMorePosts();
494
-
495
- if (hasMore) {
496
- console.log('[Community] Loaded more posts');
497
- } else {
498
- console.log('[Community] No more posts to load');
499
- }
500
-
501
- // Complete the infinite scroll
502
- event.target.complete();
503
- }
504
-
505
- handleRefresh(event: any): void {
506
- console.log('Pull-to-refresh triggered');
507
-
508
- // Check if offline and complete immediately
509
- if (this.pageComponent?.isOffline()) {
510
- console.log('Cannot refresh while offline');
511
- event.target.complete();
512
- return;
513
- }
514
-
515
- // Reset infinite scroll state
516
- this.postsService.resetPagination();
517
-
518
- setTimeout(() => {
519
- console.log('Refresh complete');
520
- event.target.complete();
521
- }, 1000);
522
- }
523
-
524
- /**
525
- * Open post detail modal
526
- * Gets post data from service and opens modal
527
- */
528
- async openPost(postId: string, focusComment: boolean = false): Promise<void> {
529
- console.log('[Community] ===== openPost called =====', postId, 'Focus comment:', focusComment);
530
-
531
- const post = this.postsService.getPostById(postId);
532
-
533
- if (post) {
534
- // Convert Post model to modal format (add postId and focusComment)
535
- // Filter out 'icon' avatarType if present, as modal only supports 'photo' | 'initials'
536
- const postData = {
537
- ...post,
538
- postId: post.id,
539
- avatarType: post.avatarType === 'icon' ? undefined : post.avatarType,
540
- focusComment
541
- };
542
-
543
- await this.postModal.open(postData, {
544
- currentUserName: 'Lars Mikkelsen', // Current user name
545
- currentUserInitials: this.userService.avatarInitials()
546
- });
547
- }
548
- }
549
-
550
- async openPostCreator(): Promise<void> {
551
- // Open the post creator as a bottom sheet modal
552
- // Using 95% initial height to maximize keyboard auto-open chances
553
- const sheet = await this.bottomSheet.create({
554
- component: DsMobilePostCreateBottomSheetComponent,
555
- componentProps: {
556
- // This helps the component know it should auto-focus
557
- autoFocus: true
558
- },
559
- breakpoints: [0, 0.95, 1],
560
- initialBreakpoint: 0.95,
561
- handle: true
562
- });
563
-
564
- // Handle the result when the sheet is dismissed
565
- const result = await sheet.onWillDismiss();
566
- if (result.role === 'post' && result.data) {
567
- console.log('New post created:', result.data);
568
-
569
- // Create a new post object
570
- const newPost: Post = {
571
- id: `user-post-${Date.now()}`, // Generate unique ID
572
- authorName: 'Lars Mikkelsen', // Current user name
573
- authorRole: 'Dig',
574
- timestamp: 'Lige nu',
575
- avatarType: this.userService.avatarType() as 'photo' | 'initials' | 'icon',
576
- avatarSrc: this.userService.avatarSrc(),
577
- avatarInitials: this.userService.avatarInitials(),
578
- content: result.data.content,
579
- imageSrc: result.data.images && result.data.images.length > 0 ? result.data.images[0] : undefined,
580
- imageAlt: result.data.images && result.data.images.length > 0 ? 'Slået billede op' : undefined,
581
- isLiked: false,
582
- likeCount: 0,
583
- commentCount: 0,
584
- comments: []
585
- };
586
-
587
- // Add to the beginning of the posts array via service
588
- this.postsService.addPost(newPost);
589
- }
590
- }
591
-
592
- /**
593
- * Open an image in the lightbox viewer
594
- * Prevents the post click event from firing
595
- */
596
- async openImageLightbox(imageSrc: string, title: string, description: string, event: Event): Promise<void> {
597
- console.log('[Community] Opening lightbox for image:', imageSrc);
598
-
599
- // Prevent the post card click event from firing
600
- event.stopPropagation();
601
-
602
- const authorMeta: LightboxAuthor = {
603
- name: 'Sophie Andersen',
604
- role: 'Lejer',
605
- avatarInitials: 'SA',
606
- timestamp: '4t siden'
607
- };
608
-
609
- // Open the lightbox with the image
610
- await this.lightbox.open({
611
- images: [
612
- {
613
- type: 'image',
614
- src: imageSrc,
615
- alt: title,
616
- title: title,
617
- description: description,
618
- isLiked: true,
619
- likeCount: 156,
620
- commentCount: 34
621
- }
622
- ],
623
- author: authorMeta,
624
- enableZoom: true,
625
- showControls: false, // Single image, no need for controls
626
- showActions: true, // Show like & comment actions
627
- showInfo: true
628
- });
629
- }
630
-
631
- async openHouseRulesPdf(): Promise<void> {
632
- console.log('[Community] Opening House Rules PDF');
633
-
634
- // Author metadata
635
- const authorMeta: LightboxAuthor = {
636
- name: 'Karen Nielsen',
637
- role: 'Ejendomsadministrator',
638
- avatarInitials: 'KN',
639
- timestamp: '2d siden'
640
- };
641
-
642
- // Open the PDF lightbox
643
- // Use absolute path for production deployment (Vercel, etc.)
644
- await this.lightbox.openPdf({
645
- pdf: {
646
- type: 'pdf',
647
- src: '/Assets/House_Rules.pdf', // Capital A to match public/Assets folder structure
648
- title: 'House Rules',
649
- description: 'Building regulations and community guidelines',
650
- fileSize: 250880, // 245 KB in bytes
651
- pageCount: 8
652
- },
653
- author: authorMeta
654
- });
655
- }
656
-
657
- /**
658
- * Handle long press on a post to show action sheet
659
- */
660
- async handlePostLongPress(postId: string, isOwnPost: boolean): Promise<void> {
661
- console.log('[Community] Post long pressed:', postId, 'isOwn:', isOwnPost);
662
-
663
- const sheet = await this.bottomSheet.create({
664
- component: DsMobilePostActionsBottomSheetComponent,
665
- componentProps: {
666
- isOwnContent: isOwnPost
667
- },
668
- breakpoints: [0, 1],
669
- initialBreakpoint: 1,
670
- handle: true,
671
- backdropDismiss: true,
672
- cssClass: 'auto-height'
673
- });
674
-
675
- const result = await sheet.onWillDismiss();
676
-
677
- if (result.role === 'select' && result.data) {
678
- const action = (result.data as PostActionResult).action;
679
-
680
- switch (action) {
681
- case 'edit':
682
- console.log('Edit post:', postId);
683
-
684
- // Get post from service
685
- const post = this.postsService.getPostById(postId);
686
- if (!post) {
687
- console.error('Post not found:', postId);
688
- return;
689
- }
690
-
691
- // Open the bottom sheet in edit mode
692
- const editSheet = await this.bottomSheet.create({
693
- component: DsMobilePostCreateBottomSheetComponent,
694
- componentProps: {
695
- autoFocus: true,
696
- isEditMode: true,
697
- postId: postId,
698
- initialContent: post.content
699
- },
700
- breakpoints: [0, 0.95, 1],
701
- initialBreakpoint: 0.95,
702
- handle: true,
703
- backdropBlur: true,
704
- backdropOpacity: 0.6
705
- });
706
-
707
- // Handle the result when the sheet is dismissed
708
- const editResult = await editSheet.onWillDismiss();
709
- if (editResult.role === 'post' && editResult.data) {
710
- console.log('Post updated:', editResult.data);
711
-
712
- // Update the post via service
713
- this.postsService.updatePost(postId, {
714
- content: editResult.data.content,
715
- timestamp: 'Lige nu'
716
- });
717
- }
718
- break;
719
-
720
- case 'delete':
721
- console.log('Delete post:', postId);
722
- if (confirm('Er du sikker på, at du vil slette dette opslag?')) {
723
- this.postsService.deletePost(postId);
724
- }
725
- break;
726
-
727
- case 'like':
728
- console.log('Like post:', postId);
729
- // Toggle like - in a real app, this would call an API
730
- const likePost = this.postsService.getPostById(postId);
731
- if (likePost) {
732
- this.postsService.updatePost(postId, {
733
- isLiked: !likePost.isLiked,
734
- likeCount: likePost.isLiked ? likePost.likeCount - 1 : likePost.likeCount + 1
735
- });
736
- }
737
- break;
738
-
739
- case 'reply':
740
- console.log('Reply to post:', postId);
741
- // Open the post detail modal with comment input focused
742
- await this.openPost(postId, true);
743
- break;
744
- }
745
- }
746
- }
747
-
748
- /**
749
- * Navigate to previous slide in pinned posts
750
- */
751
- slidePrev(): void {
752
- this.pinnedSwiper?.slidePrev();
753
- }
754
-
755
- /**
756
- * Navigate to next slide in pinned posts
757
- */
758
- slideNext(): void {
759
- this.pinnedSwiper?.slideNext();
760
- }
761
-
762
- /**
763
- * Check if currently on first slide
764
- */
765
- isFirstSlide(): boolean {
766
- return this.pinnedSwiper?.isBeginning() ?? true;
767
- }
768
-
769
- /**
770
- * Check if currently on last slide
771
- */
772
- isLastSlide(): boolean {
773
- return this.pinnedSwiper?.isEnd() ?? true;
774
- }
775
- }
776
-