@propbinder/mobile-design 0.2.48 → 0.2.50

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/ng-package.json +24 -0
  2. package/package.json +3 -39
  3. package/src/animations/page-transitions.ts +165 -0
  4. package/src/assets/fonts/brockmann-mediumitalic-webfont.woff2 +0 -0
  5. package/src/assets/fonts/brockmann-regularitalic-webfont.woff2 +0 -0
  6. package/src/assets/fonts/brockmann-semibolditalic-webfont.woff2 +0 -0
  7. package/src/components/action-list-item/ds-mobile-action-list-item.ts +102 -0
  8. package/src/components/action-list-item/index.ts +2 -0
  9. package/src/components/app-icon/ds-app-icon.ts +133 -0
  10. package/src/components/app-icon/index.ts +2 -0
  11. package/src/components/attachment-preview/ds-mobile-attachment-preview.css +139 -0
  12. package/src/components/attachment-preview/ds-mobile-attachment-preview.ts +164 -0
  13. package/src/components/attachment-preview/index.ts +1 -0
  14. package/src/components/avatar-with-badge/ds-avatar-with-badge.ts +142 -0
  15. package/src/components/avatar-with-badge/index.ts +2 -0
  16. package/src/components/booking-modal/ds-mobile-booking-confirmation-wrapper.ts +71 -0
  17. package/src/components/booking-modal/ds-mobile-booking-modal.service.ts +121 -0
  18. package/src/components/booking-modal/ds-mobile-booking-modal.ts +598 -0
  19. package/src/components/booking-modal/ds-mobile-booking-summary.ts +161 -0
  20. package/src/components/booking-modal/index.ts +4 -0
  21. package/src/components/bottom-sheet/ds-mobile-actions-bottom-sheet.ts +266 -0
  22. package/src/components/bottom-sheet/ds-mobile-bottom-sheet-header.ts +146 -0
  23. package/src/components/bottom-sheet/ds-mobile-bottom-sheet-wrapper.ts +156 -0
  24. package/src/components/bottom-sheet/ds-mobile-bottom-sheet.css +101 -0
  25. package/src/components/bottom-sheet/ds-mobile-bottom-sheet.service.ts +169 -0
  26. package/src/components/bottom-sheet/ds-mobile-confirmation-sheet.ts +211 -0
  27. package/src/components/bottom-sheet/ds-mobile-post-create-bottom-sheet.ts +578 -0
  28. package/src/components/bottom-sheet/ds-mobile-profile-actions-sheet.ts +614 -0
  29. package/src/components/bottom-sheet/index.ts +8 -0
  30. package/src/components/bottom-sheet/modal-shadow-fix.ts +42 -0
  31. package/src/components/card-inline/ds-mobile-card-inline.ts +301 -0
  32. package/src/components/card-inline/index.ts +2 -0
  33. package/src/components/card-inline-banner/ds-mobile-card-inline-banner.ts +118 -0
  34. package/src/components/card-inline-banner/index.ts +1 -0
  35. package/src/components/card-inline-contact/ds-mobile-card-inline-contact.ts +120 -0
  36. package/src/components/card-inline-contact/index.ts +1 -0
  37. package/src/components/card-inline-file/ds-mobile-card-inline-file.ts +141 -0
  38. package/src/components/card-inline-file/index.ts +1 -0
  39. package/src/components/chat-modal/ds-mobile-chat-modal.css +159 -0
  40. package/src/components/chat-modal/ds-mobile-chat-modal.service.ts +105 -0
  41. package/src/components/chat-modal/ds-mobile-chat-modal.ts +918 -0
  42. package/src/components/chat-modal/index.ts +8 -0
  43. package/src/components/comment/ds-mobile-comment.ts +568 -0
  44. package/src/components/comment/index.ts +2 -0
  45. package/src/components/contact-list-item/ds-mobile-contact-list-item.ts +182 -0
  46. package/src/components/contact-list-item/index.ts +2 -0
  47. package/src/components/content/ds-mobile-content.ts +139 -0
  48. package/src/components/content/index.ts +2 -0
  49. package/src/components/dropdown/ds-mobile-dropdown.css +199 -0
  50. package/src/components/dropdown/ds-mobile-dropdown.ts +340 -0
  51. package/src/components/dropdown/index.ts +2 -0
  52. package/src/components/ds-mobile-tabs.css +407 -0
  53. package/src/components/ds-mobile-tabs.ts +216 -0
  54. package/src/components/empty-state/ds-mobile-empty-state.ts +120 -0
  55. package/src/components/empty-state/index.ts +2 -0
  56. package/src/components/fab/ds-mobile-fab.ts +315 -0
  57. package/src/components/fab/index.ts +1 -0
  58. package/src/components/facility-creation-modal/ds-mobile-facility-creation-confirmation-wrapper.ts +121 -0
  59. package/src/components/facility-creation-modal/ds-mobile-facility-creation-modal.css +189 -0
  60. package/src/components/facility-creation-modal/ds-mobile-facility-creation-modal.service.ts +135 -0
  61. package/src/components/facility-creation-modal/ds-mobile-facility-creation-modal.ts +656 -0
  62. package/src/components/facility-creation-modal/index.ts +9 -0
  63. package/src/components/facility-creation-modal/sheets/ds-mobile-access-sheet.ts +105 -0
  64. package/src/components/facility-creation-modal/sheets/ds-mobile-price-sheet.ts +188 -0
  65. package/src/components/facility-creation-modal/sheets/ds-mobile-when-can-book-sheet.ts +460 -0
  66. package/src/components/facility-creation-modal/sheets/ds-mobile-who-can-book-sheet.ts +134 -0
  67. package/src/components/facility-detail-modal/ds-mobile-facility-detail-modal.service.ts +69 -0
  68. package/src/components/facility-detail-modal/ds-mobile-facility-detail-modal.ts +379 -0
  69. package/src/components/facility-detail-modal/index.ts +2 -0
  70. package/src/components/file-attachment/ds-mobile-file-attachment.ts +164 -0
  71. package/src/components/file-attachment/index.ts +2 -0
  72. package/src/components/handbook-detail-modal/ds-mobile-handbook-detail-modal.css +214 -0
  73. package/src/components/handbook-detail-modal/ds-mobile-handbook-detail-modal.service.ts +84 -0
  74. package/src/components/handbook-detail-modal/ds-mobile-handbook-detail-modal.ts +424 -0
  75. package/src/components/handbook-detail-modal/index.ts +3 -0
  76. package/src/components/handbook-folder/ds-mobile-handbook-folder-mini.ts +175 -0
  77. package/src/components/handbook-folder/ds-mobile-handbook-folder.ts +533 -0
  78. package/src/components/handbook-folder/index.ts +4 -0
  79. package/src/components/header-content/ds-mobile-header-content.ts +222 -0
  80. package/src/components/header-content/index.ts +2 -0
  81. package/src/components/illustration/ds-mobile-illustration.ts +124 -0
  82. package/src/components/illustration/index.ts +2 -0
  83. package/src/components/index.ts +124 -0
  84. package/src/components/inline-photo/ds-mobile-inline-photo.ts +361 -0
  85. package/src/components/inline-photo/index.ts +1 -0
  86. package/src/components/inline-tabs/ds-mobile-inline-tabs.ts +132 -0
  87. package/src/components/inline-tabs/index.ts +2 -0
  88. package/src/components/interactive-list-item-booking/ds-mobile-interactive-list-item-booking.ts +350 -0
  89. package/src/components/interactive-list-item-booking/index.ts +1 -0
  90. package/src/components/interactive-list-item-inquiry/ds-mobile-interactive-list-item-inquiry.ts +321 -0
  91. package/src/components/interactive-list-item-inquiry/index.ts +2 -0
  92. package/src/components/interactive-list-item-message/ds-mobile-interactive-list-item-message.ts +237 -0
  93. package/src/components/interactive-list-item-message/index.ts +2 -0
  94. package/src/components/interactive-list-item-post/ds-mobile-interactive-list-item-post.ts +549 -0
  95. package/src/components/interactive-list-item-post/ds-mobile-post-pdf-attachment.ts +124 -0
  96. package/src/components/interactive-list-item-post/index.ts +13 -0
  97. package/src/components/lightbox/ds-mobile-lightbox-footer.ts +315 -0
  98. package/src/components/lightbox/ds-mobile-lightbox-header.ts +202 -0
  99. package/src/components/lightbox/ds-mobile-lightbox-image.ts +484 -0
  100. package/src/components/lightbox/ds-mobile-lightbox-pdf.css +377 -0
  101. package/src/components/lightbox/ds-mobile-lightbox-pdf.ts +374 -0
  102. package/src/components/lightbox/ds-mobile-lightbox.css +587 -0
  103. package/src/components/lightbox/ds-mobile-lightbox.service.ts +296 -0
  104. package/src/components/lightbox/ds-mobile-lightbox.ts +529 -0
  105. package/src/components/lightbox/index.ts +22 -0
  106. package/src/components/list-item/ds-mobile-list-item.ts +603 -0
  107. package/src/components/list-item/index.ts +2 -0
  108. package/src/components/list-item-static/ds-mobile-list-item-static.ts +133 -0
  109. package/src/components/list-item-static/index.ts +2 -0
  110. package/src/components/loader-overlay/ds-mobile-loader-overlay.css +49 -0
  111. package/src/components/loader-overlay/ds-mobile-loader-overlay.ts +77 -0
  112. package/src/components/loader-overlay/index.ts +1 -0
  113. package/src/components/logo/ds-logo.ts +95 -0
  114. package/src/components/logo/index.ts +2 -0
  115. package/src/components/message-bubble/ds-mobile-message-bubble.ts +633 -0
  116. package/src/components/message-bubble/index.ts +7 -0
  117. package/src/components/message-composer/ds-mobile-message-composer.ts +1146 -0
  118. package/src/components/message-composer/index.ts +7 -0
  119. package/src/components/modal/ds-mobile-modal.css +163 -0
  120. package/src/components/modal/ds-mobile-modal.service.ts +329 -0
  121. package/src/components/modal/index.ts +8 -0
  122. package/src/components/modal-base/ds-mobile-modal-base.css +378 -0
  123. package/src/components/modal-base/ds-mobile-modal-base.ts +261 -0
  124. package/src/components/modal-base/index.ts +2 -0
  125. package/src/components/new-inquiry-modal/ds-mobile-new-inquiry-modal.css +112 -0
  126. package/src/components/new-inquiry-modal/ds-mobile-new-inquiry-modal.service.ts +93 -0
  127. package/src/components/new-inquiry-modal/ds-mobile-new-inquiry-modal.ts +442 -0
  128. package/src/components/new-inquiry-modal/index.ts +4 -0
  129. package/src/components/offline-banner/ds-mobile-offline-banner.ts +135 -0
  130. package/src/components/offline-banner/index.ts +1 -0
  131. package/src/components/page-details/ds-mobile-page-details.css +83 -0
  132. package/src/components/page-details/ds-mobile-page-details.ts +282 -0
  133. package/src/components/page-details/index.ts +2 -0
  134. package/src/components/page-main/ds-mobile-page-main.css +68 -0
  135. package/src/components/page-main/ds-mobile-page-main.ts +421 -0
  136. package/src/components/page-main/index.ts +2 -0
  137. package/src/components/post-composer/ds-mobile-post-composer.ts +140 -0
  138. package/src/components/post-composer/index.ts +2 -0
  139. package/src/components/post-detail-modal/ds-mobile-post-detail-modal.css +390 -0
  140. package/src/components/post-detail-modal/ds-mobile-post-detail-modal.service.ts +108 -0
  141. package/src/components/post-detail-modal/ds-mobile-post-detail-modal.ts +722 -0
  142. package/src/components/post-detail-modal/index.ts +9 -0
  143. package/src/components/property-banner/ds-mobile-property-banner.ts +95 -0
  144. package/src/components/property-banner/index.ts +2 -0
  145. package/src/components/section/ds-mobile-section.ts +263 -0
  146. package/src/components/section/index.ts +2 -0
  147. package/src/components/shared/directives/index.ts +2 -0
  148. package/src/components/shared/directives/long-press.directive.ts +212 -0
  149. package/src/components/shared/index.ts +3 -0
  150. package/src/components/shared/mobile-modal-base.ts +457 -0
  151. package/src/components/shared/mobile-page-base.ts +204 -0
  152. package/src/components/swiper/ds-mobile-swiper-with-nav.ts +160 -0
  153. package/src/components/swiper/ds-mobile-swiper.ts +327 -0
  154. package/src/components/swiper/index.ts +3 -0
  155. package/src/components/system-message-banner/ds-mobile-system-message-banner.ts +129 -0
  156. package/src/components/system-message-banner/index.ts +2 -0
  157. package/src/components/tab-bar/ds-mobile-tab-bar.css +533 -0
  158. package/src/components/tab-bar/ds-mobile-tab-bar.ts +735 -0
  159. package/src/components/tab-bar/index.ts +2 -0
  160. package/src/components/tabs/ds-mobile-tabs.css +25 -0
  161. package/src/components/tabs/ds-mobile-tabs.ts +89 -0
  162. package/src/components/tabs/index.ts +2 -0
  163. package/src/components/text-input/ds-text-input.ts +287 -0
  164. package/src/components/text-input/index.ts +2 -0
  165. package/src/examples/booking.page.ts +434 -0
  166. package/src/examples/community.page.ts +776 -0
  167. package/src/examples/handbook.page.ts +324 -0
  168. package/src/examples/home.page.ts +347 -0
  169. package/src/examples/index.ts +12 -0
  170. package/src/examples/inquiries.example.ts +273 -0
  171. package/src/examples/inquiry-detail.example.css +189 -0
  172. package/src/examples/inquiry-detail.example.ts +415 -0
  173. package/src/examples/mobile-tabs-example.component.ts +208 -0
  174. package/src/examples/post-create.page.ts +311 -0
  175. package/src/examples/post-detail.page.ts +296 -0
  176. package/src/examples/sign-in.page.ts +291 -0
  177. package/src/examples/whitelabel-demo-modal.component.ts +1094 -0
  178. package/src/examples/whitelabel-demo-modal.service.ts +77 -0
  179. package/src/models/index.ts +7 -0
  180. package/src/models/post.model.ts +41 -0
  181. package/src/pages/community.page.ts +769 -0
  182. package/src/pages/handbook.page.ts +388 -0
  183. package/src/pages/home.page.ts +303 -0
  184. package/src/pages/index.ts +11 -0
  185. package/src/pages/inquiries.example.ts +273 -0
  186. package/src/pages/inquiry-detail.example.css +189 -0
  187. package/src/pages/inquiry-detail.example.ts +415 -0
  188. package/src/pages/mobile-tabs-example.component.ts +179 -0
  189. package/src/pages/post-create.page.ts +311 -0
  190. package/src/pages/post-detail.page.ts +296 -0
  191. package/src/pages/sign-in.page.ts +291 -0
  192. package/src/pages/whitelabel-demo-modal.component.ts +1094 -0
  193. package/src/pages/whitelabel-demo-modal.service.ts +77 -0
  194. package/src/public-api.ts +6 -0
  195. package/src/services/base-modal.service.ts +101 -0
  196. package/src/services/index.ts +11 -0
  197. package/src/services/posts.service.ts +542 -0
  198. package/src/services/tracking-permission.service.ts +88 -0
  199. package/src/services/user.service.ts +60 -0
  200. package/src/services/whitelabel.service.ts +675 -0
  201. package/{styles → src/styles}/ionic.css +25 -0
  202. package/tsconfig.lib.json +17 -0
  203. package/tsconfig.lib.prod.json +9 -0
  204. package/tsconfig.spec.json +13 -0
  205. package/fesm2022/propbinder-mobile-design.mjs +0 -26168
  206. package/fesm2022/propbinder-mobile-design.mjs.map +0 -1
  207. package/index.d.ts +0 -8169
  208. /package/{assets → src/assets}/fonts/Brockmann-Bold.otf +0 -0
  209. /package/{assets → src/assets}/fonts/Brockmann-BoldItalic.otf +0 -0
  210. /package/{assets → src/assets}/fonts/Brockmann-Medium.otf +0 -0
  211. /package/{assets → src/assets}/fonts/Brockmann-MediumItalic.otf +0 -0
  212. /package/{assets → src/assets}/fonts/Brockmann-Regular.otf +0 -0
  213. /package/{assets → src/assets}/fonts/Brockmann-RegularItalic.otf +0 -0
  214. /package/{assets → src/assets}/fonts/Brockmann-SemiBold.otf +0 -0
  215. /package/{assets → src/assets}/fonts/Brockmann-SemiBoldItalic.otf +0 -0
  216. /package/{assets → src/assets}/fonts/Brockmann_desktop_license.pdf +0 -0
  217. /package/{assets → src/assets}/fonts/brockmann-medium-webfont.woff2 +0 -0
  218. /package/{assets → src/assets}/fonts/brockmann-regular-webfont.woff2 +0 -0
  219. /package/{assets → src/assets}/fonts/brockmann-semibold-webfont.woff2 +0 -0
  220. /package/{styles → src/components/shared}/mobile-common.css +0 -0
  221. /package/{styles → src/components/shared}/mobile-page-base.css +0 -0
