@propbinder/mobile-design 0.2.50 → 0.2.53

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (221) hide show
  1. package/fesm2022/propbinder-mobile-design.mjs +26206 -0
  2. package/fesm2022/propbinder-mobile-design.mjs.map +1 -0
  3. package/index.d.ts +8193 -0
  4. package/package.json +39 -3
  5. package/ng-package.json +0 -24
  6. package/src/animations/page-transitions.ts +0 -165
  7. package/src/components/action-list-item/ds-mobile-action-list-item.ts +0 -102
  8. package/src/components/action-list-item/index.ts +0 -2
  9. package/src/components/app-icon/ds-app-icon.ts +0 -133
  10. package/src/components/app-icon/index.ts +0 -2
  11. package/src/components/attachment-preview/ds-mobile-attachment-preview.css +0 -139
  12. package/src/components/attachment-preview/ds-mobile-attachment-preview.ts +0 -164
  13. package/src/components/attachment-preview/index.ts +0 -1
  14. package/src/components/avatar-with-badge/ds-avatar-with-badge.ts +0 -142
  15. package/src/components/avatar-with-badge/index.ts +0 -2
  16. package/src/components/booking-modal/ds-mobile-booking-confirmation-wrapper.ts +0 -71
  17. package/src/components/booking-modal/ds-mobile-booking-modal.service.ts +0 -121
  18. package/src/components/booking-modal/ds-mobile-booking-modal.ts +0 -598
  19. package/src/components/booking-modal/ds-mobile-booking-summary.ts +0 -161
  20. package/src/components/booking-modal/index.ts +0 -4
  21. package/src/components/bottom-sheet/ds-mobile-actions-bottom-sheet.ts +0 -266
  22. package/src/components/bottom-sheet/ds-mobile-bottom-sheet-header.ts +0 -146
  23. package/src/components/bottom-sheet/ds-mobile-bottom-sheet-wrapper.ts +0 -156
  24. package/src/components/bottom-sheet/ds-mobile-bottom-sheet.css +0 -101
  25. package/src/components/bottom-sheet/ds-mobile-bottom-sheet.service.ts +0 -169
  26. package/src/components/bottom-sheet/ds-mobile-confirmation-sheet.ts +0 -211
  27. package/src/components/bottom-sheet/ds-mobile-post-create-bottom-sheet.ts +0 -578
  28. package/src/components/bottom-sheet/ds-mobile-profile-actions-sheet.ts +0 -614
  29. package/src/components/bottom-sheet/index.ts +0 -8
  30. package/src/components/bottom-sheet/modal-shadow-fix.ts +0 -42
  31. package/src/components/card-inline/ds-mobile-card-inline.ts +0 -301
  32. package/src/components/card-inline/index.ts +0 -2
  33. package/src/components/card-inline-banner/ds-mobile-card-inline-banner.ts +0 -118
  34. package/src/components/card-inline-banner/index.ts +0 -1
  35. package/src/components/card-inline-contact/ds-mobile-card-inline-contact.ts +0 -120
  36. package/src/components/card-inline-contact/index.ts +0 -1
  37. package/src/components/card-inline-file/ds-mobile-card-inline-file.ts +0 -141
  38. package/src/components/card-inline-file/index.ts +0 -1
  39. package/src/components/chat-modal/ds-mobile-chat-modal.css +0 -159
  40. package/src/components/chat-modal/ds-mobile-chat-modal.service.ts +0 -105
  41. package/src/components/chat-modal/ds-mobile-chat-modal.ts +0 -918
  42. package/src/components/chat-modal/index.ts +0 -8
  43. package/src/components/comment/ds-mobile-comment.ts +0 -568
  44. package/src/components/comment/index.ts +0 -2
  45. package/src/components/contact-list-item/ds-mobile-contact-list-item.ts +0 -182
  46. package/src/components/contact-list-item/index.ts +0 -2
  47. package/src/components/content/ds-mobile-content.ts +0 -139
  48. package/src/components/content/index.ts +0 -2
  49. package/src/components/dropdown/ds-mobile-dropdown.css +0 -199
  50. package/src/components/dropdown/ds-mobile-dropdown.ts +0 -340
  51. package/src/components/dropdown/index.ts +0 -2
  52. package/src/components/ds-mobile-tabs.css +0 -407
  53. package/src/components/ds-mobile-tabs.ts +0 -216
  54. package/src/components/empty-state/ds-mobile-empty-state.ts +0 -120
  55. package/src/components/empty-state/index.ts +0 -2
  56. package/src/components/fab/ds-mobile-fab.ts +0 -315
  57. package/src/components/fab/index.ts +0 -1
  58. package/src/components/facility-creation-modal/ds-mobile-facility-creation-confirmation-wrapper.ts +0 -121
  59. package/src/components/facility-creation-modal/ds-mobile-facility-creation-modal.css +0 -189
  60. package/src/components/facility-creation-modal/ds-mobile-facility-creation-modal.service.ts +0 -135
  61. package/src/components/facility-creation-modal/ds-mobile-facility-creation-modal.ts +0 -656
  62. package/src/components/facility-creation-modal/index.ts +0 -9
  63. package/src/components/facility-creation-modal/sheets/ds-mobile-access-sheet.ts +0 -105
  64. package/src/components/facility-creation-modal/sheets/ds-mobile-price-sheet.ts +0 -188
  65. package/src/components/facility-creation-modal/sheets/ds-mobile-when-can-book-sheet.ts +0 -460
  66. package/src/components/facility-creation-modal/sheets/ds-mobile-who-can-book-sheet.ts +0 -134
  67. package/src/components/facility-detail-modal/ds-mobile-facility-detail-modal.service.ts +0 -69
  68. package/src/components/facility-detail-modal/ds-mobile-facility-detail-modal.ts +0 -379
  69. package/src/components/facility-detail-modal/index.ts +0 -2
  70. package/src/components/file-attachment/ds-mobile-file-attachment.ts +0 -164
  71. package/src/components/file-attachment/index.ts +0 -2
  72. package/src/components/handbook-detail-modal/ds-mobile-handbook-detail-modal.css +0 -214
  73. package/src/components/handbook-detail-modal/ds-mobile-handbook-detail-modal.service.ts +0 -84
  74. package/src/components/handbook-detail-modal/ds-mobile-handbook-detail-modal.ts +0 -424
  75. package/src/components/handbook-detail-modal/index.ts +0 -3
  76. package/src/components/handbook-folder/ds-mobile-handbook-folder-mini.ts +0 -175
  77. package/src/components/handbook-folder/ds-mobile-handbook-folder.ts +0 -533
  78. package/src/components/handbook-folder/index.ts +0 -4
  79. package/src/components/header-content/ds-mobile-header-content.ts +0 -222
  80. package/src/components/header-content/index.ts +0 -2
  81. package/src/components/illustration/ds-mobile-illustration.ts +0 -124
  82. package/src/components/illustration/index.ts +0 -2
  83. package/src/components/index.ts +0 -124
  84. package/src/components/inline-photo/ds-mobile-inline-photo.ts +0 -361
  85. package/src/components/inline-photo/index.ts +0 -1
  86. package/src/components/inline-tabs/ds-mobile-inline-tabs.ts +0 -132
  87. package/src/components/inline-tabs/index.ts +0 -2
  88. package/src/components/interactive-list-item-booking/ds-mobile-interactive-list-item-booking.ts +0 -350
  89. package/src/components/interactive-list-item-booking/index.ts +0 -1
  90. package/src/components/interactive-list-item-inquiry/ds-mobile-interactive-list-item-inquiry.ts +0 -321
  91. package/src/components/interactive-list-item-inquiry/index.ts +0 -2
  92. package/src/components/interactive-list-item-message/ds-mobile-interactive-list-item-message.ts +0 -237
  93. package/src/components/interactive-list-item-message/index.ts +0 -2
  94. package/src/components/interactive-list-item-post/ds-mobile-interactive-list-item-post.ts +0 -549
  95. package/src/components/interactive-list-item-post/ds-mobile-post-pdf-attachment.ts +0 -124
  96. package/src/components/interactive-list-item-post/index.ts +0 -13
  97. package/src/components/lightbox/ds-mobile-lightbox-footer.ts +0 -315
  98. package/src/components/lightbox/ds-mobile-lightbox-header.ts +0 -202
  99. package/src/components/lightbox/ds-mobile-lightbox-image.ts +0 -484
  100. package/src/components/lightbox/ds-mobile-lightbox-pdf.css +0 -377
  101. package/src/components/lightbox/ds-mobile-lightbox-pdf.ts +0 -374
  102. package/src/components/lightbox/ds-mobile-lightbox.css +0 -587
  103. package/src/components/lightbox/ds-mobile-lightbox.service.ts +0 -296
  104. package/src/components/lightbox/ds-mobile-lightbox.ts +0 -529
  105. package/src/components/lightbox/index.ts +0 -22
  106. package/src/components/list-item/ds-mobile-list-item.ts +0 -603
  107. package/src/components/list-item/index.ts +0 -2
  108. package/src/components/list-item-static/ds-mobile-list-item-static.ts +0 -133
  109. package/src/components/list-item-static/index.ts +0 -2
  110. package/src/components/loader-overlay/ds-mobile-loader-overlay.css +0 -49
  111. package/src/components/loader-overlay/ds-mobile-loader-overlay.ts +0 -77
  112. package/src/components/loader-overlay/index.ts +0 -1
  113. package/src/components/logo/ds-logo.ts +0 -95
  114. package/src/components/logo/index.ts +0 -2
  115. package/src/components/message-bubble/ds-mobile-message-bubble.ts +0 -633
  116. package/src/components/message-bubble/index.ts +0 -7
  117. package/src/components/message-composer/ds-mobile-message-composer.ts +0 -1146
  118. package/src/components/message-composer/index.ts +0 -7
  119. package/src/components/modal/ds-mobile-modal.css +0 -163
  120. package/src/components/modal/ds-mobile-modal.service.ts +0 -329
  121. package/src/components/modal/index.ts +0 -8
  122. package/src/components/modal-base/ds-mobile-modal-base.css +0 -378
  123. package/src/components/modal-base/ds-mobile-modal-base.ts +0 -261
  124. package/src/components/modal-base/index.ts +0 -2
  125. package/src/components/new-inquiry-modal/ds-mobile-new-inquiry-modal.css +0 -112
  126. package/src/components/new-inquiry-modal/ds-mobile-new-inquiry-modal.service.ts +0 -93
  127. package/src/components/new-inquiry-modal/ds-mobile-new-inquiry-modal.ts +0 -442
  128. package/src/components/new-inquiry-modal/index.ts +0 -4
  129. package/src/components/offline-banner/ds-mobile-offline-banner.ts +0 -135
  130. package/src/components/offline-banner/index.ts +0 -1
  131. package/src/components/page-details/ds-mobile-page-details.css +0 -83
  132. package/src/components/page-details/ds-mobile-page-details.ts +0 -282
  133. package/src/components/page-details/index.ts +0 -2
  134. package/src/components/page-main/ds-mobile-page-main.css +0 -68
  135. package/src/components/page-main/ds-mobile-page-main.ts +0 -421
  136. package/src/components/page-main/index.ts +0 -2
  137. package/src/components/post-composer/ds-mobile-post-composer.ts +0 -140
  138. package/src/components/post-composer/index.ts +0 -2
  139. package/src/components/post-detail-modal/ds-mobile-post-detail-modal.css +0 -390
  140. package/src/components/post-detail-modal/ds-mobile-post-detail-modal.service.ts +0 -108
  141. package/src/components/post-detail-modal/ds-mobile-post-detail-modal.ts +0 -722
  142. package/src/components/post-detail-modal/index.ts +0 -9
  143. package/src/components/property-banner/ds-mobile-property-banner.ts +0 -95
  144. package/src/components/property-banner/index.ts +0 -2
  145. package/src/components/section/ds-mobile-section.ts +0 -263
  146. package/src/components/section/index.ts +0 -2
  147. package/src/components/shared/directives/index.ts +0 -2
  148. package/src/components/shared/directives/long-press.directive.ts +0 -212
  149. package/src/components/shared/index.ts +0 -3
  150. package/src/components/shared/mobile-modal-base.ts +0 -457
  151. package/src/components/shared/mobile-page-base.ts +0 -204
  152. package/src/components/swiper/ds-mobile-swiper-with-nav.ts +0 -160
  153. package/src/components/swiper/ds-mobile-swiper.ts +0 -327
  154. package/src/components/swiper/index.ts +0 -3
  155. package/src/components/system-message-banner/ds-mobile-system-message-banner.ts +0 -129
  156. package/src/components/system-message-banner/index.ts +0 -2
  157. package/src/components/tab-bar/ds-mobile-tab-bar.css +0 -533
  158. package/src/components/tab-bar/ds-mobile-tab-bar.ts +0 -735
  159. package/src/components/tab-bar/index.ts +0 -2
  160. package/src/components/tabs/ds-mobile-tabs.css +0 -25
  161. package/src/components/tabs/ds-mobile-tabs.ts +0 -89
  162. package/src/components/tabs/index.ts +0 -2
  163. package/src/components/text-input/ds-text-input.ts +0 -287
  164. package/src/components/text-input/index.ts +0 -2
  165. package/src/examples/booking.page.ts +0 -434
  166. package/src/examples/community.page.ts +0 -776
  167. package/src/examples/handbook.page.ts +0 -324
  168. package/src/examples/home.page.ts +0 -347
  169. package/src/examples/index.ts +0 -12
  170. package/src/examples/inquiries.example.ts +0 -273
  171. package/src/examples/inquiry-detail.example.css +0 -189
  172. package/src/examples/inquiry-detail.example.ts +0 -415
  173. package/src/examples/mobile-tabs-example.component.ts +0 -208
  174. package/src/examples/post-create.page.ts +0 -311
  175. package/src/examples/post-detail.page.ts +0 -296
  176. package/src/examples/sign-in.page.ts +0 -291
  177. package/src/examples/whitelabel-demo-modal.component.ts +0 -1094
  178. package/src/examples/whitelabel-demo-modal.service.ts +0 -77
  179. package/src/models/index.ts +0 -7
  180. package/src/models/post.model.ts +0 -41
  181. package/src/pages/community.page.ts +0 -769
  182. package/src/pages/handbook.page.ts +0 -388
  183. package/src/pages/home.page.ts +0 -303
  184. package/src/pages/index.ts +0 -11
  185. package/src/pages/inquiries.example.ts +0 -273
  186. package/src/pages/inquiry-detail.example.css +0 -189
  187. package/src/pages/inquiry-detail.example.ts +0 -415
  188. package/src/pages/mobile-tabs-example.component.ts +0 -179
  189. package/src/pages/post-create.page.ts +0 -311
  190. package/src/pages/post-detail.page.ts +0 -296
  191. package/src/pages/sign-in.page.ts +0 -291
  192. package/src/pages/whitelabel-demo-modal.component.ts +0 -1094
  193. package/src/pages/whitelabel-demo-modal.service.ts +0 -77
  194. package/src/public-api.ts +0 -6
  195. package/src/services/base-modal.service.ts +0 -101
  196. package/src/services/index.ts +0 -11
  197. package/src/services/posts.service.ts +0 -542
  198. package/src/services/tracking-permission.service.ts +0 -88
  199. package/src/services/user.service.ts +0 -60
  200. package/src/services/whitelabel.service.ts +0 -675
  201. package/tsconfig.lib.json +0 -17
  202. package/tsconfig.lib.prod.json +0 -9
  203. package/tsconfig.spec.json +0 -13
  204. /package/{src/assets → assets}/fonts/Brockmann-Bold.otf +0 -0
  205. /package/{src/assets → assets}/fonts/Brockmann-BoldItalic.otf +0 -0
  206. /package/{src/assets → assets}/fonts/Brockmann-Medium.otf +0 -0
  207. /package/{src/assets → assets}/fonts/Brockmann-MediumItalic.otf +0 -0
  208. /package/{src/assets → assets}/fonts/Brockmann-Regular.otf +0 -0
  209. /package/{src/assets → assets}/fonts/Brockmann-RegularItalic.otf +0 -0
  210. /package/{src/assets → assets}/fonts/Brockmann-SemiBold.otf +0 -0
  211. /package/{src/assets → assets}/fonts/Brockmann-SemiBoldItalic.otf +0 -0
  212. /package/{src/assets → assets}/fonts/Brockmann_desktop_license.pdf +0 -0
  213. /package/{src/assets → assets}/fonts/brockmann-medium-webfont.woff2 +0 -0
  214. /package/{src/assets → assets}/fonts/brockmann-mediumitalic-webfont.woff2 +0 -0
  215. /package/{src/assets → assets}/fonts/brockmann-regular-webfont.woff2 +0 -0
  216. /package/{src/assets → assets}/fonts/brockmann-regularitalic-webfont.woff2 +0 -0
  217. /package/{src/assets → assets}/fonts/brockmann-semibold-webfont.woff2 +0 -0
  218. /package/{src/assets → assets}/fonts/brockmann-semibolditalic-webfont.woff2 +0 -0
  219. /package/{src/styles → styles}/ionic.css +0 -0
  220. /package/{src/components/shared → styles}/mobile-common.css +0 -0
  221. /package/{src/components/shared → styles}/mobile-page-base.css +0 -0
