@propbinder/mobile-design 0.2.47 → 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 -26136
  206. package/fesm2022/propbinder-mobile-design.mjs.map +0 -1
  207. package/index.d.ts +0 -8154
  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,434 @@
1
+ import { Component, signal, ViewChild } from '@angular/core';
2
+ import { DsIconButtonComponent } from '@propbinder/design-system';
3
+ import { DsMobilePageMainComponent } from '../components/page-main';
4
+ import { DsMobileSectionComponent } from '../components/section';
5
+ import { DsMobileSwiperComponent } from '../components/swiper/ds-mobile-swiper';
6
+ import { DsMobileInteractiveListItemBookingComponent } from '../components/interactive-list-item-booking';
7
+ import { DsMobileOfflineBannerComponent } from '../components/offline-banner';
8
+ import { DsMobileFacilityDetailModalService } from '../components/facility-detail-modal';
9
+ import { DsMobileFabComponent } from '../components/fab';
10
+ import { DsMobileFacilityCreationModalService } from '../components/facility-creation-modal';
11
+ import { UserService } from '../services/user.service';
12
+
13
+ interface FacilityDetail {
14
+ id: string;
15
+ thumbnail: string;
16
+ facilityTitle: string;
17
+ description: string;
18
+ availabilityStatus?: 'available-today' | 'available-from' | 'unavailable';
19
+ statusLabel?: string;
20
+
21
+ // Additional fields for modal
22
+ heroImage?: string;
23
+ fullDescription: string;
24
+ requirements?: string[];
25
+ bookingType?: string;
26
+ expectations?: string;
27
+ restrictions?: string[];
28
+ bookingDate?: string;
29
+ bookingTime?: string;
30
+ }
31
+
32
+ @Component({
33
+ selector: 'app-mobile-booking-page',
34
+ standalone: true,
35
+ imports: [
36
+ DsMobilePageMainComponent,
37
+ DsMobileSectionComponent,
38
+ DsMobileInteractiveListItemBookingComponent,
39
+ DsMobileSwiperComponent,
40
+ DsIconButtonComponent,
41
+ DsMobileOfflineBannerComponent,
42
+ DsMobileFabComponent
43
+ ],
44
+ styles: [`
45
+ /* Bookings swiper wrapper */
46
+ .bookings-swiper-wrapper {
47
+ padding: 0;
48
+ position: relative;
49
+ }
50
+
51
+ /* Navigation buttons - position individually to avoid blocking */
52
+ .swiper-nav-buttons {
53
+ /* Remove all positioning - we'll position buttons individually */
54
+ display: contents; /* Use contents to avoid creating a blocking layer */
55
+ }
56
+
57
+ .swiper-nav-button {
58
+ position: absolute;
59
+ top: 50%;
60
+ transform: translateY(-50%);
61
+ z-index: 10;
62
+ }
63
+
64
+ .swiper-nav-button:first-child {
65
+ left: -48px;
66
+ }
67
+
68
+ .swiper-nav-button:last-child {
69
+ right: -48px;
70
+ }
71
+
72
+ /* Force buttons to be perfectly round */
73
+ ::ng-deep .swiper-nav-button button {
74
+ border-radius: 50% !important;
75
+ width: 48px !important;
76
+ height: 48px !important;
77
+ padding: 0 !important;
78
+ }
79
+
80
+ /* Hide on mobile */
81
+ @media (max-width: 767px) {
82
+ .swiper-nav-buttons {
83
+ display: none;
84
+ }
85
+ }
86
+
87
+ /* Swiper slide styling for bookings */
88
+ ::ng-deep .bookings-swiper .swiper-slide {
89
+ width: 100%;
90
+ max-width: 600px;
91
+ height: auto;
92
+ pointer-events: auto;
93
+ }
94
+
95
+ /* Desktop: Remove max-width constraint */
96
+ @media (min-width: 768px) {
97
+ ::ng-deep .bookings-swiper .swiper-slide {
98
+ max-width: 100%;
99
+ }
100
+ }
101
+
102
+ /* Ensure list item takes full width within slide */
103
+ ::ng-deep .bookings-swiper .swiper-slide ds-mobile-interactive-list-item-booking {
104
+ width: 100%;
105
+ pointer-events: auto;
106
+ }
107
+ `],
108
+ template: `
109
+ <ds-mobile-page-main
110
+ #pageComponent
111
+ [title]="'Bookinger'"
112
+ [avatarInitials]="userService.avatarInitials()"
113
+ [avatarType]="userService.avatarType()"
114
+ (refresh)="handleRefresh($event)">
115
+
116
+ @if (pageComponent.isOffline()) {
117
+ <ds-mobile-offline-banner
118
+ header-notification
119
+ title="Ingen internetforbindelse"
120
+ message="Nogle funktioner kan være utilgængelige">
121
+ </ds-mobile-offline-banner>
122
+ }
123
+
124
+ <!-- "Dine bestillinger" Section with Swiper -->
125
+ <ds-mobile-section
126
+ headline="Dine bestillinger"
127
+ icon="remixCheckboxCircleLine">
128
+ <div class="bookings-swiper-wrapper">
129
+ <ds-mobile-swiper
130
+ #bookingsSwiper
131
+ class="bookings-swiper"
132
+ [slideWidth]="'100%'"
133
+ [gap]="32"
134
+ [pagination]="true"
135
+ [autoHeight]="true"
136
+ [progressiveOpacity]="true"
137
+ [progressiveScale]="true">
138
+ @for (booking of activeBookings(); track booking.id) {
139
+ <div class="swiper-slide">
140
+ <ds-mobile-interactive-list-item-booking
141
+ [thumbnail]="booking.thumbnail"
142
+ [facilityTitle]="booking.facilityTitle"
143
+ [bookingDate]="booking.bookingDate || ''"
144
+ [bookingTime]="booking.bookingTime || ''"
145
+ [align]="'center'"
146
+ [clickable]="true"
147
+ [enableLongPress]="false"
148
+ [showChevron]="false"
149
+ (bookingClick)="openFacilityDetail(booking.id)"
150
+ />
151
+ </div>
152
+ }
153
+ </ds-mobile-swiper>
154
+
155
+ <!-- Navigation buttons (hidden on mobile or when only 1 item) -->
156
+ @if (activeBookings().length > 1) {
157
+ <div class="swiper-nav-buttons">
158
+ <ds-icon-button
159
+ class="swiper-nav-button"
160
+ icon="remixArrowLeftSLine"
161
+ variant="ghost"
162
+ size="sm"
163
+ [disabled]="isFirstSlide()"
164
+ (clicked)="slidePrev()"
165
+ aria-label="Previous booking"
166
+ />
167
+ <ds-icon-button
168
+ class="swiper-nav-button"
169
+ icon="remixArrowRightSLine"
170
+ variant="ghost"
171
+ size="sm"
172
+ [disabled]="isLastSlide()"
173
+ (clicked)="slideNext()"
174
+ aria-label="Next booking"
175
+ />
176
+ </div>
177
+ }
178
+ </div>
179
+ </ds-mobile-section>
180
+
181
+ <!-- Available Facilities Section -->
182
+ <ds-mobile-section headline="Tilgængelige faciliteter" contentGap="0px">
183
+ @for (facility of availableFacilities(); track facility.id) {
184
+ <ds-mobile-interactive-list-item-booking
185
+ [thumbnail]="facility.thumbnail"
186
+ [facilityTitle]="facility.facilityTitle"
187
+ [description]="facility.description"
188
+ [availabilityStatus]="facility.availabilityStatus"
189
+ [statusLabel]="facility.statusLabel || ''"
190
+ [clickable]="true"
191
+ [enableLongPress]="false"
192
+ [showChevron]="false"
193
+ (bookingClick)="openFacilityDetail(facility.id)"
194
+ />
195
+ }
196
+ </ds-mobile-section>
197
+ </ds-mobile-page-main>
198
+
199
+ <!-- FAB for creating new facility -->
200
+ <ds-mobile-fab
201
+ icon="remixAddLine"
202
+ position="bottom-right"
203
+ ariaLabel="Opret facilitet"
204
+ (clicked)="openFacilityCreationModal()">
205
+ </ds-mobile-fab>
206
+ `
207
+ })
208
+ export class MobileBookingPageComponent {
209
+ @ViewChild('pageComponent') pageComponent!: DsMobilePageMainComponent;
210
+ @ViewChild('bookingsSwiper') bookingsSwiper?: DsMobileSwiperComponent;
211
+
212
+ constructor(
213
+ private facilityModal: DsMobileFacilityDetailModalService,
214
+ private facilityCreationModal: DsMobileFacilityCreationModalService,
215
+ public userService: UserService
216
+ ) {}
217
+
218
+ // Active bookings (current and upcoming)
219
+ activeBookings = signal<FacilityDetail[]>([
220
+ {
221
+ id: 'booking-1',
222
+ thumbnail: '/Assets/Dummy-photos/rooftop-party.jpg',
223
+ facilityTitle: 'Festlokale på taget',
224
+ bookingDate: '14. februar, 2026',
225
+ bookingTime: '9:00 - 17:00',
226
+ description: 'Din aktive booking af festlokalet på taget',
227
+ heroImage: '/Assets/Dummy-photos/rooftop-party.jpg',
228
+ fullDescription: '<p>Festlokalet på taget giver jer et lyst og indbydende rum med flot udsigt over byen. Lokalet er velegnet til fødselsdage, mindre sammenkomster og hyggelige middage med naboer og venner.</p>',
229
+ requirements: ['Kræver nøglekort'],
230
+ bookingType: 'Øjeblikkelig booking',
231
+ expectations: '<p>Lokalet er klargjort med borde og stole ved ankomst. Husk at rydde op efter brug, så området er klar til de næste beboere.</p>',
232
+ restrictions: [
233
+ 'Maksimal bookingvarighed: 3 timer',
234
+ 'Ingen høj musik efter kl. 22',
235
+ 'Efterlad lokalet rent og opryddet'
236
+ ]
237
+ }
238
+ ]);
239
+
240
+ // Available facilities for booking
241
+ availableFacilities = signal<FacilityDetail[]>([
242
+ {
243
+ id: 'facility-1',
244
+ thumbnail: '/Assets/Dummy-photos/handyman.jpg',
245
+ facilityTitle: 'Boremaskinen',
246
+ description: 'Lån en boremaskine til mindre gør-det-selv-opgaver i boligen.',
247
+ availabilityStatus: 'available-today',
248
+ statusLabel: 'Ledig i dag',
249
+ heroImage: '/Assets/Dummy-photos/handyman.jpg',
250
+ fullDescription: '<p>Vores boremaskine i professionel kvalitet er tilgængelig for alle beboere til mindre forbedringer i hjemmet. Den er ideel til ophængning af hylder, montering af beslag og andre boreopgaver i lejligheden.</p>',
251
+ requirements: ['Kræver nøglekort'],
252
+ bookingType: 'Øjeblikkelig booking',
253
+ expectations: '<p>Boremaskinen udleveres med et sæt bor og tilbehør. Den er opladet og klar til brug. Returner værktøjet i rengjort stand efter brug.</p>',
254
+ restrictions: [
255
+ 'Maksimal bookingvarighed: 48 timer',
256
+ 'Skal returneres i samme stand',
257
+ 'Skader skal meldes med det samme',
258
+ 'Må ikke bruges til kommercielt arbejde'
259
+ ]
260
+ },
261
+ {
262
+ id: 'facility-2',
263
+ thumbnail: '/Assets/Dummy-photos/rooftop-party.jpg',
264
+ facilityTitle: 'Festlokale på taget',
265
+ description: 'Book det fælles festlokale på taget til fødselsdage, fejring og mindre arrangementer.',
266
+ availabilityStatus: 'available-today',
267
+ statusLabel: 'Ledig i dag',
268
+ heroImage: '/Assets/Dummy-photos/rooftop-party.jpg',
269
+ fullDescription: `
270
+ <p>Tagterrassen er indrettet som et afslappende fristed og et levende samlingspunkt for beboerne med flot udsigt over byen. Uanset om du planlægger en mindre sammenkomst, en rolig aften udendørs eller en hyggelig stund med venner, giver terrassen de perfekte rammer.</p>
271
+
272
+ <h3 class="section-headline">Hvad du kan forvente</h3>
273
+ <p>Terrassen er møbleret med borde, stole og loungeområder, så den egner sig godt til sociale arrangementer, afslappet spisning eller en rolig pause. Sæsonens planter giver en indbydende stemning, og området har belysning til brug om aftenen. Terrassen er ikke en legeplads, og børn skal være under opsyn.</p>
274
+
275
+ <h3 class="section-headline">Restriktioner</h3>
276
+ <ul>
277
+ <li>Rygning og vaping er ikke tilladt på terrassen.</li>
278
+ <li>Høj musik og fester over rimeligt lydniveau er ikke tilladt.</li>
279
+ <li>Åben ild og stearinlys er ikke tilladt af sikkerhedshensyn.</li>
280
+ <li>Private grill eller eget madudstyr må ikke anvendes; brug kun fælles faciliteter.</li>
281
+ <li>Kæledyr er ikke tilladt på terrassen, undtaget servicehunde.</li>
282
+ </ul>
283
+
284
+ <h3 class="section-headline">Sikkerhed og adfærd</h3>
285
+ <p>For alles komfort og sikkerhed beder vi dig:</p>
286
+ <ul>
287
+ <li>Undgå overfyldning; terrassen har plads til maks. 20 personer ad gangen.</li>
288
+ <li>Holde børn under opsyn til enhver tid.</li>
289
+ <li>Undlade at flytte eller fjerne møbler.</li>
290
+ <li>Holde nødudgange og gangarealer fri.</li>
291
+ <li>Bortskaffe affald i de opsatte skraldespande.</li>
292
+ </ul>
293
+
294
+ <h3 class="section-headline">Booking og varighed</h3>
295
+ <p>Terrassen skal bookes på forhånd ved private arrangementer:</p>
296
+ <ul>
297
+ <li>Maksimal varighed: 3 timer pr. booking.</li>
298
+ <li>Oprydning: Beboeren har ansvar for at efterlade terrassen ren og klar til næste booking.</li>
299
+ </ul>
300
+ `,
301
+ requirements: ['Kræver nøglekort'],
302
+ bookingType: 'Øjeblikkelig booking',
303
+ expectations: '',
304
+ restrictions: []
305
+ },
306
+ {
307
+ id: 'facility-3',
308
+ thumbnail: '/Assets/Dummy-photos/parking.jpg',
309
+ facilityTitle: 'Gæsteparkering',
310
+ description: 'Book en gæsteparkeringsplads, så dine besøgende nemt kan parkere ved ejendommen.',
311
+ availabilityStatus: 'available-from',
312
+ statusLabel: 'Ledig fra 28. februar, 2026',
313
+ heroImage: '/Assets/Dummy-photos/parking.jpg',
314
+ fullDescription: '<p>Ekstra gæsteparkeringspladser er tilgængelige for beboere, der har brug for parkering til besøgende. Pladserne giver dine gæster en nem og tryg parkeringsmulighed tæt på boligen.</p>',
315
+ requirements: ['Kræver nøglekort'],
316
+ bookingType: 'Forudgående booking påkrævet',
317
+ expectations: '<p>Parkeringsområdet er sikkert og velholdt. Gæstetilladelse skal være synlig i forruden under hele parkeringen. Informer gerne dine gæster om placering og regler.</p>',
318
+ restrictions: [
319
+ 'Forudgående booking påkrævet (minimum 24 timer)',
320
+ 'Maksimal bookingvarighed: 12 timer',
321
+ 'Gæster skal vise synlig parkeringstilladelse',
322
+ 'Ingen erhvervskøretøjer tilladt'
323
+ ]
324
+ },
325
+ {
326
+ id: 'facility-4',
327
+ thumbnail: '/Assets/Dummy-photos/yard.jpg',
328
+ facilityTitle: 'BBQ område',
329
+ description: 'Book grillområdet til sommerarrangementer og udendørs spisning med naboer og venner.',
330
+ availabilityStatus: 'unavailable',
331
+ statusLabel: 'Ikke tilgængelig',
332
+ heroImage: '/Assets/Dummy-photos/yard.jpg',
333
+ fullDescription: '<p>BBQ-området har grill i professionel kvalitet og udendørs siddepladser, perfekt til sommerarrangementer og fællesspisning. Området er velegnet til både mindre familiemåltider og større sociale arrangementer.</p>',
334
+ requirements: ['Kræver nøglekort'],
335
+ bookingType: 'Sæsonbestemt tilgængelighed',
336
+ expectations: '<p>Alt grilludstyr og rengøringsartikler stilles til rådighed. Området har overdækkede siddepladser og borde til forberedelse. Rengør grillen efter brug, og bortskaf kul korrekt i de anviste beholdere.</p>',
337
+ restrictions: [
338
+ 'Lukket i vintersæsonen',
339
+ 'Åbner igen i maj 2026',
340
+ 'Maksimal gruppestørrelse: 20 personer',
341
+ 'Musik skal stoppe senest kl. 22'
342
+ ]
343
+ }
344
+ ]);
345
+
346
+ handleRefresh(event: any): void {
347
+ console.log('Pull-to-refresh triggered');
348
+
349
+ // Check if offline and complete immediately
350
+ if (this.pageComponent?.isOffline()) {
351
+ console.log('Cannot refresh while offline');
352
+ event.target.complete();
353
+ return;
354
+ }
355
+
356
+ // Simulate data refresh
357
+ setTimeout(() => {
358
+ console.log('Refresh complete');
359
+ event.target.complete();
360
+ }, 1000);
361
+ }
362
+
363
+ /**
364
+ * Navigate to previous slide
365
+ */
366
+ slidePrev(): void {
367
+ this.bookingsSwiper?.slidePrev();
368
+ }
369
+
370
+ /**
371
+ * Navigate to next slide
372
+ */
373
+ slideNext(): void {
374
+ this.bookingsSwiper?.slideNext();
375
+ }
376
+
377
+ /**
378
+ * Check if at first slide
379
+ */
380
+ isFirstSlide(): boolean {
381
+ return this.bookingsSwiper?.isBeginning() ?? true;
382
+ }
383
+
384
+ /**
385
+ * Check if at last slide
386
+ */
387
+ isLastSlide(): boolean {
388
+ return this.bookingsSwiper?.isEnd() ?? true;
389
+ }
390
+
391
+ /**
392
+ * Open facility detail modal
393
+ */
394
+ async openFacilityDetail(facilityId: string): Promise<void> {
395
+ // Find facility in either active bookings or available facilities
396
+ const allFacilities = [...this.activeBookings(), ...this.availableFacilities()];
397
+ const facility = allFacilities.find(f => f.id === facilityId);
398
+
399
+ if (facility) {
400
+ await this.facilityModal.open({
401
+ id: facility.id,
402
+ facilityTitle: facility.facilityTitle,
403
+ heroImage: facility.heroImage || facility.thumbnail,
404
+ fullDescription: facility.fullDescription,
405
+ requirements: facility.requirements,
406
+ bookingType: facility.bookingType,
407
+ expectations: facility.expectations,
408
+ restrictions: facility.restrictions,
409
+ availabilityStatus: facility.availabilityStatus,
410
+ statusLabel: facility.statusLabel,
411
+ bookingDate: facility.bookingDate,
412
+ bookingTime: facility.bookingTime
413
+ });
414
+ }
415
+ }
416
+
417
+ /**
418
+ * Open facility creation modal
419
+ */
420
+ async openFacilityCreationModal(): Promise<void> {
421
+ console.log('[BookingPage] FAB clicked, opening facility creation modal...');
422
+
423
+ await this.facilityCreationModal.open({
424
+ onSubmit: async (data) => {
425
+ console.log('[BookingPage] New facility created:', data);
426
+ // In a real app, call your API to create the facility
427
+ // await this.facilityService.createFacility(data);
428
+
429
+ // Optionally add the new facility to the available facilities list
430
+ // This is just for demo - in reality you'd refetch from the API
431
+ }
432
+ });
433
+ }
434
+ }