@@ -0,0 +1,542 @@
1
+ import { Injectable, signal, computed } from '@angular/core';
2
+ import { Post, Comment } from '../models/post.model';
3
+
4
+ /**
5
+ * PostsService
6
+ *
7
+ * Centralized service for managing community posts.
8
+ * Provides a single source of truth for post data, including comments.
9
+ *
10
+ * Features:
11
+ * - CRUD operations for posts
12
+ * - Infinite scroll pagination
13
+ * - Post search/filter (future)
14
+ * - Comment management (future)
15
+ */
16
+ @Injectable({
17
+ providedIn: 'root'
18
+ })
19
+ export class PostsService {
20
+ // Private signal for internal state management
21
+ private postsState = signal<Post[]>(this.getInitialPosts());
22
+
23
+ // Public computed signal (read-only)
24
+ posts = computed(() => this.postsState());
25
+
26
+ // Pagination state for infinite scroll
27
+ private currentPage = signal(0);
28
+ private hasMore = signal(true);
29
+
30
+ constructor() {}
31
+
32
+ /**
33
+ * Get a post by ID
34
+ */
35
+ getPostById(id: string): Post | undefined {
36
+ return this.postsState().find(post => post.id === id);
37
+ }
38
+
39
+ /**
40
+ * Add a new post (e.g., from post creator)
41
+ * Adds to the beginning of the list
42
+ */
43
+ addPost(post: Post): void {
44
+ this.postsState.update(posts => [post, ...posts]);
45
+ }
46
+
47
+ /**
48
+ * Update an existing post
49
+ */
50
+ updatePost(id: string, updates: Partial<Post>): void {
51
+ this.postsState.update(posts =>
52
+ posts.map(post => post.id === id ? { ...post, ...updates } : post)
53
+ );
54
+ }
55
+
56
+ /**
57
+ * Delete a post by ID
58
+ */
59
+ deletePost(id: string): void {
60
+ this.postsState.update(posts => posts.filter(post => post.id !== id));
61
+ }
62
+
63
+ /**
64
+ * Load more posts for infinite scroll
65
+ * Returns true if more posts were loaded, false if no more posts
66
+ */
67
+ async loadMorePosts(): Promise<boolean> {
68
+ const page = this.currentPage();
69
+ const itemsPerPage = 2;
70
+ const additionalPosts = this.getAdditionalPosts();
71
+ const startIndex = page * itemsPerPage;
72
+ const endIndex = startIndex + itemsPerPage;
73
+
74
+ // Simulate API delay
75
+ await new Promise(resolve => setTimeout(resolve, 1000));
76
+
77
+ // Get next batch
78
+ const newPosts = additionalPosts.slice(startIndex, endIndex);
79
+
80
+ if (newPosts.length > 0) {
81
+ // Append to existing posts
82
+ this.postsState.update(posts => [...posts, ...newPosts]);
83
+ this.currentPage.update(p => p + 1);
84
+
85
+ // Check if there are more posts
86
+ if (endIndex >= additionalPosts.length) {
87
+ this.hasMore.set(false);
88
+ }
89
+
90
+ return true;
91
+ }
92
+
93
+ this.hasMore.set(false);
94
+ return false;
95
+ }
96
+
97
+ /**
98
+ * Check if there are more posts to load
99
+ */
100
+ hasMorePosts(): boolean {
101
+ return this.hasMore();
102
+ }
103
+
104
+ /**
105
+ * Reset pagination (e.g., on pull-to-refresh)
106
+ */
107
+ resetPagination(): void {
108
+ this.currentPage.set(0);
109
+ this.hasMore.set(true);
110
+ }
111
+
112
+ /**
113
+ * Get initial posts (shown on page load)
114
+ */
115
+ private getInitialPosts(): Post[] {
116
+ return [
117
+ {
118
+ id: 'user-post-1',
119
+ authorName: 'Lars Mikkelsen',
120
+ authorRole: 'Dig',
121
+ timestamp: '5m siden',
122
+ avatarType: 'initials',
123
+ avatarInitials: 'LM',
124
+ content: 'Dette er mit første opslag! Ser frem til at forbinde med alle i bygningen. 🏠',
125
+ isLiked: false,
126
+ likeCount: 3,
127
+ commentCount: 1,
128
+ comments: []
129
+ },
130
+ {
131
+ id: 'post-1',
132
+ authorName: 'Anders Jensen',
133
+ authorRole: 'Lejer',
134
+ timestamp: '2t siden',
135
+ avatarType: 'photo',
136
+ avatarSrc: 'https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?w=100&h=100&fit=crop&crop=face',
137
+ content: 'Lige flyttet ind i min nye lejlighed! Udlejeren var super hjælpsom gennem hele processen. Virkelig begejstret for at være en del af dette fællesskab! 🏠',
138
+ isLiked: false,
139
+ likeCount: 42,
140
+ commentCount: 12,
141
+ comments: [
142
+ {
143
+ id: 'comment-1-1',
144
+ authorName: 'Mette Larsen',
145
+ authorRole: 'Lejer',
146
+ timestamp: '1t siden',
147
+ avatarInitials: 'ML',
148
+ content: 'Velkommen til fællesskabet!',
149
+ likeCount: 1,
150
+ isLiked: false,
151
+ isOwnComment: false
152
+ },
153
+ {
154
+ id: 'comment-1-2',
155
+ authorName: 'Lars Mikkelsen',
156
+ authorRole: 'Dig',
157
+ timestamp: 'Lige nu',
158
+ avatarInitials: 'LM',
159
+ content: 'Vxhknbh',
160
+ likeCount: 1,
161
+ isLiked: false,
162
+ isOwnComment: true
163
+ }
164
+ ]
165
+ },
166
+ {
167
+ id: 'post-2',
168
+ authorName: 'Sophie Andersen',
169
+ authorRole: 'Lejer',
170
+ timestamp: '4t siden',
171
+ avatarInitials: 'SA',
172
+ avatarType: 'initials',
173
+ content: 'Jeg har taget nogle billeder af vores smukke ejendom i løbet af det sidste par måneder. Fra altanudsigten om morgenen til den nye trappe og fællesområderne. Elsker virkelig at bo her! 🏡✨',
174
+ hasInlinePhotos: true,
175
+ isLiked: true,
176
+ likeCount: 156,
177
+ commentCount: 34,
178
+ comments: [
179
+ {
180
+ id: 'comment-2-1',
181
+ authorName: 'Anders Jensen',
182
+ authorRole: 'Lejer',
183
+ timestamp: '3t siden',
184
+ avatarInitials: 'AJ',
185
+ content: 'Wow, den udsigt er fantastisk! Hvilken etage er du på?',
186
+ likeCount: 12,
187
+ isLiked: false,
188
+ isOwnComment: false
189
+ },
190
+ {
191
+ id: 'comment-2-2',
192
+ authorName: 'Thomas Hansen',
193
+ authorRole: 'Lejer',
194
+ timestamp: '3t siden',
195
+ avatarInitials: 'TH',
196
+ content: 'Smuk! Jeg kan også se byens silhuet fra min lejlighed 🌆',
197
+ isLiked: true,
198
+ likeCount: 8,
199
+ isOwnComment: false
200
+ },
201
+ {
202
+ id: 'comment-2-3',
203
+ authorName: 'Lars Mikkelsen',
204
+ authorRole: 'Dig',
205
+ timestamp: 'Lige nu',
206
+ avatarInitials: 'LM',
207
+ content: 'Vxhknbh',
208
+ likeCount: 1,
209
+ isLiked: false,
210
+ isOwnComment: true
211
+ }
212
+ ]
213
+ },
214
+ {
215
+ id: 'post-3',
216
+ authorName: 'Thomas Hansen',
217
+ authorRole: 'Lejer',
218
+ timestamp: '1d siden',
219
+ avatarType: 'photo',
220
+ avatarSrc: 'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=100&h=100&fit=crop&crop=face',
221
+ content: 'Kender nogen et fælles fitnesscenter i nærheden? Leder efter anbefalinger til gode træningscentre i området. 🏋️',
222
+ isLiked: false,
223
+ likeCount: 23,
224
+ commentCount: 45,
225
+ comments: []
226
+ },
227
+ {
228
+ id: 'post-3.5',
229
+ authorName: 'Karen Nielsen',
230
+ authorRole: 'Ejendomsadministrator',
231
+ timestamp: '2d siden',
232
+ avatarInitials: 'KN',
233
+ avatarType: 'initials',
234
+ showBadge: true,
235
+ isPinned: true,
236
+ content: 'Her er et kig på vores nyligt renoverede fællesområder! Vi har opgraderet postkasserne, trappeafsatsen og gårdområdet. Der er også blevet ansat en ny vicevært. Glæd dig over forbedringerne! 🏢✨',
237
+ hasInlinePhotos: true,
238
+ inlinePhotoCount: 6,
239
+ isLiked: false,
240
+ likeCount: 234,
241
+ commentCount: 89,
242
+ comments: []
243
+ },
244
+ {
245
+ id: 'post-4',
246
+ authorName: 'Karen Nielsen',
247
+ authorRole: 'Ejendomsadministrator',
248
+ timestamp: '2d siden',
249
+ avatarInitials: 'KN',
250
+ avatarType: 'initials',
251
+ showBadge: true,
252
+ isPinned: true,
253
+ content: '📢 Påmindelse: Bygningsvedligeholdelse planlagt til denne lørdag fra kl. 9 til 14. Vandet vil være midlertidigt lukket. Vær venlig at planlægge derefter!',
254
+ isLiked: false,
255
+ likeCount: 89,
256
+ commentCount: 67,
257
+ comments: []
258
+ },
259
+ {
260
+ id: 'post-5',
261
+ authorName: 'Emma Petersen',
262
+ authorRole: 'Lejer',
263
+ timestamp: '3d siden',
264
+ avatarType: 'photo',
265
+ avatarSrc: 'https://images.unsplash.com/photo-1438761681033-6461ffad8d80?w=100&h=100&fit=crop&crop=face',
266
+ content: 'Arrangerer en fælles BBQ næste weekend! Alle er inviteret. Tag din yndlingsret med til at dele. Lad os lære hinanden bedre at kende! 🍔🌭',
267
+ isLiked: true,
268
+ likeCount: 124,
269
+ commentCount: 89,
270
+ comments: []
271
+ }
272
+ ];
273
+ }
274
+
275
+ /**
276
+ * Get additional posts for infinite scroll
277
+ */
278
+ private getAdditionalPosts(): Post[] {
279
+ return [
280
+ {
281
+ id: 'post-6',
282
+ authorName: 'Peter Christensen',
283
+ authorRole: 'Lejer',
284
+ timestamp: '4d siden',
285
+ avatarType: 'photo',
286
+ avatarSrc: 'https://images.unsplash.com/photo-1500648767791-00dcc994a43e?w=100&h=100&fit=crop&crop=face',
287
+ content: 'Nogen der ved, hvornår de nye cykelstativer bliver installeret? 🚲',
288
+ isLiked: false,
289
+ likeCount: 15,
290
+ commentCount: 23,
291
+ comments: []
292
+ },
293
+ {
294
+ id: 'post-7',
295
+ authorName: 'Maria Schmidt',
296
+ authorRole: 'Lejer',
297
+ timestamp: '5d siden',
298
+ avatarInitials: 'MS',
299
+ avatarType: 'initials',
300
+ content: 'Tak til vores fantastiske vicevært for at holde bygningen så pæn og ren! 🌟',
301
+ isLiked: true,
302
+ likeCount: 78,
303
+ commentCount: 12,
304
+ comments: []
305
+ },
306
+ {
307
+ id: 'post-8',
308
+ authorName: 'Jens Nielsen',
309
+ authorRole: 'Lejer',
310
+ timestamp: '6d siden',
311
+ avatarType: 'photo',
312
+ avatarSrc: 'https://images.unsplash.com/photo-1519345182560-3f2917c472ef?w=100&h=100&fit=crop&crop=face',
313
+ content: 'Jeg har fundet en nøgle i gården. Hvis den er din, så kontakt mig! 🔑',
314
+ isLiked: false,
315
+ likeCount: 8,
316
+ commentCount: 3,
317
+ comments: []
318
+ },
319
+ {
320
+ id: 'post-9',
321
+ authorName: 'Anna Larsen',
322
+ authorRole: 'Lejer',
323
+ timestamp: '1u siden',
324
+ avatarInitials: 'AL',
325
+ avatarType: 'initials',
326
+ content: 'Glædelig sommer til alle! ☀️ Håber I alle får en vidunderlig ferie!',
327
+ isLiked: true,
328
+ likeCount: 134,
329
+ commentCount: 45,
330
+ comments: []
331
+ },
332
+ {
333
+ id: 'post-10',
334
+ authorName: 'Michael Andersen',
335
+ authorRole: 'Lejer',
336
+ timestamp: '1u siden',
337
+ avatarType: 'photo',
338
+ avatarSrc: 'https://images.unsplash.com/photo-1506794778202-cad84cf45f1d?w=100&h=100&fit=crop&crop=face',
339
+ content: 'Er der nogen der kan anbefale en god pizzarestaurant i området? 🍕',
340
+ isLiked: false,
341
+ likeCount: 32,
342
+ commentCount: 67,
343
+ comments: []
344
+ },
345
+ {
346
+ id: 'post-11',
347
+ authorName: 'Camilla Jensen',
348
+ authorRole: 'Lejer',
349
+ timestamp: '2u siden',
350
+ avatarInitials: 'CJ',
351
+ avatarType: 'initials',
352
+ content: 'Hej alle! Jeg overvejer at starte en bogklub. Er der nogen interesserede? 📚',
353
+ isLiked: false,
354
+ likeCount: 42,
355
+ commentCount: 28,
356
+ comments: []
357
+ },
358
+ {
359
+ id: 'post-12',
360
+ authorName: 'Henrik Madsen',
361
+ authorRole: 'Lejer',
362
+ timestamp: '2u siden',
363
+ avatarType: 'photo',
364
+ avatarSrc: 'https://images.unsplash.com/photo-1568602471122-7832951cc4c5?w=100&h=100&fit=crop&crop=face',
365
+ content: 'Vores fælles have ser fantastisk ud i år! Stor ros til haveudvalget! 🌻🌸',
366
+ isLiked: true,
367
+ likeCount: 95,
368
+ commentCount: 18,
369
+ comments: []
370
+ },
371
+ {
372
+ id: 'post-13',
373
+ authorName: 'Louise Berg',
374
+ authorRole: 'Lejer',
375
+ timestamp: '3u siden',
376
+ avatarInitials: 'LB',
377
+ avatarType: 'initials',
378
+ content: 'Påmindelse: Generalforsamling næste mandag kl. 19. Håber at se jer alle! 📋',
379
+ isLiked: false,
380
+ likeCount: 56,
381
+ commentCount: 34,
382
+ comments: []
383
+ },
384
+ {
385
+ id: 'post-14',
386
+ authorName: 'Martin Olsen',
387
+ authorRole: 'Lejer',
388
+ timestamp: '3u siden',
389
+ avatarType: 'photo',
390
+ avatarSrc: 'https://images.unsplash.com/photo-1566492031773-4f4e44671857?w=100&h=100&fit=crop&crop=face',
391
+ content: 'Har nogen set min kat? Hun har været væk siden i går aftes. Hun hedder Luna og er grå. 🐱',
392
+ isLiked: false,
393
+ likeCount: 67,
394
+ commentCount: 45,
395
+ comments: []
396
+ },
397
+ {
398
+ id: 'post-15',
399
+ authorName: 'Sarah Thomsen',
400
+ authorRole: 'Lejer',
401
+ timestamp: '4u siden',
402
+ avatarInitials: 'ST',
403
+ avatarType: 'initials',
404
+ content: 'Super godt initiativ med de nye genbrugsstationer! Gør det meget nemmere at sortere affald 💚♻️',
405
+ isLiked: true,
406
+ likeCount: 123,
407
+ commentCount: 21,
408
+ comments: []
409
+ },
410
+ {
411
+ id: 'post-16',
412
+ authorName: 'Nikolaj Hansen',
413
+ authorRole: 'Lejer',
414
+ timestamp: '5u siden',
415
+ avatarType: 'photo',
416
+ avatarSrc: 'https://images.unsplash.com/photo-1570295999919-56ceb5ecca61?w=100&h=100&fit=crop&crop=face',
417
+ content: 'Leder efter en pålídelig babysitter i bygningen. Kender I nogen? Tak! 👶',
418
+ isLiked: false,
419
+ likeCount: 12,
420
+ commentCount: 9,
421
+ comments: []
422
+ },
423
+ {
424
+ id: 'post-17',
425
+ authorName: 'Isabella Larsen',
426
+ authorRole: 'Lejer',
427
+ timestamp: '6u siden',
428
+ avatarInitials: 'IL',
429
+ avatarType: 'initials',
430
+ content: 'Vi holder en lille julemarked i gården på lørdag! Kom og køb håndlavede ting og nyd varm kakao! 🎄☕',
431
+ isLiked: true,
432
+ likeCount: 187,
433
+ commentCount: 56,
434
+ comments: []
435
+ },
436
+ {
437
+ id: 'post-18',
438
+ authorName: 'Frederik Nielsen',
439
+ authorRole: 'Lejer',
440
+ timestamp: '7u siden',
441
+ avatarType: 'photo',
442
+ avatarSrc: 'https://images.unsplash.com/photo-1599566150163-29194dcaad36?w=100&h=100&fit=crop&crop=face',
443
+ content: 'Er der nogen der vil være med til at starte en løbeklub? Tænker 2-3 gange om ugen. 🏃‍♂️',
444
+ isLiked: false,
445
+ likeCount: 38,
446
+ commentCount: 41,
447
+ comments: []
448
+ },
449
+ {
450
+ id: 'post-19',
451
+ authorName: 'Sofie Petersen',
452
+ authorRole: 'Lejer',
453
+ timestamp: '1d siden',
454
+ avatarInitials: 'SP',
455
+ avatarType: 'initials',
456
+ content: 'Fantastisk sammenkomst i går aftes! Tusind tak til alle der kom. Vi skal gøre det igen snart! 🎉',
457
+ isLiked: true,
458
+ likeCount: 156,
459
+ commentCount: 72,
460
+ comments: []
461
+ },
462
+ {
463
+ id: 'post-20',
464
+ authorName: 'Christian Møller',
465
+ authorRole: 'Lejer',
466
+ timestamp: '1d siden',
467
+ avatarType: 'photo',
468
+ avatarSrc: 'https://images.unsplash.com/photo-1552058544-f2b08422138a?w=100&h=100&fit=crop&crop=face',
469
+ content: 'Nogen der har brug for hjælp med at flytte møbler? Jeg har en stor bil og kan hjælpe i weekenden! 🚐',
470
+ isLiked: false,
471
+ likeCount: 29,
472
+ commentCount: 15,
473
+ comments: []
474
+ },
475
+ {
476
+ id: 'post-21',
477
+ authorName: 'Laura Andersen',
478
+ authorRole: 'Lejer',
479
+ timestamp: '2d siden',
480
+ avatarInitials: 'LA',
481
+ avatarType: 'initials',
482
+ content: 'Jeg giver klavertimer hvis nogen er interesserede! Alle niveauer velkomne 🎹🎵',
483
+ isLiked: false,
484
+ likeCount: 44,
485
+ commentCount: 22,
486
+ comments: []
487
+ },
488
+ {
489
+ id: 'post-22',
490
+ authorName: 'Rasmus Schmidt',
491
+ authorRole: 'Lejer',
492
+ timestamp: '2d siden',
493
+ avatarType: 'photo',
494
+ avatarSrc: 'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=100&h=100&fit=crop&crop=face',
495
+ content: 'Vi har fået ny belysning i trappeopgangen! Så meget lysere nu om aftenen 💡',
496
+ isLiked: true,
497
+ likeCount: 89,
498
+ commentCount: 13,
499
+ comments: []
500
+ },
501
+ {
502
+ id: 'post-23',
503
+ authorName: 'Mette Hansen',
504
+ authorRole: 'Lejer',
505
+ timestamp: '3d siden',
506
+ avatarInitials: 'MH',
507
+ avatarType: 'initials',
508
+ content: 'Nogen der vil dele en Costco-medlemskab? Vi kan tage på indkøb sammen! 🛒',
509
+ isLiked: false,
510
+ likeCount: 18,
511
+ commentCount: 31,
512
+ comments: []
513
+ },
514
+ {
515
+ id: 'post-24',
516
+ authorName: 'Jonas Berg',
517
+ authorRole: 'Lejer',
518
+ timestamp: '3d siden',
519
+ avatarType: 'photo',
520
+ avatarSrc: 'https://images.unsplash.com/photo-1500648767791-00dcc994a43e?w=100&h=100&fit=crop&crop=face',
521
+ content: 'Har plantet nye blomster ved indgangen. Håber I kan lide dem! 🌷🌺',
522
+ isLiked: true,
523
+ likeCount: 142,
524
+ commentCount: 38,
525
+ comments: []
526
+ },
527
+ {
528
+ id: 'post-25',
529
+ authorName: 'Caroline Jensen',
530
+ authorRole: 'Lejer',
531
+ timestamp: '4d siden',
532
+ avatarInitials: 'CJ',
533
+ avatarType: 'initials',
534
+ content: 'Leder efter en tennismakker. Er der nogen der spiller? 🎾',
535
+ isLiked: false,
536
+ likeCount: 21,
537
+ commentCount: 17,
538
+ comments: []
539
+ }
540
+ ];
541
+ }
542
+ }
@@ -0,0 +1,88 @@
1
+ import { Injectable, inject, signal } from '@angular/core';
2
+ import { Platform } from '@ionic/angular/standalone';
3
+ import { AppTrackingStatus, AppTrackingTransparency } from 'capacitor-plugin-app-tracking-transparency';
4
+
5
+ @Injectable({
6
+ providedIn: 'root',
7
+ })
8
+ export class TrackingPermissionService {
9
+ private readonly trackingPromptRequestedKey = 'tracking_prompt_requested_v1';
10
+ private readonly platform = inject(Platform);
11
+ private readonly trackingSettingsReminder = signal(false);
12
+
13
+ readonly showTrackingSettingsReminder = this.trackingSettingsReminder.asReadonly();
14
+
15
+ async requestOnFirstHomeEntry(): Promise<void> {
16
+ if (!this.isNativeIos()) {
17
+ this.trackingSettingsReminder.set(false);
18
+ return;
19
+ }
20
+
21
+ if (this.hasRequestedTrackingPrompt()) {
22
+ await this.refreshTrackingStatus();
23
+ return;
24
+ }
25
+
26
+ try {
27
+ const { status } = await AppTrackingTransparency.getStatus();
28
+ if (status === 'notDetermined') {
29
+ await AppTrackingTransparency.requestPermission();
30
+ }
31
+ } catch (error) {
32
+ console.log('Unable to request app tracking permission:', error);
33
+ } finally {
34
+ this.setTrackingPromptRequested();
35
+ await this.refreshTrackingStatus();
36
+ }
37
+ }
38
+
39
+ async getTrackingStatus(): Promise<AppTrackingStatus | null> {
40
+ if (!this.isNativeIos()) {
41
+ return null;
42
+ }
43
+
44
+ try {
45
+ const { status } = await AppTrackingTransparency.getStatus();
46
+ return status;
47
+ } catch (error) {
48
+ console.log('Unable to read app tracking status:', error);
49
+ return null;
50
+ }
51
+ }
52
+
53
+ async openAppSettings(): Promise<void> {
54
+ if (!this.isNativeIos()) {
55
+ return;
56
+ }
57
+
58
+ // iOS deep link for opening this app's system settings page.
59
+ window.location.href = 'app-settings:';
60
+ }
61
+
62
+ shouldShowSettingsReminder(): boolean {
63
+ return this.trackingSettingsReminder();
64
+ }
65
+
66
+ async refreshTrackingStatus(): Promise<void> {
67
+ if (!this.isNativeIos()) {
68
+ this.trackingSettingsReminder.set(false);
69
+ return;
70
+ }
71
+
72
+ const status = await this.getTrackingStatus();
73
+ const hasRequested = this.hasRequestedTrackingPrompt();
74
+ this.trackingSettingsReminder.set(Boolean(hasRequested && status && status !== 'authorized'));
75
+ }
76
+
77
+ private isNativeIos(): boolean {
78
+ return this.platform.is('ios') && this.platform.is('capacitor');
79
+ }
80
+
81
+ private hasRequestedTrackingPrompt(): boolean {
82
+ return localStorage.getItem(this.trackingPromptRequestedKey) === '1';
83
+ }
84
+
85
+ private setTrackingPromptRequested(): void {
86
+ localStorage.setItem(this.trackingPromptRequestedKey, '1');
87
+ }
88
+ }
@@ -0,0 +1,60 @@
1
+ import { Injectable, signal } from '@angular/core';
2
+ import { Subject } from 'rxjs';
3
+ import { ActionGroup, ActionResult } from '../components/bottom-sheet';
4
+
5
+ /**
6
+ * User service for managing current user data globally
7
+ */
8
+ @Injectable({
9
+ providedIn: 'root',
10
+ })
11
+ export class UserService {
12
+ // User avatar configuration
13
+ private _avatarInitials = signal('LM');
14
+ private _avatarType = signal<'initials' | 'photo' | 'icon'>('initials');
15
+ private _avatarSrc = signal('');
16
+
17
+ // Profile menu items configuration
18
+ private _profileMenuItems = signal<ActionGroup[] | undefined>(undefined);
19
+
20
+ // Readonly computed values
21
+ readonly avatarInitials = this._avatarInitials.asReadonly();
22
+ readonly avatarType = this._avatarType.asReadonly();
23
+ readonly avatarSrc = this._avatarSrc.asReadonly();
24
+ readonly profileMenuItems = this._profileMenuItems.asReadonly();
25
+
26
+ // Profile action selection notification
27
+ private profileActionSelectedSubject = new Subject<ActionResult>();
28
+ readonly profileActionSelected$ = this.profileActionSelectedSubject.asObservable();
29
+
30
+ /**
31
+ * Update avatar configuration
32
+ */
33
+ setAvatarInitials(initials: string) {
34
+ this._avatarInitials.set(initials);
35
+ }
36
+
37
+ setAvatarType(type: 'initials' | 'photo' | 'icon') {
38
+ this._avatarType.set(type);
39
+ }
40
+
41
+ setAvatarSrc(src: string) {
42
+ this._avatarSrc.set(src);
43
+ }
44
+
45
+ /**
46
+ * Set profile menu items globally.
47
+ * This will be used by both ds-mobile-tab-bar and ds-mobile-page-main
48
+ * if they don't receive profileMenuItems as an input.
49
+ */
50
+ setProfileMenuItems(items: ActionGroup[]) {
51
+ this._profileMenuItems.set(items);
52
+ }
53
+
54
+ /**
55
+ * Notify subscribers that a profile action was selected
56
+ */
57
+ notifyProfileAction(result: ActionResult) {
58
+ this.profileActionSelectedSubject.next(result);
59
+ }
60
+ }