@@ -1,656 +0,0 @@
1
- import { Component, signal, Input, ViewChild, ElementRef, OnInit, AfterViewInit, CUSTOM_ELEMENTS_SCHEMA, inject } from '@angular/core';
2
- import { CommonModule } from '@angular/common';
3
- import { FormsModule } from '@angular/forms';
4
- import { ModalController } from '@ionic/angular/standalone';
5
- import { Capacitor } from '@capacitor/core';
6
- import { FilePicker } from '@capawesome/capacitor-file-picker';
7
- import { DsButtonComponent, DsTextareaComponent, DsIconComponent, DsIconButtonComponent } from '@propbinder/design-system';
8
- import { DsMobileModalBaseComponent } from '../modal-base/ds-mobile-modal-base';
9
- import { DsMobileSectionComponent } from '../section';
10
- import { DsMobileListItemComponent } from '../list-item';
11
- import { DsMobileBottomSheetService } from '../bottom-sheet';
12
- import { DsMobileAttachmentPreviewComponent, type AttachmentData, type AttachmentFileType } from '../attachment-preview';
13
-
14
- /**
15
- * New facility form data
16
- */
17
- export interface NewFacilityData {
18
- title: string;
19
- description: string;
20
- whoCanBook: string;
21
- whenCanBook: string;
22
- price: string;
23
- accessRequirements: string;
24
- attachments: AttachmentData[];
25
- }
26
-
27
- /**
28
- * DsMobileFacilityCreationModalComponent
29
- *
30
- * Modal component for creating new facilities.
31
- * Uses ds-mobile-modal-base for consistent layout and behavior.
32
- *
33
- * Features:
34
- * - Title and description fields
35
- * - Interactive list items for facility options
36
- * - Bottom sheet pickers for selections
37
- * - Photo upload with preview
38
- * - Form validation
39
- *
40
- * This component is typically not used directly - use DsMobileFacilityCreationModalService instead.
41
- */
42
- @Component({
43
- selector: 'ds-mobile-facility-creation-modal',
44
- standalone: true,
45
- imports: [
46
- CommonModule,
47
- FormsModule,
48
- DsButtonComponent,
49
- DsTextareaComponent,
50
- DsIconComponent,
51
- DsIconButtonComponent,
52
- DsMobileModalBaseComponent,
53
- DsMobileSectionComponent,
54
- DsMobileListItemComponent,
55
- DsMobileAttachmentPreviewComponent,
56
- ],
57
- styleUrls: ['../shared/mobile-common.css', './ds-mobile-facility-creation-modal.css'],
58
- schemas: [CUSTOM_ELEMENTS_SCHEMA],
59
- template: `
60
- <ds-mobile-modal-base
61
- [loading]="loading"
62
- [error]="error"
63
- [showHeader]="false"
64
- [hasFixedBottom]="true"
65
- [enableKeyboardHandling]="true"
66
- [keyboardContentBehavior]="'overlay'"
67
- closeButtonLabel="Close"
68
- >
69
- <!-- Form Content -->
70
- <ds-mobile-section class="form-section">
71
- <!-- Title Field (Large Ghost Textarea) -->
72
- <ds-textarea
73
- #titleInput
74
- [(ngModel)]="title"
75
- [ghost]="true"
76
- [required]="true"
77
- [rows]="1"
78
- [placeholder]="titlePlaceholder"
79
- class="inquiry-title-input ghost-input-clean"
80
- (valueChange)="handleTitleChange($event)"
81
- />
82
-
83
- <!-- Description Field (Ghost Textarea) -->
84
- <ds-textarea
85
- #descriptionInput
86
- [(ngModel)]="description"
87
- [ghost]="true"
88
- [rows]="1"
89
- [placeholder]="descriptionPlaceholder"
90
- class="inquiry-description-input ghost-input-clean"
91
- (valueChange)="handleDescriptionChange($event)"
92
- />
93
- </ds-mobile-section>
94
-
95
- <!-- List Items Section -->
96
- <ds-mobile-section [contentGap]="'0'">
97
- <!-- Who can book - hidden until Propbinder API supports this field -->
98
- <!-- <ds-mobile-list-item
99
- [leadingSize]="'32px'"
100
- [showDivider]="true"
101
- [interactive]="true"
102
- [showDesktopMoreButton]="false"
103
- [align]="'center'"
104
- (itemClick)="openWhoSheet()">
105
- <ds-icon content-leading name="remixGroupLine" size="20px" color="tertiary" />
106
- <div content-main>
107
- <div class="detail-label">Hvem kan booke</div>
108
- <div class="detail-value">{{ whoCanBook() }}</div>
109
- </div>
110
- <ds-icon content-trailing name="remixArrowRightSLine" size="20px" color="tertiary" />
111
- </ds-mobile-list-item> -->
112
-
113
- <!-- When can it be booked -->
114
- <ds-mobile-list-item
115
- [leadingSize]="'32px'"
116
- [showDivider]="true"
117
- [interactive]="true"
118
- [showDesktopMoreButton]="false"
119
- [align]="'center'"
120
- (itemClick)="openWhenSheet()">
121
- <ds-icon content-leading name="remixCalendarLine" size="20px" color="tertiary" />
122
- <div content-main>
123
- <div class="detail-label">Hvornår kan det bookes</div>
124
- <div class="detail-value">{{ whenCanBook() }}</div>
125
- </div>
126
- <ds-icon content-trailing name="remixArrowRightSLine" size="20px" color="tertiary" />
127
- </ds-mobile-list-item>
128
-
129
- <!-- Price -->
130
- <ds-mobile-list-item
131
- [leadingSize]="'32px'"
132
- [showDivider]="false"
133
- [interactive]="true"
134
- [showDesktopMoreButton]="false"
135
- [align]="'center'"
136
- (itemClick)="openPriceSheet()">
137
- <ds-icon content-leading name="remixPriceTag3Line" size="20px" color="tertiary" />
138
- <div content-main>
139
- <div class="detail-label">Pris</div>
140
- <div class="detail-value">{{ price() }}</div>
141
- </div>
142
- <ds-icon content-trailing name="remixArrowRightSLine" size="20px" color="tertiary" />
143
- </ds-mobile-list-item>
144
-
145
- <!-- Access requirements - hidden until Propbinder API supports this field -->
146
- <!-- <ds-mobile-list-item
147
- [leadingSize]="'32px'"
148
- [showDivider]="false"
149
- [interactive]="true"
150
- [showDesktopMoreButton]="false"
151
- [align]="'center'"
152
- (itemClick)="openAccessSheet()">
153
- <ds-icon content-leading name="remixKeyLine" size="20px" color="tertiary" />
154
- <div content-main>
155
- <div class="detail-label">Adgangskrav</div>
156
- <div class="detail-value">{{ accessRequirements() }}</div>
157
- </div>
158
- <ds-icon content-trailing name="remixArrowRightSLine" size="20px" color="tertiary" />
159
- </ds-mobile-list-item> -->
160
- </ds-mobile-section>
161
-
162
- <!-- Fixed Bottom Container (Slides with keyboard) -->
163
- <div fixed-bottom class="fixed-bottom-container">
164
- <!-- Attachment Previews (if any) -->
165
- @if (attachments().length > 0) {
166
- <div class="attachment-previews-section">
167
- <div class="image-previews">
168
- @for (attachment of attachments(); track attachment.id) {
169
- <ds-mobile-attachment-preview [attachment]="attachment" (remove)="removeAttachment($event)" />
170
- }
171
- </div>
172
- </div>
173
- }
174
-
175
- <!-- Submit Actions Container -->
176
- <div class="submit-container">
177
- <div class="submit-content">
178
- <!-- Upload Actions (Left) -->
179
- <div class="upload-actions">
180
- <ds-icon-button icon="remixImageLine" variant="secondary" size="md" (clicked)="addPhoto()" [disabled]="attachments().length >= 6" aria-label="Add photo">
181
- </ds-icon-button>
182
- <ds-icon-button
183
- icon="remixAttachmentLine"
184
- variant="secondary"
185
- size="md"
186
- (clicked)="handleAddAttachment()"
187
- [disabled]="attachments().length >= 6"
188
- aria-label="Add attachment"
189
- >
190
- </ds-icon-button>
191
-
192
- <!-- Hidden file input for file selection -->
193
- <input #fileInput type="file" accept="*/*" multiple (change)="handleFileSelect($event)" style="display: none;" aria-hidden="true" />
194
- </div>
195
-
196
- <!-- Submit Button (Right) -->
197
- <ds-button class="submit-action-button" variant="primary" size="sm" [disabled]="!isFormValid() || isSubmitting()" (clicked)="handleSubmit()">
198
- {{ submitButtonLabel }}
199
- </ds-button>
200
- </div>
201
- </div>
202
- </div>
203
- </ds-mobile-modal-base>
204
- `
205
- })
206
- export class DsMobileFacilityCreationModalComponent implements OnInit, AfterViewInit {
207
- private modalController = inject(ModalController);
208
- private bottomSheetService = inject(DsMobileBottomSheetService);
209
-
210
- @ViewChild('titleInput', { read: ElementRef }) titleInputRef?: ElementRef<HTMLElement>;
211
- @ViewChild('descriptionInput', { read: ElementRef }) descriptionInputRef?: ElementRef<HTMLElement>;
212
- @ViewChild('titleInput') titleInput?: DsTextareaComponent;
213
- @ViewChild('fileInput') fileInput?: ElementRef<HTMLInputElement>;
214
-
215
- /**
216
- * Loading state for the modal
217
- */
218
- @Input() loading: boolean = false;
219
-
220
- /**
221
- * Error message to display
222
- */
223
- @Input() error?: string;
224
-
225
- /**
226
- * Callback function when form is submitted
227
- */
228
- @Input() onSubmit?: (data: NewFacilityData) => void | Promise<void>;
229
-
230
- /**
231
- * Placeholder for the title field
232
- */
233
- @Input() titlePlaceholder: string = 'Festlokale på tal';
234
-
235
- /**
236
- * Placeholder for the description field
237
- */
238
- @Input() descriptionPlaceholder: string = 'Beskriv din booking så detaljeret som muligt...';
239
-
240
- /**
241
- * Label for the submit button
242
- */
243
- @Input() submitButtonLabel: string = 'Opret';
244
-
245
- /**
246
- * Form title field
247
- */
248
- title = '';
249
-
250
- /**
251
- * Form description field
252
- */
253
- description = '';
254
-
255
- /**
256
- * Attachments array
257
- */
258
- attachments = signal<AttachmentData[]>([]);
259
-
260
- /**
261
- * Who can book signal
262
- */
263
- whoCanBook = signal<string>('Alle');
264
-
265
- /**
266
- * When can it be booked signal
267
- */
268
- whenCanBook = signal<string>('I weekenden, 09:00 til 17:30');
269
-
270
- /**
271
- * Price signal
272
- */
273
- price = signal<string>('Gratis');
274
-
275
- /**
276
- * Access requirements signal
277
- */
278
- accessRequirements = signal<string>('Ingen adgangskrav');
279
-
280
- /**
281
- * Form validation state
282
- */
283
- isFormValid = signal<boolean>(false);
284
-
285
- /**
286
- * Submitting state
287
- */
288
- isSubmitting = signal<boolean>(false);
289
-
290
- ngOnInit(): void {
291
- console.log('[FacilityCreationModal] Component initialized');
292
- }
293
-
294
- ngAfterViewInit(): void {
295
- // Setup auto-resize for title textarea
296
- setTimeout(() => {
297
- this.autoResizeTitleTextarea();
298
- this.autoResizeDescriptionTextarea();
299
-
300
- // Focus the title textarea after view initialization to trigger keyboard on iOS
301
- if (this.titleInputRef) {
302
- const textareaElement = this.titleInputRef.nativeElement.querySelector('textarea');
303
- if (textareaElement) {
304
- textareaElement.focus();
305
- }
306
- }
307
- }, 300);
308
- }
309
-
310
- /**
311
- * Auto-resize the title textarea based on content
312
- */
313
- private autoResizeTitleTextarea(): void {
314
- if (!this.titleInputRef) return;
315
-
316
- // Access the native textarea element
317
- const textareaElement = this.titleInputRef.nativeElement.querySelector('textarea');
318
- if (textareaElement) {
319
- textareaElement.style.height = 'auto';
320
- textareaElement.style.height = textareaElement.scrollHeight + 'px';
321
- }
322
- }
323
-
324
- /**
325
- * Auto-resize the description textarea based on content
326
- */
327
- private autoResizeDescriptionTextarea(): void {
328
- if (!this.descriptionInputRef) return;
329
-
330
- const textareaElement = this.descriptionInputRef.nativeElement.querySelector('textarea');
331
- if (textareaElement) {
332
- textareaElement.style.height = 'auto';
333
- textareaElement.style.height = textareaElement.scrollHeight + 'px';
334
- }
335
- }
336
-
337
- /**
338
- * Handle title change with auto-resize
339
- */
340
- handleTitleChange(value: string): void {
341
- this.validateForm();
342
- this.autoResizeTitleTextarea();
343
- }
344
-
345
- /**
346
- * Handle description change with auto-resize
347
- */
348
- handleDescriptionChange(value: string): void {
349
- this.validateForm();
350
- this.autoResizeDescriptionTextarea();
351
- }
352
-
353
- /**
354
- * Validate form fields
355
- */
356
- validateForm(): void {
357
- const isValid = this.title.trim().length > 0 && this.description.trim().length > 0;
358
- this.isFormValid.set(isValid);
359
- }
360
-
361
- /**
362
- * Open who can book sheet
363
- */
364
- async openWhoSheet(): Promise<void> {
365
- console.log('[FacilityCreationModal] Opening who can book sheet');
366
- const { DsMobileWhoCanBookSheetComponent } = await import('./sheets/ds-mobile-who-can-book-sheet');
367
-
368
- const modal = await this.bottomSheetService.create({
369
- component: DsMobileWhoCanBookSheetComponent,
370
- componentProps: {},
371
- breakpoints: [0, 1],
372
- initialBreakpoint: 1,
373
- handle: true,
374
- cssClass: ['ds-bottom-sheet', 'auto-height']
375
- });
376
-
377
- const result = await modal.onWillDismiss();
378
- if (result?.data?.value) {
379
- // value is now an array of selected community IDs
380
- const selectedIds = result.data.value as string[];
381
-
382
- // If all non-"alle" options are selected, just display "Alle"
383
- const allCommunities = ['faelleskab-a', 'faelleskab-b', 'faelleskab-c'];
384
- const allCommunitiesSelected = allCommunities.every(id => selectedIds.includes(id));
385
-
386
- if (allCommunitiesSelected || selectedIds.includes('alle')) {
387
- this.whoCanBook.set('Alle');
388
- } else {
389
- // Otherwise, show individual labels
390
- const labels = selectedIds
391
- .filter(id => id !== 'alle') // Exclude "alle" from individual display
392
- .map((id: string) => {
393
- // Convert IDs to display labels
394
- if (id === 'faelleskab-a') return 'Fælleskab A';
395
- if (id === 'faelleskab-b') return 'Fælleskab B';
396
- if (id === 'faelleskab-c') return 'Fælleskab C';
397
- return id;
398
- });
399
- this.whoCanBook.set(labels.join(', '));
400
- }
401
- }
402
- }
403
-
404
- /**
405
- * Open when can it be booked sheet
406
- */
407
- async openWhenSheet(): Promise<void> {
408
- console.log('[FacilityCreationModal] Opening when sheet');
409
- const { DsMobileWhenCanBookSheetComponent } = await import('./sheets/ds-mobile-when-can-book-sheet');
410
-
411
- const modal = await this.bottomSheetService.create({
412
- component: DsMobileWhenCanBookSheetComponent,
413
- componentProps: {},
414
- breakpoints: [0, 1],
415
- initialBreakpoint: 1,
416
- handle: true,
417
- cssClass: ['ds-bottom-sheet', 'auto-height']
418
- });
419
-
420
- const result = await modal.onWillDismiss();
421
- if (result?.data?.value) {
422
- // value is now an object with days, timeRange, duration
423
- const { days, timeRange, duration } = result.data.value;
424
- const dayStr = days.join(', ');
425
- const timeStr = `${timeRange.start} til ${timeRange.end}`;
426
- this.whenCanBook.set(`${dayStr}, ${timeStr}, ${duration}`);
427
- }
428
- }
429
-
430
- /**
431
- * Open price sheet
432
- */
433
- async openPriceSheet(): Promise<void> {
434
- console.log('[FacilityCreationModal] Opening price sheet');
435
- const { DsMobilePriceSheetComponent } = await import('./sheets/ds-mobile-price-sheet');
436
-
437
- const modal = await this.bottomSheetService.create({
438
- component: DsMobilePriceSheetComponent,
439
- componentProps: {},
440
- breakpoints: [0, 1],
441
- initialBreakpoint: 1,
442
- handle: true,
443
- cssClass: ['ds-bottom-sheet', 'auto-height']
444
- });
445
-
446
- const result = await modal.onWillDismiss();
447
- if (result?.data?.value) {
448
- this.price.set(result.data.value);
449
- }
450
- }
451
-
452
- /**
453
- * Open access requirements sheet
454
- */
455
- async openAccessSheet(): Promise<void> {
456
- console.log('[FacilityCreationModal] Opening access sheet');
457
- const { DsMobileAccessSheetComponent } = await import('./sheets/ds-mobile-access-sheet');
458
-
459
- const modal = await this.bottomSheetService.create({
460
- component: DsMobileAccessSheetComponent,
461
- componentProps: {},
462
- breakpoints: [0, 1],
463
- initialBreakpoint: 1,
464
- handle: true,
465
- cssClass: ['ds-bottom-sheet', 'auto-height']
466
- });
467
-
468
- const result = await modal.onWillDismiss();
469
- if (result?.data?.value !== undefined) {
470
- // value is now an array of selected restriction IDs
471
- const selectedIds = result.data.value as string[];
472
-
473
- // If no restrictions are selected, show "Ingen adgangskrav"
474
- if (selectedIds.length === 0) {
475
- this.accessRequirements.set('Ingen adgangskrav');
476
- } else {
477
- const labels = selectedIds.map((id: string) => {
478
- // Convert IDs to display labels
479
- if (id === 'digital-adgangskode') return 'Digital adgangskode';
480
- if (id === 'depositum') return 'Depositum';
481
- if (id === 'nøglekort') return 'Nøglekort';
482
- return id;
483
- });
484
- this.accessRequirements.set(labels.join(', '));
485
- }
486
- }
487
- }
488
-
489
- /**
490
- * Add a new photo from camera/library
491
- */
492
- async addPhoto(): Promise<void> {
493
- if (this.attachments().length >= 6) {
494
- return;
495
- }
496
-
497
- try {
498
- const result = await FilePicker.pickImages({
499
- limit: 1,
500
- });
501
-
502
- const image = result.files?.[0];
503
- if (image) {
504
- const newAttachment: AttachmentData = {
505
- id: `photo-${Date.now()}`,
506
- src: image.path ? Capacitor.convertFileSrc(image.path) : (image.blob ? URL.createObjectURL(image.blob) : ''),
507
- type: 'image',
508
- name: image.name || `Photo ${this.attachments().length + 1}`,
509
- size: this.formatFileSize(image.size ?? 0),
510
- };
511
-
512
- this.attachments.update((attachments) => [...attachments, newAttachment]);
513
- }
514
- } catch (error) {
515
- console.error('[FacilityCreationModal] Error adding photo:', error);
516
- // User cancelled or error occurred - just ignore
517
- }
518
- }
519
-
520
- /**
521
- * Remove an attachment
522
- */
523
- removeAttachment(attachmentId: string): void {
524
- this.attachments.update((attachments) => attachments.filter((a) => a.id !== attachmentId));
525
- }
526
-
527
- /**
528
- * Handle attachment button click
529
- */
530
- handleAddAttachment(): void {
531
- if (this.attachments().length >= 6) {
532
- return;
533
- }
534
-
535
- // Trigger the hidden file input
536
- if (this.fileInput) {
537
- this.fileInput.nativeElement.click();
538
- }
539
- }
540
-
541
- /**
542
- * Detect file type from file name or mime type
543
- */
544
- private detectFileType(file: File): AttachmentFileType {
545
- const fileName = file.name.toLowerCase();
546
- const mimeType = file.type.toLowerCase();
547
-
548
- // Check if it's an image
549
- if (mimeType.startsWith('image/')) {
550
- return 'image';
551
- }
552
-
553
- // Check file extension
554
- if (fileName.endsWith('.pdf')) {
555
- return 'pdf';
556
- } else if (fileName.endsWith('.doc')) {
557
- return 'doc';
558
- } else if (fileName.endsWith('.docx')) {
559
- return 'docx';
560
- } else if (fileName.endsWith('.xls')) {
561
- return 'xls';
562
- } else if (fileName.endsWith('.xlsx')) {
563
- return 'xlsx';
564
- }
565
-
566
- return 'other';
567
- }
568
-
569
- /**
570
- * Format file size for display
571
- */
572
- private formatFileSize(bytes: number): string {
573
- if (bytes === 0) return '0 B';
574
- const k = 1024;
575
- const sizes = ['B', 'KB', 'MB', 'GB'];
576
- const i = Math.floor(Math.log(bytes) / Math.log(k));
577
- return Math.round((bytes / Math.pow(k, i)) * 100) / 100 + ' ' + sizes[i];
578
- }
579
-
580
- /**
581
- * Handle file selection from file input
582
- */
583
- handleFileSelect(event: Event): void {
584
- const input = event.target as HTMLInputElement;
585
- const files = input.files;
586
-
587
- if (!files || files.length === 0) {
588
- return;
589
- }
590
-
591
- // Process each selected file (up to the limit)
592
- const remainingSlots = 6 - this.attachments().length;
593
- const filesToProcess = Array.from(files).slice(0, remainingSlots);
594
-
595
- filesToProcess.forEach((file) => {
596
- const fileType = this.detectFileType(file);
597
-
598
- // Create a data URL for preview
599
- const reader = new FileReader();
600
- reader.onload = (e) => {
601
- const result = e.target?.result as string;
602
- if (result) {
603
- const newAttachment: AttachmentData = {
604
- id: `file-${Date.now()}-${Math.random()}`,
605
- src: result,
606
- type: fileType,
607
- name: file.name,
608
- size: this.formatFileSize(file.size),
609
- };
610
- this.attachments.update((attachments) => [...attachments, newAttachment]);
611
- }
612
- };
613
- reader.readAsDataURL(file);
614
- });
615
-
616
- // Reset the input so the same file can be selected again
617
- input.value = '';
618
- }
619
-
620
- /**
621
- * Handle form submission
622
- */
623
- async handleSubmit(): Promise<void> {
624
- if (!this.isFormValid() || this.isSubmitting()) {
625
- return;
626
- }
627
-
628
- this.isSubmitting.set(true);
629
-
630
- try {
631
- const facilityData: NewFacilityData = {
632
- title: this.title.trim(),
633
- description: this.description.trim(),
634
- whoCanBook: this.whoCanBook(),
635
- whenCanBook: this.whenCanBook(),
636
- price: this.price(),
637
- accessRequirements: this.accessRequirements(),
638
- attachments: this.attachments(),
639
- };
640
-
641
- console.log('[FacilityCreationModal] Submitting facility:', facilityData);
642
-
643
- if (this.onSubmit) {
644
- await this.onSubmit(facilityData);
645
- }
646
-
647
- // Success - close the modal
648
- this.modalController.dismiss();
649
- } catch (error) {
650
- console.error('[FacilityCreationModal] Error submitting facility:', error);
651
- this.error = 'Failed to create facility. Please try again.';
652
- } finally {
653
- this.isSubmitting.set(false);
654
- }
655
- }
656
- }
@@ -1,9 +0,0 @@
1
- export { DsMobileFacilityCreationModalComponent } from './ds-mobile-facility-creation-modal';
2
- export type { NewFacilityData } from './ds-mobile-facility-creation-modal';
3
- export { DsMobileFacilityCreationModalService } from './ds-mobile-facility-creation-modal.service';
4
- export type { FacilityCreationModalOptions } from './ds-mobile-facility-creation-modal.service';
5
- export { DsMobileFacilityCreationConfirmationWrapperComponent } from './ds-mobile-facility-creation-confirmation-wrapper';
6
- export { DsMobileWhoCanBookSheetComponent } from './sheets/ds-mobile-who-can-book-sheet';
7
- export { DsMobileWhenCanBookSheetComponent } from './sheets/ds-mobile-when-can-book-sheet';
8
- export { DsMobilePriceSheetComponent } from './sheets/ds-mobile-price-sheet';
9
- export { DsMobileAccessSheetComponent } from './sheets/ds-mobile-access-sheet';