@propbinder/mobile-design 0.2.74 → 0.2.75

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.
@@ -5,7 +5,7 @@ import { CommonModule, isPlatformBrowser } from '@angular/common';
5
5
  import * as i1$3 from '@angular/router';
6
6
  import { Router, NavigationEnd, ActivatedRoute } from '@angular/router';
7
7
  import * as i1 from '@ionic/angular/standalone';
8
- import { ModalController, IonHeader, IonToolbar, IonTitle, IonButtons, IonContent, Platform, IonRefresher, IonRefresherContent, IonPopover, AlertController, IonSpinner, IonTabBar, IonTabButton, IonLabel, IonTabs, IonTab, IonPicker, IonPickerColumn, IonPickerColumnOption, IonInfiniteScroll, IonInfiniteScrollContent } from '@ionic/angular/standalone';
8
+ import { ModalController, IonHeader, IonToolbar, IonTitle, IonButtons, IonContent, Platform, IonRefresher, IonRefresherContent, IonPopover, AlertController, IonSpinner, IonTabBar, IonTabButton, IonLabel, IonTabs, IonTab, IonPicker, IonPickerColumn, IonPickerColumnOption, IonInfiniteScroll, IonInfiniteScrollContent, NavController } from '@ionic/angular/standalone';
9
9
  import { ImpactStyle, Haptics } from '@capacitor/haptics';
10
10
  import { DsIconButtonComponent, DsIconComponent, DsButtonComponent, DsAvatarComponent, DsShapeIndicatorComponent, DsTextareaComponent, DsDatepickerComponent, DsCheckboxComponent, DsInputTimeComponent, DsLabelComponent, DsBadgeComponent } from '@propbinder/design-system';
11
11
  import { StatusBar, Style } from '@capacitor/status-bar';
@@ -12268,6 +12268,325 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
12268
12268
  type: Input
12269
12269
  }] } });
12270
12270
 
12271
+ const DEFAULT_COMMUNITY_ADMIN_LABELS = {
12272
+ pageTitle: 'Fællesskabsadministrator',
12273
+ closeButton: 'Luk',
12274
+ addButtonAriaLabel: 'Tilføj administrator',
12275
+ emptyState: 'Ingen administratorer endnu',
12276
+ emptyStateDescription: 'Tilføj beboere som administratorer, så de kan hjælpe med at administrere fællesskabet.',
12277
+ removeConfirmTitle: 'Fjern administrator?',
12278
+ removeConfirmMessage: (name) => `${name} fjernes som administrator.`,
12279
+ removeConfirmButton: 'Fjern',
12280
+ cancelButton: 'Annuller',
12281
+ addPickerTitle: 'Tilføj administrator',
12282
+ addPickerSearchPlaceholder: 'Søg efter beboer',
12283
+ addPickerSearchAriaLabel: 'Søg efter beboer',
12284
+ addPickerEmpty: 'Ingen beboere fundet',
12285
+ onboardingTitle: 'Du er nu fællesskabsadministrator',
12286
+ onboardingMessage: 'Du kan nu oprette bookbare faciliteter i fællesskabet, samt fastgøre eller slette opslag i dit ejendomsfællesskab.',
12287
+ onboardingButton: 'Forstået',
12288
+ };
12289
+ /**
12290
+ * Full-screen modal for managing community administrators.
12291
+ *
12292
+ * The main view lists current admins with a "more" menu to remove them.
12293
+ * Tapping the "+" header button opens a stacked picker modal to add new admins
12294
+ * from the available tenants list.
12295
+ */
12296
+ class DsMobileCommunityAdminsModalComponent {
12297
+ modalCtrl = inject(ModalController);
12298
+ bottomSheet = inject(DsMobileBottomSheetService);
12299
+ getAdminsSnapshot;
12300
+ availableTenants = [];
12301
+ currentUserId = '';
12302
+ onAddAdmin;
12303
+ onRemoveAdmin;
12304
+ labels;
12305
+ lbl;
12306
+ localAdmins = [];
12307
+ get showAddButton() {
12308
+ return !!this.onAddAdmin && this.availableTenants.length > 0;
12309
+ }
12310
+ ngOnInit() {
12311
+ this.lbl = { ...DEFAULT_COMMUNITY_ADMIN_LABELS, ...this.labels };
12312
+ this.syncAdmins();
12313
+ }
12314
+ syncAdmins() {
12315
+ this.localAdmins = [...(this.getAdminsSnapshot?.() ?? [])];
12316
+ }
12317
+ async confirmRemoveAdmin(admin) {
12318
+ if (!this.onRemoveAdmin || admin.id === this.currentUserId)
12319
+ return;
12320
+ const confirm = await this.bottomSheet.create({
12321
+ component: DsMobileConfirmationSheetComponent,
12322
+ componentProps: {
12323
+ title: this.lbl.removeConfirmMessage(admin.name),
12324
+ buttonText: this.lbl.removeConfirmButton,
12325
+ destructive: true,
12326
+ showIllustration: false,
12327
+ showCancelButton: true,
12328
+ },
12329
+ breakpoints: [0, 1],
12330
+ initialBreakpoint: 1,
12331
+ handle: true,
12332
+ cssClass: 'auto-height',
12333
+ });
12334
+ const result = await confirm.onWillDismiss();
12335
+ if (result.role !== 'confirm')
12336
+ return;
12337
+ await Promise.resolve(this.onRemoveAdmin(admin.id));
12338
+ this.syncAdmins();
12339
+ }
12340
+ async openAddAdminPicker() {
12341
+ if (!this.onAddAdmin)
12342
+ return;
12343
+ const currentAdminIds = new Set(this.localAdmins.map(a => a.id));
12344
+ const pickable = this.availableTenants.filter(t => !currentAdminIds.has(t.id));
12345
+ if (pickable.length === 0)
12346
+ return;
12347
+ const picker = await this.modalCtrl.create({
12348
+ component: DsMobileCommunityAdminPickerComponent,
12349
+ componentProps: {
12350
+ tenants: pickable,
12351
+ labels: this.lbl,
12352
+ },
12353
+ cssClass: 'ds-modal-base',
12354
+ mode: 'ios',
12355
+ presentingElement: document.querySelector('ion-router-outlet') || undefined,
12356
+ backdropDismiss: true,
12357
+ showBackdrop: true,
12358
+ animated: true,
12359
+ });
12360
+ await picker.present();
12361
+ const { data, role } = await picker.onWillDismiss();
12362
+ if (role === 'selected' && data?.tenantId) {
12363
+ await Promise.resolve(this.onAddAdmin(data.tenantId));
12364
+ this.syncAdmins();
12365
+ }
12366
+ }
12367
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DsMobileCommunityAdminsModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
12368
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: DsMobileCommunityAdminsModalComponent, isStandalone: true, selector: "ds-mobile-community-admins-modal", inputs: { getAdminsSnapshot: "getAdminsSnapshot", availableTenants: "availableTenants", currentUserId: "currentUserId", onAddAdmin: "onAddAdmin", onRemoveAdmin: "onRemoveAdmin", labels: "labels" }, ngImport: i0, template: `
12369
+ <ds-mobile-modal-base
12370
+ [headerTitle]="lbl.pageTitle"
12371
+ [closeButtonLabel]="lbl.closeButton"
12372
+ contentPadding="0"
12373
+ [hasFixedBottom]="false"
12374
+ >
12375
+ @if (showAddButton) {
12376
+ <div header-trailing>
12377
+ <ds-icon-button
12378
+ icon="remixAddLine"
12379
+ variant="secondary"
12380
+ size="md"
12381
+ (clicked)="openAddAdminPicker()"
12382
+ [attr.aria-label]="lbl.addButtonAriaLabel"
12383
+ />
12384
+ </div>
12385
+ }
12386
+
12387
+ <ds-mobile-section contentGap="0px" padding="12px 20px 20px 20px" [showBorder]="false">
12388
+ @if (localAdmins.length > 0) {
12389
+ @for (admin of localAdmins; track admin.id) {
12390
+ <ds-mobile-contact-list-item
12391
+ [name]="admin.name"
12392
+ [initials]="admin.avatarInitials || ''"
12393
+ [contactPerson]="admin.unit || ''"
12394
+ [avatarSrc]="admin.avatarSrc || ''"
12395
+ [avatarType]="admin.avatarType || 'initials'"
12396
+ [clickable]="false"
12397
+ [showChevron]="false"
12398
+ [showDeleteAction]="admin.id !== currentUserId"
12399
+ (deleteClick)="confirmRemoveAdmin(admin)"
12400
+ />
12401
+ }
12402
+ } @else {
12403
+ <p class="empty-state">{{ lbl.emptyState }}</p>
12404
+ }
12405
+ </ds-mobile-section>
12406
+ </ds-mobile-modal-base>
12407
+ `, isInline: true, styles: [".empty-state{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);color:var(--color-text-tertiary);text-align:center;padding:24px 16px;margin:0}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: DsMobileModalBaseComponent, selector: "ds-mobile-modal-base", inputs: ["headerTitleInteractive", "showHeader"], outputs: ["titleClick"] }, { kind: "component", type: DsIconButtonComponent, selector: "ds-icon-button", inputs: ["variant", "size", "icon", "disabled", "loading", "pressed", "expanded", "ariaLabel", "tooltip", "tooltipDisabled", "tooltipPlacement"], outputs: ["clicked", "focused", "blurred"] }, { kind: "component", type: DsMobileSectionComponent, selector: "ds-mobile-section", inputs: ["headline", "icon", "linkText", "padding", "paddingDesktop", "gap", "contentGap", "showBorder", "overflow"], outputs: ["linkClick"] }, { kind: "component", type: DsMobileContactListItemComponent, selector: "ds-mobile-contact-list-item", inputs: ["name", "nameSuffix", "initials", "avatarSrc", "avatarType", "avatarIconName", "showBadge", "contactPerson", "phoneNumber", "clickable", "showChevron", "showMoreMenu", "moreMenuAriaLabel", "selectionMode", "selected", "showDeleteAction", "variant", "align"], outputs: ["contactClick", "selectionToggle", "moreClick", "deleteClick"] }] });
12408
+ }
12409
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DsMobileCommunityAdminsModalComponent, decorators: [{
12410
+ type: Component,
12411
+ args: [{ selector: 'ds-mobile-community-admins-modal', standalone: true, imports: [
12412
+ CommonModule,
12413
+ DsMobileModalBaseComponent,
12414
+ DsIconButtonComponent,
12415
+ DsMobileSectionComponent,
12416
+ DsMobileContactListItemComponent,
12417
+ ], template: `
12418
+ <ds-mobile-modal-base
12419
+ [headerTitle]="lbl.pageTitle"
12420
+ [closeButtonLabel]="lbl.closeButton"
12421
+ contentPadding="0"
12422
+ [hasFixedBottom]="false"
12423
+ >
12424
+ @if (showAddButton) {
12425
+ <div header-trailing>
12426
+ <ds-icon-button
12427
+ icon="remixAddLine"
12428
+ variant="secondary"
12429
+ size="md"
12430
+ (clicked)="openAddAdminPicker()"
12431
+ [attr.aria-label]="lbl.addButtonAriaLabel"
12432
+ />
12433
+ </div>
12434
+ }
12435
+
12436
+ <ds-mobile-section contentGap="0px" padding="12px 20px 20px 20px" [showBorder]="false">
12437
+ @if (localAdmins.length > 0) {
12438
+ @for (admin of localAdmins; track admin.id) {
12439
+ <ds-mobile-contact-list-item
12440
+ [name]="admin.name"
12441
+ [initials]="admin.avatarInitials || ''"
12442
+ [contactPerson]="admin.unit || ''"
12443
+ [avatarSrc]="admin.avatarSrc || ''"
12444
+ [avatarType]="admin.avatarType || 'initials'"
12445
+ [clickable]="false"
12446
+ [showChevron]="false"
12447
+ [showDeleteAction]="admin.id !== currentUserId"
12448
+ (deleteClick)="confirmRemoveAdmin(admin)"
12449
+ />
12450
+ }
12451
+ } @else {
12452
+ <p class="empty-state">{{ lbl.emptyState }}</p>
12453
+ }
12454
+ </ds-mobile-section>
12455
+ </ds-mobile-modal-base>
12456
+ `, styles: [".empty-state{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);color:var(--color-text-tertiary);text-align:center;padding:24px 16px;margin:0}\n"] }]
12457
+ }], propDecorators: { getAdminsSnapshot: [{
12458
+ type: Input,
12459
+ args: [{ required: true }]
12460
+ }], availableTenants: [{
12461
+ type: Input
12462
+ }], currentUserId: [{
12463
+ type: Input
12464
+ }], onAddAdmin: [{
12465
+ type: Input
12466
+ }], onRemoveAdmin: [{
12467
+ type: Input
12468
+ }], labels: [{
12469
+ type: Input
12470
+ }] } });
12471
+ /**
12472
+ * Internal stacked picker for selecting a single tenant to promote to admin.
12473
+ */
12474
+ class DsMobileCommunityAdminPickerComponent {
12475
+ modalCtrl = inject(ModalController);
12476
+ tenants = [];
12477
+ labels;
12478
+ lbl;
12479
+ searchQuery = signal('', ...(ngDevMode ? [{ debugName: "searchQuery" }] : []));
12480
+ tenantsSig = signal([], ...(ngDevMode ? [{ debugName: "tenantsSig" }] : []));
12481
+ ngOnInit() {
12482
+ this.lbl = this.labels ?? DEFAULT_COMMUNITY_ADMIN_LABELS;
12483
+ this.tenantsSig.set(this.tenants ?? []);
12484
+ }
12485
+ filteredTenants = computed(() => {
12486
+ const q = this.searchQuery().toLowerCase().trim();
12487
+ const list = this.tenantsSig();
12488
+ if (!q)
12489
+ return list;
12490
+ return list.filter(t => t.name.toLowerCase().includes(q) ||
12491
+ (t.unit ?? '').toLowerCase().includes(q));
12492
+ }, ...(ngDevMode ? [{ debugName: "filteredTenants" }] : []));
12493
+ selectTenant(tenant) {
12494
+ void this.modalCtrl.dismiss({ tenantId: tenant.id }, 'selected');
12495
+ }
12496
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DsMobileCommunityAdminPickerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
12497
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: DsMobileCommunityAdminPickerComponent, isStandalone: true, selector: "ds-mobile-community-admin-picker", inputs: { tenants: "tenants", labels: "labels" }, ngImport: i0, template: `
12498
+ <ds-mobile-modal-base
12499
+ [headerTitle]="lbl.addPickerTitle"
12500
+ [closeButtonLabel]="lbl.closeButton"
12501
+ [hasFixedBottom]="false"
12502
+ [enableKeyboardHandling]="true"
12503
+ contentPadding="0"
12504
+ >
12505
+ <div header-below>
12506
+ <ds-mobile-list-search
12507
+ [placeholder]="lbl.addPickerSearchPlaceholder"
12508
+ [ariaLabel]="lbl.addPickerSearchAriaLabel"
12509
+ [showDivider]="false"
12510
+ [value]="searchQuery()"
12511
+ (valueChange)="searchQuery.set($event)"
12512
+ />
12513
+ </div>
12514
+
12515
+ <ds-mobile-section contentGap="0px" padding="12px 20px 20px 20px" [showBorder]="false">
12516
+ @if (filteredTenants().length > 0) {
12517
+ @for (t of filteredTenants(); track t.id) {
12518
+ <ds-mobile-contact-list-item
12519
+ [name]="t.name"
12520
+ [initials]="t.avatarInitials || ''"
12521
+ [contactPerson]="t.unit || ''"
12522
+ [avatarSrc]="t.avatarSrc || ''"
12523
+ [avatarType]="t.avatarType || 'initials'"
12524
+ [clickable]="true"
12525
+ [showMoreMenu]="false"
12526
+ [showChevron]="false"
12527
+ (contactClick)="selectTenant(t)"
12528
+ />
12529
+ }
12530
+ } @else {
12531
+ <p class="search-empty">{{ lbl.addPickerEmpty }}</p>
12532
+ }
12533
+ </ds-mobile-section>
12534
+ </ds-mobile-modal-base>
12535
+ `, isInline: true, styles: [".search-empty{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);color:var(--color-text-tertiary);text-align:center;padding:24px 16px;margin:0}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: DsMobileModalBaseComponent, selector: "ds-mobile-modal-base", inputs: ["headerTitleInteractive", "showHeader"], outputs: ["titleClick"] }, { kind: "component", type: DsMobileSectionComponent, selector: "ds-mobile-section", inputs: ["headline", "icon", "linkText", "padding", "paddingDesktop", "gap", "contentGap", "showBorder", "overflow"], outputs: ["linkClick"] }, { kind: "component", type: DsMobileListSearchComponent, selector: "ds-mobile-list-search", inputs: ["placeholder", "ariaLabel", "value", "showDivider"], outputs: ["valueChange"] }, { kind: "component", type: DsMobileContactListItemComponent, selector: "ds-mobile-contact-list-item", inputs: ["name", "nameSuffix", "initials", "avatarSrc", "avatarType", "avatarIconName", "showBadge", "contactPerson", "phoneNumber", "clickable", "showChevron", "showMoreMenu", "moreMenuAriaLabel", "selectionMode", "selected", "showDeleteAction", "variant", "align"], outputs: ["contactClick", "selectionToggle", "moreClick", "deleteClick"] }] });
12536
+ }
12537
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DsMobileCommunityAdminPickerComponent, decorators: [{
12538
+ type: Component,
12539
+ args: [{ selector: 'ds-mobile-community-admin-picker', standalone: true, imports: [
12540
+ CommonModule,
12541
+ DsMobileModalBaseComponent,
12542
+ DsMobileSectionComponent,
12543
+ DsMobileListSearchComponent,
12544
+ DsMobileContactListItemComponent,
12545
+ ], template: `
12546
+ <ds-mobile-modal-base
12547
+ [headerTitle]="lbl.addPickerTitle"
12548
+ [closeButtonLabel]="lbl.closeButton"
12549
+ [hasFixedBottom]="false"
12550
+ [enableKeyboardHandling]="true"
12551
+ contentPadding="0"
12552
+ >
12553
+ <div header-below>
12554
+ <ds-mobile-list-search
12555
+ [placeholder]="lbl.addPickerSearchPlaceholder"
12556
+ [ariaLabel]="lbl.addPickerSearchAriaLabel"
12557
+ [showDivider]="false"
12558
+ [value]="searchQuery()"
12559
+ (valueChange)="searchQuery.set($event)"
12560
+ />
12561
+ </div>
12562
+
12563
+ <ds-mobile-section contentGap="0px" padding="12px 20px 20px 20px" [showBorder]="false">
12564
+ @if (filteredTenants().length > 0) {
12565
+ @for (t of filteredTenants(); track t.id) {
12566
+ <ds-mobile-contact-list-item
12567
+ [name]="t.name"
12568
+ [initials]="t.avatarInitials || ''"
12569
+ [contactPerson]="t.unit || ''"
12570
+ [avatarSrc]="t.avatarSrc || ''"
12571
+ [avatarType]="t.avatarType || 'initials'"
12572
+ [clickable]="true"
12573
+ [showMoreMenu]="false"
12574
+ [showChevron]="false"
12575
+ (contactClick)="selectTenant(t)"
12576
+ />
12577
+ }
12578
+ } @else {
12579
+ <p class="search-empty">{{ lbl.addPickerEmpty }}</p>
12580
+ }
12581
+ </ds-mobile-section>
12582
+ </ds-mobile-modal-base>
12583
+ `, styles: [".search-empty{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);color:var(--color-text-tertiary);text-align:center;padding:24px 16px;margin:0}\n"] }]
12584
+ }], propDecorators: { tenants: [{
12585
+ type: Input
12586
+ }], labels: [{
12587
+ type: Input
12588
+ }] } });
12589
+
12271
12590
  function isPeerDirectConversation(c) {
12272
12591
  return c.kind === 'direct';
12273
12592
  }
@@ -12398,6 +12717,71 @@ function sysMsg(id, systemKind, systemMeta, ts) {
12398
12717
  };
12399
12718
  }
12400
12719
 
12720
+ const RADIUS_PX = {
12721
+ sm: 6,
12722
+ md: 8,
12723
+ lg: 12,
12724
+ xl: 16,
12725
+ };
12726
+ class DsMobileVendorAvatarComponent {
12727
+ name = input('', ...(ngDevMode ? [{ debugName: "name" }] : []));
12728
+ logo = input('', ...(ngDevMode ? [{ debugName: "logo" }] : []));
12729
+ size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : []));
12730
+ radiusPx = computed(() => RADIUS_PX[this.size()], ...(ngDevMode ? [{ debugName: "radiusPx" }] : []));
12731
+ sizePx = computed(() => {
12732
+ const map = { sm: 24, md: 32, lg: 48, xl: 64 };
12733
+ return map[this.size()];
12734
+ }, ...(ngDevMode ? [{ debugName: "sizePx" }] : []));
12735
+ initials = computed(() => {
12736
+ return this.name()
12737
+ .split(/\s+/)
12738
+ .filter(w => w.length > 0)
12739
+ .slice(0, 2)
12740
+ .map(w => w[0].toUpperCase())
12741
+ .join('');
12742
+ }, ...(ngDevMode ? [{ debugName: "initials" }] : []));
12743
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DsMobileVendorAvatarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
12744
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: DsMobileVendorAvatarComponent, isStandalone: true, selector: "ds-mobile-vendor-avatar", inputs: { name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null }, logo: { classPropertyName: "logo", publicName: "logo", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
12745
+ @if (logo()) {
12746
+ <div
12747
+ class="vendor-avatar-logo"
12748
+ [style.width.px]="sizePx()"
12749
+ [style.height.px]="sizePx()"
12750
+ [style.border-radius.px]="radiusPx()">
12751
+ <img [src]="logo()" [alt]="name()" />
12752
+ </div>
12753
+ } @else {
12754
+ <div [style.--vendor-avatar-radius.px]="radiusPx()">
12755
+ <ds-avatar
12756
+ type="initials"
12757
+ [size]="size()"
12758
+ [initials]="initials()" />
12759
+ </div>
12760
+ }
12761
+ `, isInline: true, styles: [":host{display:inline-flex;flex-shrink:0}.vendor-avatar-logo{display:inline-flex;align-items:center;justify-content:center;overflow:hidden;flex-shrink:0;background:transparent}.vendor-avatar-logo img{width:100%;height:100%;object-fit:contain;display:block}:host ::ng-deep ds-avatar .avatar{border-radius:var(--vendor-avatar-radius)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: DsAvatarComponent, selector: "ds-avatar", inputs: ["type", "size", "initials", "src", "alt", "iconName", "iconColor"] }] });
12762
+ }
12763
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DsMobileVendorAvatarComponent, decorators: [{
12764
+ type: Component,
12765
+ args: [{ selector: 'ds-mobile-vendor-avatar', standalone: true, imports: [CommonModule, DsAvatarComponent], template: `
12766
+ @if (logo()) {
12767
+ <div
12768
+ class="vendor-avatar-logo"
12769
+ [style.width.px]="sizePx()"
12770
+ [style.height.px]="sizePx()"
12771
+ [style.border-radius.px]="radiusPx()">
12772
+ <img [src]="logo()" [alt]="name()" />
12773
+ </div>
12774
+ } @else {
12775
+ <div [style.--vendor-avatar-radius.px]="radiusPx()">
12776
+ <ds-avatar
12777
+ type="initials"
12778
+ [size]="size()"
12779
+ [initials]="initials()" />
12780
+ </div>
12781
+ }
12782
+ `, styles: [":host{display:inline-flex;flex-shrink:0}.vendor-avatar-logo{display:inline-flex;align-items:center;justify-content:center;overflow:hidden;flex-shrink:0;background:transparent}.vendor-avatar-logo img{width:100%;height:100%;object-fit:contain;display:block}:host ::ng-deep ds-avatar .avatar{border-radius:var(--vendor-avatar-radius)}\n"] }]
12783
+ }], propDecorators: { name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }], logo: [{ type: i0.Input, args: [{ isSignal: true, alias: "logo", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }] } });
12784
+
12401
12785
  /**
12402
12786
  * DsMobileCardInlineComponent
12403
12787
  *
@@ -15595,6 +15979,11 @@ class DsMobileChatModalComponent {
15595
15979
  (click)="onGroupTitleClick()"
15596
15980
  />
15597
15981
  }
15982
+ } @else if (participant().avatarShape === 'squircle') {
15983
+ <ds-mobile-vendor-avatar
15984
+ [name]="participant().name"
15985
+ [logo]="participant().avatarSrc || ''"
15986
+ size="md" />
15598
15987
  } @else {
15599
15988
  <ds-avatar-with-badge
15600
15989
  [initials]="participant().avatarInitials || ''"
@@ -15658,6 +16047,11 @@ class DsMobileChatModalComponent {
15658
16047
  style="cursor: pointer"
15659
16048
  (click)="onGroupTitleClick(); $event.stopPropagation()"
15660
16049
  />
16050
+ } @else if (participant().avatarShape === 'squircle') {
16051
+ <ds-mobile-vendor-avatar
16052
+ [name]="participant().name"
16053
+ [logo]="participant().avatarSrc || ''"
16054
+ size="xl" />
15661
16055
  } @else {
15662
16056
  <ds-avatar-with-badge
15663
16057
  [initials]="participant().avatarInitials || ''"
@@ -15809,13 +16203,14 @@ class DsMobileChatModalComponent {
15809
16203
  </ds-mobile-message-composer>
15810
16204
  </div>
15811
16205
  </ds-mobile-modal-base>
15812
- `, isInline: true, styles: [".author-details{display:flex;flex-direction:column;gap:2px;min-width:0;flex:1}.author-name{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);font-weight:600;line-height:20px;letter-spacing:-.3px;color:var(--color-text-primary, #1a1a1a);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.author-meta{font-family:Brockmann,sans-serif;font-size:var(--font-size-xs);font-weight:400;line-height:1.2;letter-spacing:-.26px;color:var(--color-text-tertiary, #737373);display:flex;align-items:center;gap:6px}.author-meta .separator{color:var(--color-text-tertiary, #a0a0a0)}.lightbox-context .author-name,.overlay-context .author-name{color:#fffffff2}.lightbox-context .author-meta,.overlay-context .author-meta{color:#ffffffb3}.lightbox-context .author-meta .separator,.overlay-context .author-meta .separator{color:#ffffff80}.section-headline{font-size:var(--font-size-base);font-weight:600;color:var(--text-color-default-primary);padding:16px 0;margin:0;letter-spacing:-.2px;display:flex;align-items:center;gap:6px}.empty-state-title{font-family:Brockmann,sans-serif;font-size:var(--font-size-base);font-weight:600;line-height:1.3;color:var(--text-color-default-primary, #202227);margin:0 0 8px}.empty-state-description{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);font-weight:400;line-height:1.4;color:var(--text-color-default-secondary, #545B66);margin:0}.ghost-input-clean ::ng-deep .ds-input,.ghost-input-clean ::ng-deep .ds-textarea,.ghost-input-clean ::ng-deep .textarea-container{outline:none!important;border:none!important;padding:0!important}:host ::ng-deep ds-textarea.ghost-input-clean .textarea-container{padding:0!important}.ghost-input-clean ::ng-deep .ds-input:hover,.ghost-input-clean ::ng-deep .ds-textarea:hover,.ghost-input-clean ::ng-deep .textarea-container:hover,.ghost-input-clean ::ng-deep .ds-input:focus,.ghost-input-clean ::ng-deep .ds-textarea:focus,.ghost-input-clean ::ng-deep .textarea-container:focus,.ghost-input-clean ::ng-deep .ds-input:focus-within,.ghost-input-clean ::ng-deep .ds-textarea:focus-within,.ghost-input-clean ::ng-deep .textarea-container:focus-within{outline:none!important;border:none!important;box-shadow:none!important}.ghost-input-clean ::ng-deep textarea{outline:none!important;border:none!important;box-shadow:none!important;resize:none!important}.ghost-input-clean ::ng-deep textarea:hover,.ghost-input-clean ::ng-deep textarea:focus{outline:none!important;border:none!important;box-shadow:none!important}\n", ":host ::ng-deep .modal-content-container{padding-top:0}:host-context(.chat-modal--settings) ::ng-deep .modal-header{border-bottom:none}:host-context(.chat-modal--add-members) ::ng-deep .modal-header{border-bottom:1px solid var(--border-color-default)}.chat-messages-container{display:flex;flex-direction:column;width:100%}.chat-system-line{font-family:Brockmann,sans-serif;font-size:var(--font-size-xs, 12px);font-weight:400;line-height:1.35;color:var(--text-color-default-tertiary, #737373);text-align:center;margin:8px 24px}.chat-avatar-section{display:flex;flex-direction:column;align-items:center;gap:12px;padding:48px 0 0;background:var(--color-background-neutral-primary, #ffffff)}.chat-avatar-info{display:flex;flex-direction:column;align-items:center;gap:4px}.chat-avatar-name{display:flex;align-items:center;gap:6px;font-family:Brockmann,sans-serif;font-size:var(--font-size-base);font-weight:600;line-height:1.3;color:var(--color-text-primary, #1a1a1a)}.chat-avatar-role{font-family:Brockmann,sans-serif;font-size:var(--font-size-xs);font-weight:400;line-height:1.2;color:var(--color-text-secondary, #666666)}.chat-avatar-meta{font-family:Brockmann,sans-serif;font-size:var(--font-size-xs);font-weight:400;line-height:1.2;color:var(--color-text-tertiary, #737373);display:flex;align-items:center;gap:4px}.messages-list{display:flex;flex-direction:column;width:100%;padding:16px 0 0;align-items:stretch}.messages-list ds-mobile-message-bubble{width:100%;display:flex}.timestamp-header{display:flex;justify-content:center;margin:16px 0 8px}.timestamp-text{font-family:Brockmann,sans-serif;font-size:12px;font-weight:400;color:var(--color-text-secondary);padding:4px 12px}.message-file-attachments{display:flex;flex-direction:column;gap:8px;margin-bottom:12px;padding:0 20px 0 60px;max-width:100%}.message-file-attachments.own-message{padding:0 0 0 96px;align-items:flex-end}.message-file-attachments ds-mobile-card-inline-file{max-width:280px;width:100%}.message-image-attachment{width:96px;height:96px;cursor:pointer;border-radius:12px;overflow:hidden;position:relative;transition:transform .2s ease;border:1px solid var(--border-color-default, #e5e5e5)}.message-image-attachment:active{transform:scale(.98)}.message-image-attachment .inline-image{width:100%;height:100%;display:block;-o-object-fit:cover;object-fit:cover}.group-settings-back-btn{flex-shrink:0;border-radius:50%}.group-settings-back-btn::ng-deep button{border-radius:50%!important;width:36px!important;height:36px!important;min-width:36px!important;min-height:36px!important;padding:0!important;display:flex!important;align-items:center!important;justify-content:center!important}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: DsAvatarWithBadgeComponent, selector: "ds-avatar-with-badge", inputs: ["type", "size", "initials", "src", "iconName", "showBadge", "badgePosition"] }, { kind: "component", type: DsMobileMessageComposerComponent, selector: "ds-mobile-message-composer", inputs: ["avatarInitials", "avatarType", "avatarSrc", "placeholder", "sendButtonLabel", "attachmentButtonLabel", "showAttachmentButton", "editIndicatorText", "replyIndicatorText", "enableMentions", "mentionUsers", "autoFocus"], outputs: ["messageSent", "editCancelled", "replyCancelled", "mentionSelected", "attachmentClicked", "attachmentsChanged"] }, { kind: "component", type: DsMobileMessageBubbleComponent, selector: "ds-mobile-message-bubble", inputs: ["content", "isOwnMessage", "senderName", "timestamp", "showTimestamp", "avatarInitials", "avatarType", "avatarSrc", "showAvatar", "clusterPosition", "attachments", "clickable", "isNewMessage", "isDeleted", "showEditedHint", "editedHintText"], outputs: ["attachmentClick", "longPress", "messageClick"] }, { kind: "component", type: DsMobileModalBaseComponent, selector: "ds-mobile-modal-base", inputs: ["headerTitleInteractive", "showHeader"], outputs: ["titleClick"] }, { kind: "component", type: DsMobileCardInlineFileComponent, selector: "ds-mobile-card-inline-file", inputs: ["fileName", "fileSize", "variant", "layout", "fileUrl"], outputs: ["fileClick"] }, { kind: "component", type: DsMobileSystemMessageBannerComponent, selector: "ds-mobile-system-message-banner", inputs: ["message", "iconName", "afterTimestamp"] }, { kind: "component", type: DsIconComponent, selector: "ds-icon", inputs: ["name", "size", "color", "interactive"] }, { kind: "component", type: DsIconButtonComponent, selector: "ds-icon-button", inputs: ["variant", "size", "icon", "disabled", "loading", "pressed", "expanded", "ariaLabel", "tooltip", "tooltipDisabled", "tooltipPlacement"], outputs: ["clicked", "focused", "blurred"] }, { kind: "component", type: DsMobileSectionComponent, selector: "ds-mobile-section", inputs: ["headline", "icon", "linkText", "padding", "paddingDesktop", "gap", "contentGap", "showBorder", "overflow"], outputs: ["linkClick"] }, { kind: "component", type: DsMobileGroupAvatarStackComponent, selector: "ds-mobile-group-avatar-stack", inputs: ["members", "customAvatarUrl", "size", "layout", "currentUserId"] }, { kind: "component", type: DsMobileListSearchComponent, selector: "ds-mobile-list-search", inputs: ["placeholder", "ariaLabel", "value", "showDivider"], outputs: ["valueChange"] }, { kind: "component", type: DsMobileChatGroupPanelsComponent, selector: "ds-mobile-chat-group-panels", inputs: ["panelView", "group", "membersForStack", "participantName", "currentUserId", "isAdmin", "canEditGroupDetails", "canAddGroupMembers", "canLeaveGroup", "canRemoveMember", "canMessageMember", "allTenantsForPicker", "searchQuery", "labels"], outputs: ["navigateTo", "renameGroup", "setGroupAvatarUrl", "addMembers", "removeMember", "messageMember", "leaveGroup"] }] });
16206
+ `, isInline: true, styles: [".author-details{display:flex;flex-direction:column;gap:2px;min-width:0;flex:1}.author-name{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);font-weight:600;line-height:20px;letter-spacing:-.3px;color:var(--color-text-primary, #1a1a1a);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.author-meta{font-family:Brockmann,sans-serif;font-size:var(--font-size-xs);font-weight:400;line-height:1.2;letter-spacing:-.26px;color:var(--color-text-tertiary, #737373);display:flex;align-items:center;gap:6px}.author-meta .separator{color:var(--color-text-tertiary, #a0a0a0)}.lightbox-context .author-name,.overlay-context .author-name{color:#fffffff2}.lightbox-context .author-meta,.overlay-context .author-meta{color:#ffffffb3}.lightbox-context .author-meta .separator,.overlay-context .author-meta .separator{color:#ffffff80}.section-headline{font-size:var(--font-size-base);font-weight:600;color:var(--text-color-default-primary);padding:16px 0;margin:0;letter-spacing:-.2px;display:flex;align-items:center;gap:6px}.empty-state-title{font-family:Brockmann,sans-serif;font-size:var(--font-size-base);font-weight:600;line-height:1.3;color:var(--text-color-default-primary, #202227);margin:0 0 8px}.empty-state-description{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);font-weight:400;line-height:1.4;color:var(--text-color-default-secondary, #545B66);margin:0}.ghost-input-clean ::ng-deep .ds-input,.ghost-input-clean ::ng-deep .ds-textarea,.ghost-input-clean ::ng-deep .textarea-container{outline:none!important;border:none!important;padding:0!important}:host ::ng-deep ds-textarea.ghost-input-clean .textarea-container{padding:0!important}.ghost-input-clean ::ng-deep .ds-input:hover,.ghost-input-clean ::ng-deep .ds-textarea:hover,.ghost-input-clean ::ng-deep .textarea-container:hover,.ghost-input-clean ::ng-deep .ds-input:focus,.ghost-input-clean ::ng-deep .ds-textarea:focus,.ghost-input-clean ::ng-deep .textarea-container:focus,.ghost-input-clean ::ng-deep .ds-input:focus-within,.ghost-input-clean ::ng-deep .ds-textarea:focus-within,.ghost-input-clean ::ng-deep .textarea-container:focus-within{outline:none!important;border:none!important;box-shadow:none!important}.ghost-input-clean ::ng-deep textarea{outline:none!important;border:none!important;box-shadow:none!important;resize:none!important}.ghost-input-clean ::ng-deep textarea:hover,.ghost-input-clean ::ng-deep textarea:focus{outline:none!important;border:none!important;box-shadow:none!important}\n", ":host ::ng-deep .modal-content-container{padding-top:0}:host-context(.chat-modal--settings) ::ng-deep .modal-header{border-bottom:none}:host-context(.chat-modal--add-members) ::ng-deep .modal-header{border-bottom:1px solid var(--border-color-default)}.chat-messages-container{display:flex;flex-direction:column;width:100%}.chat-system-line{font-family:Brockmann,sans-serif;font-size:var(--font-size-xs, 12px);font-weight:400;line-height:1.35;color:var(--text-color-default-tertiary, #737373);text-align:center;margin:8px 24px}.chat-avatar-section{display:flex;flex-direction:column;align-items:center;gap:12px;padding:48px 0 0;background:var(--color-background-neutral-primary, #ffffff)}.chat-avatar-info{display:flex;flex-direction:column;align-items:center;gap:4px}.chat-avatar-name{display:flex;align-items:center;gap:6px;font-family:Brockmann,sans-serif;font-size:var(--font-size-base);font-weight:600;line-height:1.3;color:var(--color-text-primary, #1a1a1a)}.chat-avatar-role{font-family:Brockmann,sans-serif;font-size:var(--font-size-xs);font-weight:400;line-height:1.2;color:var(--color-text-secondary, #666666)}.chat-avatar-meta{font-family:Brockmann,sans-serif;font-size:var(--font-size-xs);font-weight:400;line-height:1.2;color:var(--color-text-tertiary, #737373);display:flex;align-items:center;gap:4px}.messages-list{display:flex;flex-direction:column;width:100%;padding:16px 0 0;align-items:stretch}.messages-list ds-mobile-message-bubble{width:100%;display:flex}.timestamp-header{display:flex;justify-content:center;margin:16px 0 8px}.timestamp-text{font-family:Brockmann,sans-serif;font-size:12px;font-weight:400;color:var(--color-text-secondary);padding:4px 12px}.message-file-attachments{display:flex;flex-direction:column;gap:8px;margin-bottom:12px;padding:0 20px 0 60px;max-width:100%}.message-file-attachments.own-message{padding:0 0 0 96px;align-items:flex-end}.message-file-attachments ds-mobile-card-inline-file{max-width:280px;width:100%}.message-image-attachment{width:96px;height:96px;cursor:pointer;border-radius:12px;overflow:hidden;position:relative;transition:transform .2s ease;border:1px solid var(--border-color-default, #e5e5e5)}.message-image-attachment:active{transform:scale(.98)}.message-image-attachment .inline-image{width:100%;height:100%;display:block;-o-object-fit:cover;object-fit:cover}.group-settings-back-btn{flex-shrink:0;border-radius:50%}.group-settings-back-btn::ng-deep button{border-radius:50%!important;width:36px!important;height:36px!important;min-width:36px!important;min-height:36px!important;padding:0!important;display:flex!important;align-items:center!important;justify-content:center!important}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: DsAvatarWithBadgeComponent, selector: "ds-avatar-with-badge", inputs: ["type", "size", "initials", "src", "iconName", "showBadge", "badgePosition"] }, { kind: "component", type: DsMobileVendorAvatarComponent, selector: "ds-mobile-vendor-avatar", inputs: ["name", "logo", "size"] }, { kind: "component", type: DsMobileMessageComposerComponent, selector: "ds-mobile-message-composer", inputs: ["avatarInitials", "avatarType", "avatarSrc", "placeholder", "sendButtonLabel", "attachmentButtonLabel", "showAttachmentButton", "editIndicatorText", "replyIndicatorText", "enableMentions", "mentionUsers", "autoFocus"], outputs: ["messageSent", "editCancelled", "replyCancelled", "mentionSelected", "attachmentClicked", "attachmentsChanged"] }, { kind: "component", type: DsMobileMessageBubbleComponent, selector: "ds-mobile-message-bubble", inputs: ["content", "isOwnMessage", "senderName", "timestamp", "showTimestamp", "avatarInitials", "avatarType", "avatarSrc", "showAvatar", "clusterPosition", "attachments", "clickable", "isNewMessage", "isDeleted", "showEditedHint", "editedHintText"], outputs: ["attachmentClick", "longPress", "messageClick"] }, { kind: "component", type: DsMobileModalBaseComponent, selector: "ds-mobile-modal-base", inputs: ["headerTitleInteractive", "showHeader"], outputs: ["titleClick"] }, { kind: "component", type: DsMobileCardInlineFileComponent, selector: "ds-mobile-card-inline-file", inputs: ["fileName", "fileSize", "variant", "layout", "fileUrl"], outputs: ["fileClick"] }, { kind: "component", type: DsMobileSystemMessageBannerComponent, selector: "ds-mobile-system-message-banner", inputs: ["message", "iconName", "afterTimestamp"] }, { kind: "component", type: DsIconComponent, selector: "ds-icon", inputs: ["name", "size", "color", "interactive"] }, { kind: "component", type: DsIconButtonComponent, selector: "ds-icon-button", inputs: ["variant", "size", "icon", "disabled", "loading", "pressed", "expanded", "ariaLabel", "tooltip", "tooltipDisabled", "tooltipPlacement"], outputs: ["clicked", "focused", "blurred"] }, { kind: "component", type: DsMobileSectionComponent, selector: "ds-mobile-section", inputs: ["headline", "icon", "linkText", "padding", "paddingDesktop", "gap", "contentGap", "showBorder", "overflow"], outputs: ["linkClick"] }, { kind: "component", type: DsMobileGroupAvatarStackComponent, selector: "ds-mobile-group-avatar-stack", inputs: ["members", "customAvatarUrl", "size", "layout", "currentUserId"] }, { kind: "component", type: DsMobileListSearchComponent, selector: "ds-mobile-list-search", inputs: ["placeholder", "ariaLabel", "value", "showDivider"], outputs: ["valueChange"] }, { kind: "component", type: DsMobileChatGroupPanelsComponent, selector: "ds-mobile-chat-group-panels", inputs: ["panelView", "group", "membersForStack", "participantName", "currentUserId", "isAdmin", "canEditGroupDetails", "canAddGroupMembers", "canLeaveGroup", "canRemoveMember", "canMessageMember", "allTenantsForPicker", "searchQuery", "labels"], outputs: ["navigateTo", "renameGroup", "setGroupAvatarUrl", "addMembers", "removeMember", "messageMember", "leaveGroup"] }] });
15813
16207
  }
15814
16208
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DsMobileChatModalComponent, decorators: [{
15815
16209
  type: Component,
15816
16210
  args: [{ selector: 'ds-mobile-chat-modal', standalone: true, imports: [
15817
16211
  CommonModule,
15818
16212
  DsAvatarWithBadgeComponent,
16213
+ DsMobileVendorAvatarComponent,
15819
16214
  DsMobileMessageComposerComponent,
15820
16215
  DsMobileMessageBubbleComponent,
15821
16216
  DsMobileModalBaseComponent,
@@ -15866,6 +16261,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
15866
16261
  (click)="onGroupTitleClick()"
15867
16262
  />
15868
16263
  }
16264
+ } @else if (participant().avatarShape === 'squircle') {
16265
+ <ds-mobile-vendor-avatar
16266
+ [name]="participant().name"
16267
+ [logo]="participant().avatarSrc || ''"
16268
+ size="md" />
15869
16269
  } @else {
15870
16270
  <ds-avatar-with-badge
15871
16271
  [initials]="participant().avatarInitials || ''"
@@ -15929,6 +16329,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
15929
16329
  style="cursor: pointer"
15930
16330
  (click)="onGroupTitleClick(); $event.stopPropagation()"
15931
16331
  />
16332
+ } @else if (participant().avatarShape === 'squircle') {
16333
+ <ds-mobile-vendor-avatar
16334
+ [name]="participant().name"
16335
+ [logo]="participant().avatarSrc || ''"
16336
+ size="xl" />
15932
16337
  } @else {
15933
16338
  <ds-avatar-with-badge
15934
16339
  [initials]="participant().avatarInitials || ''"
@@ -16711,12 +17116,23 @@ class DsMobileTenantPickerModalComponent {
16711
17116
  modalCtrl = inject(ModalController);
16712
17117
  peerMessaging = inject(PeerMessagingService);
16713
17118
  peerChat = inject(PeerChatLauncherService);
17119
+ /**
17120
+ * When true the modal acts as a simple single-select picker:
17121
+ * tapping a tenant dismisses with `{ tenantId }` (role `'selected'`).
17122
+ * The "more" menu and group-selection footer are hidden.
17123
+ */
17124
+ pickMode = false;
17125
+ /** Optional set of tenant IDs to exclude from the list (e.g. already-selected admins). */
17126
+ excludeIds;
16714
17127
  searchQuery = signal('', ...(ngDevMode ? [{ debugName: "searchQuery" }] : []));
16715
17128
  selectionMode = signal(false, ...(ngDevMode ? [{ debugName: "selectionMode" }] : []));
16716
17129
  selectedIds = signal(new Set(), ...(ngDevMode ? [{ debugName: "selectedIds" }] : []));
16717
17130
  filteredTenants = computed(() => {
16718
17131
  const q = this.searchQuery().toLowerCase().trim();
16719
- const tenants = this.peerMessaging.tenants();
17132
+ let tenants = this.peerMessaging.tenants();
17133
+ if (this.excludeIds?.size) {
17134
+ tenants = tenants.filter(t => !this.excludeIds.has(t.id));
17135
+ }
16720
17136
  if (!q)
16721
17137
  return tenants;
16722
17138
  return tenants.filter(t => t.name.toLowerCase().includes(q) || t.unit.toLowerCase().includes(q));
@@ -16738,6 +17154,10 @@ class DsMobileTenantPickerModalComponent {
16738
17154
  async onTenantClick(tenant) {
16739
17155
  if (this.selectionMode())
16740
17156
  return;
17157
+ if (this.pickMode) {
17158
+ await this.modalCtrl.dismiss({ tenantId: tenant.id }, 'selected');
17159
+ return;
17160
+ }
16741
17161
  await this.modalCtrl.dismiss(null, 'cancel');
16742
17162
  await this.peerChat.openTenant(tenant, { autoFocus: true });
16743
17163
  }
@@ -16787,7 +17207,7 @@ class DsMobileTenantPickerModalComponent {
16787
17207
  await this.peerChat.createGroup(ids, groupName);
16788
17208
  }
16789
17209
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DsMobileTenantPickerModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
16790
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: DsMobileTenantPickerModalComponent, isStandalone: true, selector: "ds-mobile-tenant-picker-modal", ngImport: i0, template: `
17210
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: DsMobileTenantPickerModalComponent, isStandalone: true, selector: "ds-mobile-tenant-picker-modal", inputs: { pickMode: "pickMode", excludeIds: "excludeIds" }, ngImport: i0, template: `
16791
17211
  <ds-mobile-modal-base
16792
17212
  headerTitle="Beboere"
16793
17213
  closeButtonLabel="Luk"
@@ -16813,8 +17233,8 @@ class DsMobileTenantPickerModalComponent {
16813
17233
  [initials]="tenant.initials"
16814
17234
  [contactPerson]="tenant.unit"
16815
17235
  [clickable]="true"
16816
- [showMoreMenu]="!selectionMode()"
16817
- [selectionMode]="selectionMode()"
17236
+ [showMoreMenu]="!pickMode && !selectionMode()"
17237
+ [selectionMode]="!pickMode && selectionMode()"
16818
17238
  [selected]="selectedIds().has(tenant.id)"
16819
17239
  (selectionToggle)="toggleTenant(tenant.id)"
16820
17240
  (contactClick)="onTenantClick(tenant)"
@@ -16880,8 +17300,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
16880
17300
  [initials]="tenant.initials"
16881
17301
  [contactPerson]="tenant.unit"
16882
17302
  [clickable]="true"
16883
- [showMoreMenu]="!selectionMode()"
16884
- [selectionMode]="selectionMode()"
17303
+ [showMoreMenu]="!pickMode && !selectionMode()"
17304
+ [selectionMode]="!pickMode && selectionMode()"
16885
17305
  [selected]="selectedIds().has(tenant.id)"
16886
17306
  (selectionToggle)="toggleTenant(tenant.id)"
16887
17307
  (contactClick)="onTenantClick(tenant)"
@@ -16912,7 +17332,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
16912
17332
  }
16913
17333
  </ds-mobile-modal-base>
16914
17334
  `, styles: [".search-empty{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);color:var(--color-text-tertiary);text-align:center;padding:24px 16px;margin:0}.group-footer{display:flex;gap:8px;padding:12px 16px;border-top:1px solid var(--border-color-default, #e5e5e5);background:var(--color-background-neutral-primary, #fff)}.group-footer ds-button{display:block;flex:1;min-width:0;width:100%}.group-footer ::ng-deep button{width:100%;border-radius:99px}\n"] }]
16915
- }] });
17335
+ }], propDecorators: { pickMode: [{
17336
+ type: Input
17337
+ }], excludeIds: [{
17338
+ type: Input
17339
+ }] } });
16916
17340
 
16917
17341
  var index = /*#__PURE__*/Object.freeze({
16918
17342
  __proto__: null,
@@ -17819,7 +18243,7 @@ class DsMobileInteractiveListItemBookingComponent {
17819
18243
  </div>
17820
18244
  }
17821
18245
  </ds-mobile-list-item>
17822
- `, isInline: true, styles: [":host{display:block}:host:last-child{--divider-display: none;--item-padding-bottom: 0}.booking-thumbnail{position:relative;flex-shrink:0;width:64px;height:64px;border-radius:12px;overflow:hidden;background:var(--color-surface-secondary, #f5f5f5);display:flex;align-items:center;justify-content:center}.booking-thumbnail img{width:100%;height:100%;object-fit:cover}.booking-thumbnail-placeholder{width:100%;height:100%;display:flex;align-items:center;justify-content:center;color:var(--text-color-default-tertiary, #737373)}.booking-content{display:flex;flex-direction:column;gap:4px;flex:1;min-width:0}.booking-title{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm, 14px);font-weight:600;line-height:20px;letter-spacing:-.3px;color:var(--text-color-default-primary, #202227);margin:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.booking-description{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm, 14px);font-weight:400;line-height:20px;letter-spacing:-.3px;color:var(--text-color-default-secondary, #545B66);margin:0;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.booking-meta{font-family:Brockmann,sans-serif;font-size:var(--font-size-xs, 12px);font-weight:400;line-height:1.2;letter-spacing:-.26px;color:var(--text-color-default-secondary, #545B66);display:flex;align-items:center;gap:8px;margin-top:4px}.booking-status{display:flex;align-items:center;gap:6px;font-family:Brockmann,sans-serif;font-size:var(--font-size-xs);font-weight:500;line-height:1.2;letter-spacing:-.26px;color:var(--text-color-default-secondary, #545B66)}.booking-status.available-today{color:var(--color-accent, #5d5fef)}.booking-status.available-from{color:var(--color-warning, #f59e0b)}.booking-status.unavailable{color:var(--text-color-default-tertiary, #737373)}.booking-datetime{display:flex;align-items:center;gap:4px;font-family:Brockmann,sans-serif;font-size:var(--font-size-xs);font-weight:400;line-height:1.2;letter-spacing:-.26px;color:var(--text-color-default-secondary, #545B66)}.booking-trailing{display:flex;align-items:center;color:var(--color-text-tertiary, #a3a3a3)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: DsIconComponent, selector: "ds-icon", inputs: ["name", "size", "color", "interactive"] }, { kind: "component", type: DsShapeIndicatorComponent, selector: "ds-shape-indicator", inputs: ["shape", "variant", "label"] }, { kind: "component", type: DsMobileListItemComponent, selector: "ds-mobile-list-item", inputs: ["leadingSize", "variant", "align", "flushTop", "interactive", "disabled", "loading", "enableLongPress", "showDesktopMoreButton", "moreActions", "moreButtonAriaLabel", "interactiveOffset", "title", "subtitle", "showDivider", "dividerSpacing"], outputs: ["itemClick", "moreButtonClick"] }, { kind: "component", type: DsMobileLoaderOverlayComponent, selector: "ds-mobile-loader-overlay", inputs: ["spinnerSize", "borderRadius"] }] });
18246
+ `, isInline: true, styles: [":host{display:block}:host:first-child{--item-padding-top: 0}:host:last-child{--divider-display: none;--item-padding-bottom: 0}.booking-thumbnail{position:relative;flex-shrink:0;width:64px;height:64px;border-radius:12px;overflow:hidden;background:var(--color-surface-secondary, #f5f5f5);display:flex;align-items:center;justify-content:center}.booking-thumbnail img{width:100%;height:100%;object-fit:cover}.booking-thumbnail-placeholder{width:100%;height:100%;display:flex;align-items:center;justify-content:center;color:var(--text-color-default-tertiary, #737373)}.booking-content{display:flex;flex-direction:column;gap:4px;flex:1;min-width:0}.booking-title{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm, 14px);font-weight:600;line-height:20px;letter-spacing:-.3px;color:var(--text-color-default-primary, #202227);margin:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.booking-description{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm, 14px);font-weight:400;line-height:20px;letter-spacing:-.3px;color:var(--text-color-default-secondary, #545B66);margin:0;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.booking-meta{font-family:Brockmann,sans-serif;font-size:var(--font-size-xs, 12px);font-weight:400;line-height:1.2;letter-spacing:-.26px;color:var(--text-color-default-secondary, #545B66);display:flex;align-items:center;gap:8px;margin-top:4px}.booking-status{display:flex;align-items:center;gap:6px;font-family:Brockmann,sans-serif;font-size:var(--font-size-xs);font-weight:500;line-height:1.2;letter-spacing:-.26px;color:var(--text-color-default-secondary, #545B66)}.booking-status.available-today{color:var(--color-accent, #5d5fef)}.booking-status.available-from{color:var(--color-warning, #f59e0b)}.booking-status.unavailable{color:var(--text-color-default-tertiary, #737373)}.booking-datetime{display:flex;align-items:center;gap:4px;font-family:Brockmann,sans-serif;font-size:var(--font-size-xs);font-weight:400;line-height:1.2;letter-spacing:-.26px;color:var(--text-color-default-secondary, #545B66)}.booking-trailing{display:flex;align-items:center;color:var(--color-text-tertiary, #a3a3a3)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: DsIconComponent, selector: "ds-icon", inputs: ["name", "size", "color", "interactive"] }, { kind: "component", type: DsShapeIndicatorComponent, selector: "ds-shape-indicator", inputs: ["shape", "variant", "label"] }, { kind: "component", type: DsMobileListItemComponent, selector: "ds-mobile-list-item", inputs: ["leadingSize", "variant", "align", "flushTop", "interactive", "disabled", "loading", "enableLongPress", "showDesktopMoreButton", "moreActions", "moreButtonAriaLabel", "interactiveOffset", "title", "subtitle", "showDivider", "dividerSpacing"], outputs: ["itemClick", "moreButtonClick"] }, { kind: "component", type: DsMobileLoaderOverlayComponent, selector: "ds-mobile-loader-overlay", inputs: ["spinnerSize", "borderRadius"] }] });
17823
18247
  }
17824
18248
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DsMobileInteractiveListItemBookingComponent, decorators: [{
17825
18249
  type: Component,
@@ -17899,7 +18323,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
17899
18323
  </div>
17900
18324
  }
17901
18325
  </ds-mobile-list-item>
17902
- `, styles: [":host{display:block}:host:last-child{--divider-display: none;--item-padding-bottom: 0}.booking-thumbnail{position:relative;flex-shrink:0;width:64px;height:64px;border-radius:12px;overflow:hidden;background:var(--color-surface-secondary, #f5f5f5);display:flex;align-items:center;justify-content:center}.booking-thumbnail img{width:100%;height:100%;object-fit:cover}.booking-thumbnail-placeholder{width:100%;height:100%;display:flex;align-items:center;justify-content:center;color:var(--text-color-default-tertiary, #737373)}.booking-content{display:flex;flex-direction:column;gap:4px;flex:1;min-width:0}.booking-title{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm, 14px);font-weight:600;line-height:20px;letter-spacing:-.3px;color:var(--text-color-default-primary, #202227);margin:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.booking-description{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm, 14px);font-weight:400;line-height:20px;letter-spacing:-.3px;color:var(--text-color-default-secondary, #545B66);margin:0;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.booking-meta{font-family:Brockmann,sans-serif;font-size:var(--font-size-xs, 12px);font-weight:400;line-height:1.2;letter-spacing:-.26px;color:var(--text-color-default-secondary, #545B66);display:flex;align-items:center;gap:8px;margin-top:4px}.booking-status{display:flex;align-items:center;gap:6px;font-family:Brockmann,sans-serif;font-size:var(--font-size-xs);font-weight:500;line-height:1.2;letter-spacing:-.26px;color:var(--text-color-default-secondary, #545B66)}.booking-status.available-today{color:var(--color-accent, #5d5fef)}.booking-status.available-from{color:var(--color-warning, #f59e0b)}.booking-status.unavailable{color:var(--text-color-default-tertiary, #737373)}.booking-datetime{display:flex;align-items:center;gap:4px;font-family:Brockmann,sans-serif;font-size:var(--font-size-xs);font-weight:400;line-height:1.2;letter-spacing:-.26px;color:var(--text-color-default-secondary, #545B66)}.booking-trailing{display:flex;align-items:center;color:var(--color-text-tertiary, #a3a3a3)}\n"] }]
18326
+ `, styles: [":host{display:block}:host:first-child{--item-padding-top: 0}:host:last-child{--divider-display: none;--item-padding-bottom: 0}.booking-thumbnail{position:relative;flex-shrink:0;width:64px;height:64px;border-radius:12px;overflow:hidden;background:var(--color-surface-secondary, #f5f5f5);display:flex;align-items:center;justify-content:center}.booking-thumbnail img{width:100%;height:100%;object-fit:cover}.booking-thumbnail-placeholder{width:100%;height:100%;display:flex;align-items:center;justify-content:center;color:var(--text-color-default-tertiary, #737373)}.booking-content{display:flex;flex-direction:column;gap:4px;flex:1;min-width:0}.booking-title{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm, 14px);font-weight:600;line-height:20px;letter-spacing:-.3px;color:var(--text-color-default-primary, #202227);margin:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.booking-description{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm, 14px);font-weight:400;line-height:20px;letter-spacing:-.3px;color:var(--text-color-default-secondary, #545B66);margin:0;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.booking-meta{font-family:Brockmann,sans-serif;font-size:var(--font-size-xs, 12px);font-weight:400;line-height:1.2;letter-spacing:-.26px;color:var(--text-color-default-secondary, #545B66);display:flex;align-items:center;gap:8px;margin-top:4px}.booking-status{display:flex;align-items:center;gap:6px;font-family:Brockmann,sans-serif;font-size:var(--font-size-xs);font-weight:500;line-height:1.2;letter-spacing:-.26px;color:var(--text-color-default-secondary, #545B66)}.booking-status.available-today{color:var(--color-accent, #5d5fef)}.booking-status.available-from{color:var(--color-warning, #f59e0b)}.booking-status.unavailable{color:var(--text-color-default-tertiary, #737373)}.booking-datetime{display:flex;align-items:center;gap:4px;font-family:Brockmann,sans-serif;font-size:var(--font-size-xs);font-weight:400;line-height:1.2;letter-spacing:-.26px;color:var(--text-color-default-secondary, #545B66)}.booking-trailing{display:flex;align-items:center;color:var(--color-text-tertiary, #a3a3a3)}\n"] }]
17903
18327
  }], ctorParameters: () => [], propDecorators: { thumbnail: [{ type: i0.Input, args: [{ isSignal: true, alias: "thumbnail", required: false }] }], facilityTitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "facilityTitle", required: true }] }], description: [{ type: i0.Input, args: [{ isSignal: true, alias: "description", required: false }] }], bookingDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "bookingDate", required: false }] }], bookingTime: [{ type: i0.Input, args: [{ isSignal: true, alias: "bookingTime", required: false }] }], availabilityStatus: [{ type: i0.Input, args: [{ isSignal: true, alias: "availabilityStatus", required: false }] }], statusLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "statusLabel", required: false }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], align: [{ type: i0.Input, args: [{ isSignal: true, alias: "align", required: false }] }], clickable: [{ type: i0.Input, args: [{ isSignal: true, alias: "clickable", required: false }] }], showChevron: [{ type: i0.Input, args: [{ isSignal: true, alias: "showChevron", required: false }] }], enableLongPress: [{ type: i0.Input, args: [{ isSignal: true, alias: "enableLongPress", required: false }] }], moreActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "moreActions", required: false }] }], bookingClick: [{ type: i0.Output, args: ["bookingClick"] }], longPress: [{ type: i0.Output, args: ["longPress"] }] } });
17904
18328
 
17905
18329
  /**
@@ -21628,6 +22052,10 @@ class DsMobileNewInquiryModalComponent {
21628
22052
  * Label for the submit button
21629
22053
  */
21630
22054
  submitButtonLabel = 'Submit';
22055
+ /**
22056
+ * Pre-set category included in the emitted NewInquiryData (e.g. vendor id)
22057
+ */
22058
+ category;
21631
22059
  /**
21632
22060
  * Form title field
21633
22061
  */
@@ -21863,6 +22291,7 @@ class DsMobileNewInquiryModalComponent {
21863
22291
  title: this.title.trim(),
21864
22292
  description: this.description.trim(),
21865
22293
  attachments: this.attachments(),
22294
+ ...(this.category && { category: this.category }),
21866
22295
  };
21867
22296
  if (this.onSubmit) {
21868
22297
  await this.onSubmit(inquiryData);
@@ -21935,7 +22364,7 @@ class DsMobileNewInquiryModalComponent {
21935
22364
  return null;
21936
22365
  }
21937
22366
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DsMobileNewInquiryModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
21938
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: DsMobileNewInquiryModalComponent, isStandalone: true, selector: "ds-mobile-new-inquiry-modal", inputs: { loading: "loading", error: "error", onSubmit: "onSubmit", titlePlaceholder: "titlePlaceholder", descriptionPlaceholder: "descriptionPlaceholder", submitButtonLabel: "submitButtonLabel" }, viewQueries: [{ propertyName: "titleInputRef", first: true, predicate: ["titleInput"], descendants: true, read: ElementRef }, { propertyName: "descriptionInputRef", first: true, predicate: ["descriptionInput"], descendants: true, read: ElementRef }, { propertyName: "titleInput", first: true, predicate: ["titleInput"], descendants: true }, { propertyName: "fileInput", first: true, predicate: ["fileInput"], descendants: true }], ngImport: i0, template: `
22367
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: DsMobileNewInquiryModalComponent, isStandalone: true, selector: "ds-mobile-new-inquiry-modal", inputs: { loading: "loading", error: "error", onSubmit: "onSubmit", titlePlaceholder: "titlePlaceholder", descriptionPlaceholder: "descriptionPlaceholder", submitButtonLabel: "submitButtonLabel", category: "category" }, viewQueries: [{ propertyName: "titleInputRef", first: true, predicate: ["titleInput"], descendants: true, read: ElementRef }, { propertyName: "descriptionInputRef", first: true, predicate: ["descriptionInput"], descendants: true, read: ElementRef }, { propertyName: "titleInput", first: true, predicate: ["titleInput"], descendants: true }, { propertyName: "fileInput", first: true, predicate: ["fileInput"], descendants: true }], ngImport: i0, template: `
21939
22368
  <ds-mobile-modal-base [loading]="loading" [error]="error" [showHeader]="false" [hasFixedBottom]="true" [enableKeyboardHandling]="true" [keyboardContentBehavior]="'overlay'" closeButtonLabel="Close" [onCloseRequest]="handleCloseRequest">
21940
22369
  <!-- Form Content -->
21941
22370
  <ds-mobile-section>
@@ -22143,6 +22572,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
22143
22572
  type: Input
22144
22573
  }], submitButtonLabel: [{
22145
22574
  type: Input
22575
+ }], category: [{
22576
+ type: Input
22146
22577
  }] } });
22147
22578
 
22148
22579
  /**
@@ -22197,6 +22628,7 @@ class DsMobileNewInquiryModalService extends BaseModalService {
22197
22628
  ...(options?.titlePlaceholder && { titlePlaceholder: options.titlePlaceholder }),
22198
22629
  ...(options?.descriptionPlaceholder && { descriptionPlaceholder: options.descriptionPlaceholder }),
22199
22630
  ...(options?.submitButtonLabel && { submitButtonLabel: options.submitButtonLabel }),
22631
+ ...(options?.category && { category: options.category }),
22200
22632
  }, {
22201
22633
  keyboardClose: false, // Don't close on keyboard hide for this modal
22202
22634
  });
@@ -28947,6 +29379,267 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
28947
29379
  args: ['pageComponent']
28948
29380
  }] } });
28949
29381
 
29382
+ class DsMobileInteractiveListItemServiceComponent {
29383
+ title = input.required(...(ngDevMode ? [{ debugName: "title" }] : []));
29384
+ description = input('', ...(ngDevMode ? [{ debugName: "description" }] : []));
29385
+ logo = input('', ...(ngDevMode ? [{ debugName: "logo" }] : []));
29386
+ showChevron = input(false, ...(ngDevMode ? [{ debugName: "showChevron" }] : []));
29387
+ serviceClick = output();
29388
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DsMobileInteractiveListItemServiceComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
29389
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: DsMobileInteractiveListItemServiceComponent, isStandalone: true, selector: "ds-mobile-interactive-list-item-service", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: true, transformFunction: null }, description: { classPropertyName: "description", publicName: "description", isSignal: true, isRequired: false, transformFunction: null }, logo: { classPropertyName: "logo", publicName: "logo", isSignal: true, isRequired: false, transformFunction: null }, showChevron: { classPropertyName: "showChevron", publicName: "showChevron", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { serviceClick: "serviceClick" }, ngImport: i0, template: `
29390
+ <ds-mobile-list-item
29391
+ [leadingSize]="'32px'"
29392
+ [align]="'top'"
29393
+ [interactive]="true"
29394
+ [enableLongPress]="false"
29395
+ (itemClick)="serviceClick.emit()">
29396
+
29397
+ <div content-leading>
29398
+ <ds-mobile-vendor-avatar
29399
+ [name]="title()"
29400
+ [logo]="logo()"
29401
+ size="md" />
29402
+ </div>
29403
+
29404
+ <div content-main>
29405
+ <div class="service-content">
29406
+ <h3 class="service-title">{{ title() }}</h3>
29407
+ @if (description()) {
29408
+ <p class="service-description">{{ description() }}</p>
29409
+ }
29410
+ </div>
29411
+ </div>
29412
+
29413
+ @if (showChevron()) {
29414
+ <div content-trailing>
29415
+ <div class="service-trailing">
29416
+ <ds-icon name="remixArrowRightSLine" size="20px" />
29417
+ </div>
29418
+ </div>
29419
+ }
29420
+ </ds-mobile-list-item>
29421
+ `, isInline: true, styles: [":host{display:block}:host:first-child{--item-padding-top: 0}:host:last-child{--divider-display: none;--item-padding-bottom: 0}.service-content{display:flex;flex-direction:column;gap:2px;flex:1;min-width:0}.service-title{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm, 14px);font-weight:600;line-height:20px;letter-spacing:-.3px;color:var(--text-color-default-primary, #202227);margin:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.service-description{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm, 14px);font-weight:400;line-height:20px;letter-spacing:-.3px;color:var(--text-color-default-secondary, #545B66);margin:0;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.service-trailing{display:flex;align-items:center;color:var(--color-text-tertiary, #a3a3a3)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: DsIconComponent, selector: "ds-icon", inputs: ["name", "size", "color", "interactive"] }, { kind: "component", type: DsMobileListItemComponent, selector: "ds-mobile-list-item", inputs: ["leadingSize", "variant", "align", "flushTop", "interactive", "disabled", "loading", "enableLongPress", "showDesktopMoreButton", "moreActions", "moreButtonAriaLabel", "interactiveOffset", "title", "subtitle", "showDivider", "dividerSpacing"], outputs: ["itemClick", "moreButtonClick"] }, { kind: "component", type: DsMobileVendorAvatarComponent, selector: "ds-mobile-vendor-avatar", inputs: ["name", "logo", "size"] }] });
29422
+ }
29423
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DsMobileInteractiveListItemServiceComponent, decorators: [{
29424
+ type: Component,
29425
+ args: [{ selector: 'ds-mobile-interactive-list-item-service', standalone: true, imports: [CommonModule, DsIconComponent, DsMobileListItemComponent, DsMobileVendorAvatarComponent], template: `
29426
+ <ds-mobile-list-item
29427
+ [leadingSize]="'32px'"
29428
+ [align]="'top'"
29429
+ [interactive]="true"
29430
+ [enableLongPress]="false"
29431
+ (itemClick)="serviceClick.emit()">
29432
+
29433
+ <div content-leading>
29434
+ <ds-mobile-vendor-avatar
29435
+ [name]="title()"
29436
+ [logo]="logo()"
29437
+ size="md" />
29438
+ </div>
29439
+
29440
+ <div content-main>
29441
+ <div class="service-content">
29442
+ <h3 class="service-title">{{ title() }}</h3>
29443
+ @if (description()) {
29444
+ <p class="service-description">{{ description() }}</p>
29445
+ }
29446
+ </div>
29447
+ </div>
29448
+
29449
+ @if (showChevron()) {
29450
+ <div content-trailing>
29451
+ <div class="service-trailing">
29452
+ <ds-icon name="remixArrowRightSLine" size="20px" />
29453
+ </div>
29454
+ </div>
29455
+ }
29456
+ </ds-mobile-list-item>
29457
+ `, styles: [":host{display:block}:host:first-child{--item-padding-top: 0}:host:last-child{--divider-display: none;--item-padding-bottom: 0}.service-content{display:flex;flex-direction:column;gap:2px;flex:1;min-width:0}.service-title{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm, 14px);font-weight:600;line-height:20px;letter-spacing:-.3px;color:var(--text-color-default-primary, #202227);margin:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.service-description{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm, 14px);font-weight:400;line-height:20px;letter-spacing:-.3px;color:var(--text-color-default-secondary, #545B66);margin:0;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.service-trailing{display:flex;align-items:center;color:var(--color-text-tertiary, #a3a3a3)}\n"] }]
29458
+ }], propDecorators: { title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: true }] }], description: [{ type: i0.Input, args: [{ isSignal: true, alias: "description", required: false }] }], logo: [{ type: i0.Input, args: [{ isSignal: true, alias: "logo", required: false }] }], showChevron: [{ type: i0.Input, args: [{ isSignal: true, alias: "showChevron", required: false }] }], serviceClick: [{ type: i0.Output, args: ["serviceClick"] }] } });
29459
+
29460
+ class DsMobileServiceVendorSheetComponent {
29461
+ vendorName;
29462
+ vendorDescription = '';
29463
+ vendorImage = '';
29464
+ vendorLogo = '';
29465
+ bookButtonLabel = 'Book';
29466
+ modalController = inject(ModalController);
29467
+ async handleBook() {
29468
+ await this.modalController.dismiss(null, 'book');
29469
+ }
29470
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DsMobileServiceVendorSheetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
29471
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: DsMobileServiceVendorSheetComponent, isStandalone: true, selector: "ds-mobile-service-vendor-sheet", inputs: { vendorName: "vendorName", vendorDescription: "vendorDescription", vendorImage: "vendorImage", vendorLogo: "vendorLogo", bookButtonLabel: "bookButtonLabel" }, ngImport: i0, template: `
29472
+ <ds-mobile-modal-base
29473
+ [headerTitle]="vendorName"
29474
+ [showHeader]="true"
29475
+ [hasFixedBottom]="true">
29476
+
29477
+ <ds-mobile-vendor-avatar
29478
+ header-leading
29479
+ [name]="vendorName"
29480
+ [logo]="vendorLogo"
29481
+ size="md" />
29482
+
29483
+ <ds-mobile-section [showBorder]="false" padding="20px 20px 0 20px">
29484
+ @if (vendorImage) {
29485
+ <div class="hero-image-container">
29486
+ <img class="hero-image" [src]="vendorImage" [alt]="vendorName" />
29487
+ </div>
29488
+ } @else {
29489
+ <div class="hero-empty-state">
29490
+ <ds-mobile-vendor-avatar
29491
+ [name]="vendorName"
29492
+ [logo]="vendorLogo"
29493
+ size="xl" />
29494
+ </div>
29495
+ }
29496
+ </ds-mobile-section>
29497
+
29498
+ <ds-mobile-section padding="20px 20px 20px 20px">
29499
+ @if (vendorDescription) {
29500
+ <div class="vendor-description" [innerHTML]="vendorDescription"></div>
29501
+ }
29502
+ </ds-mobile-section>
29503
+
29504
+ <div fixed-bottom>
29505
+ <div class="booking-action">
29506
+ <ds-button
29507
+ size="md"
29508
+ variant="primary"
29509
+ [fullWidth]="true"
29510
+ (clicked)="handleBook()">
29511
+ {{ bookButtonLabel }}
29512
+ </ds-button>
29513
+ </div>
29514
+ </div>
29515
+ </ds-mobile-modal-base>
29516
+ `, isInline: true, styles: [".hero-image-container{width:100%;aspect-ratio:16 / 9;border-radius:12px;overflow:hidden;background:var(--color-surface-secondary, #f5f5f5)}.hero-image{width:100%;height:100%;object-fit:cover;display:block}.hero-empty-state{width:100%;aspect-ratio:16 / 9;border-radius:12px;background:var(--color-background-neutral-secondary, #f5f5f5);display:flex;align-items:center;justify-content:center}.vendor-description{font-family:Brockmann,sans-serif;font-size:var(--font-size-base, 16px);line-height:1.6;color:var(--text-color-default-primary, #202227)}::ng-deep .vendor-description p{margin:12px 0 0}::ng-deep .vendor-description p:first-child,::ng-deep .vendor-description h3+p{margin-top:0}::ng-deep .vendor-description h3{font-family:Brockmann,sans-serif;font-size:var(--font-size-lg, 18px);font-weight:600;line-height:1.4;color:var(--text-color-default-primary, #202227);margin:0!important;padding:24px 0 8px!important;display:block}::ng-deep .vendor-description h3:first-child{padding-top:0!important}::ng-deep .vendor-description ul{list-style:disc;padding-left:20px;margin:0 0 12px}::ng-deep .vendor-description ul li{font-family:Brockmann,sans-serif;font-size:var(--font-size-base, 16px);line-height:1.6;color:var(--text-color-default-primary, #202227);margin-top:4px}::ng-deep .vendor-description ul li:first-child{margin-top:0}.booking-action{padding:16px 20px;background:var(--color-surface-primary, #ffffff);border-top:1px solid var(--color-border, #e5e5e5)}.booking-action ::ng-deep ds-button{display:block;width:100%}.booking-action ::ng-deep ds-button button{width:100%;border-radius:100px;height:44px;min-height:44px;max-height:44px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: DsButtonComponent, selector: "ds-button", inputs: ["variant", "size", "disabled", "loading", "pressed", "expanded", "leadingIcon", "trailingIcon", "ariaLabel", "iconOnly"], outputs: ["clicked", "focused", "blurred"] }, { kind: "component", type: DsMobileModalBaseComponent, selector: "ds-mobile-modal-base", inputs: ["headerTitleInteractive", "showHeader"], outputs: ["titleClick"] }, { kind: "component", type: DsMobileSectionComponent, selector: "ds-mobile-section", inputs: ["headline", "icon", "linkText", "padding", "paddingDesktop", "gap", "contentGap", "showBorder", "overflow"], outputs: ["linkClick"] }, { kind: "component", type: DsMobileVendorAvatarComponent, selector: "ds-mobile-vendor-avatar", inputs: ["name", "logo", "size"] }] });
29517
+ }
29518
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DsMobileServiceVendorSheetComponent, decorators: [{
29519
+ type: Component,
29520
+ args: [{ selector: 'ds-mobile-service-vendor-sheet', standalone: true, imports: [
29521
+ CommonModule,
29522
+ DsButtonComponent,
29523
+ DsMobileModalBaseComponent,
29524
+ DsMobileSectionComponent,
29525
+ DsMobileVendorAvatarComponent,
29526
+ ], schemas: [CUSTOM_ELEMENTS_SCHEMA], template: `
29527
+ <ds-mobile-modal-base
29528
+ [headerTitle]="vendorName"
29529
+ [showHeader]="true"
29530
+ [hasFixedBottom]="true">
29531
+
29532
+ <ds-mobile-vendor-avatar
29533
+ header-leading
29534
+ [name]="vendorName"
29535
+ [logo]="vendorLogo"
29536
+ size="md" />
29537
+
29538
+ <ds-mobile-section [showBorder]="false" padding="20px 20px 0 20px">
29539
+ @if (vendorImage) {
29540
+ <div class="hero-image-container">
29541
+ <img class="hero-image" [src]="vendorImage" [alt]="vendorName" />
29542
+ </div>
29543
+ } @else {
29544
+ <div class="hero-empty-state">
29545
+ <ds-mobile-vendor-avatar
29546
+ [name]="vendorName"
29547
+ [logo]="vendorLogo"
29548
+ size="xl" />
29549
+ </div>
29550
+ }
29551
+ </ds-mobile-section>
29552
+
29553
+ <ds-mobile-section padding="20px 20px 20px 20px">
29554
+ @if (vendorDescription) {
29555
+ <div class="vendor-description" [innerHTML]="vendorDescription"></div>
29556
+ }
29557
+ </ds-mobile-section>
29558
+
29559
+ <div fixed-bottom>
29560
+ <div class="booking-action">
29561
+ <ds-button
29562
+ size="md"
29563
+ variant="primary"
29564
+ [fullWidth]="true"
29565
+ (clicked)="handleBook()">
29566
+ {{ bookButtonLabel }}
29567
+ </ds-button>
29568
+ </div>
29569
+ </div>
29570
+ </ds-mobile-modal-base>
29571
+ `, styles: [".hero-image-container{width:100%;aspect-ratio:16 / 9;border-radius:12px;overflow:hidden;background:var(--color-surface-secondary, #f5f5f5)}.hero-image{width:100%;height:100%;object-fit:cover;display:block}.hero-empty-state{width:100%;aspect-ratio:16 / 9;border-radius:12px;background:var(--color-background-neutral-secondary, #f5f5f5);display:flex;align-items:center;justify-content:center}.vendor-description{font-family:Brockmann,sans-serif;font-size:var(--font-size-base, 16px);line-height:1.6;color:var(--text-color-default-primary, #202227)}::ng-deep .vendor-description p{margin:12px 0 0}::ng-deep .vendor-description p:first-child,::ng-deep .vendor-description h3+p{margin-top:0}::ng-deep .vendor-description h3{font-family:Brockmann,sans-serif;font-size:var(--font-size-lg, 18px);font-weight:600;line-height:1.4;color:var(--text-color-default-primary, #202227);margin:0!important;padding:24px 0 8px!important;display:block}::ng-deep .vendor-description h3:first-child{padding-top:0!important}::ng-deep .vendor-description ul{list-style:disc;padding-left:20px;margin:0 0 12px}::ng-deep .vendor-description ul li{font-family:Brockmann,sans-serif;font-size:var(--font-size-base, 16px);line-height:1.6;color:var(--text-color-default-primary, #202227);margin-top:4px}::ng-deep .vendor-description ul li:first-child{margin-top:0}.booking-action{padding:16px 20px;background:var(--color-surface-primary, #ffffff);border-top:1px solid var(--color-border, #e5e5e5)}.booking-action ::ng-deep ds-button{display:block;width:100%}.booking-action ::ng-deep ds-button button{width:100%;border-radius:100px;height:44px;min-height:44px;max-height:44px}\n"] }]
29572
+ }], propDecorators: { vendorName: [{
29573
+ type: Input,
29574
+ args: [{ required: true }]
29575
+ }], vendorDescription: [{
29576
+ type: Input
29577
+ }], vendorImage: [{
29578
+ type: Input
29579
+ }], vendorLogo: [{
29580
+ type: Input
29581
+ }], bookButtonLabel: [{
29582
+ type: Input
29583
+ }] } });
29584
+ class DsMobileServiceVendorModalService extends BaseModalService {
29585
+ constructor(modalController) {
29586
+ super(modalController);
29587
+ }
29588
+ async open(props) {
29589
+ const modal = await this.createModal(DsMobileServiceVendorSheetComponent, props);
29590
+ await modal.present();
29591
+ return modal;
29592
+ }
29593
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DsMobileServiceVendorModalService, deps: [{ token: i1.ModalController }], target: i0.ɵɵFactoryTarget.Injectable });
29594
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DsMobileServiceVendorModalService, providedIn: 'root' });
29595
+ }
29596
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DsMobileServiceVendorModalService, decorators: [{
29597
+ type: Injectable,
29598
+ args: [{ providedIn: 'root' }]
29599
+ }], ctorParameters: () => [{ type: i1.ModalController }] });
29600
+
29601
+ class InquiriesService {
29602
+ inquiries = signal([
29603
+ {
29604
+ id: '1',
29605
+ title: 'Tørretumbler virker ikke',
29606
+ description: 'I de sidste tre dage har jeg oplevet vedvarende problemer med tørretumbleren. Den starter, men stopper efter få minutter.',
29607
+ status: 'open',
29608
+ timestamp: '12 dage siden',
29609
+ category: 'appliance',
29610
+ },
29611
+ {
29612
+ id: '2',
29613
+ title: 'Problem med vandtryk',
29614
+ description: 'Lavt vandtryk i badeværelseshåndvasken. Det er blevet gradvist værre i løbet af den sidste uge.',
29615
+ status: 'open',
29616
+ timestamp: '5 dage siden',
29617
+ category: 'plumbing',
29618
+ },
29619
+ {
29620
+ id: '3',
29621
+ title: 'Varme virker ikke ordentligt',
29622
+ description: 'Varmesystemet holder ikke den indstillede temperatur. Lejligheden er meget koldere, end den burde være.',
29623
+ status: 'closed',
29624
+ timestamp: '2 måneder siden',
29625
+ category: 'heating',
29626
+ },
29627
+ ], ...(ngDevMode ? [{ debugName: "inquiries" }] : []));
29628
+ openInquiries = computed(() => this.inquiries().filter(i => i.status === 'open'), ...(ngDevMode ? [{ debugName: "openInquiries" }] : []));
29629
+ getById(id) {
29630
+ return this.inquiries().find(i => i.id === id);
29631
+ }
29632
+ addInquiry(inquiry) {
29633
+ this.inquiries.update(list => [inquiry, ...list]);
29634
+ }
29635
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: InquiriesService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
29636
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: InquiriesService, providedIn: 'root' });
29637
+ }
29638
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: InquiriesService, decorators: [{
29639
+ type: Injectable,
29640
+ args: [{ providedIn: 'root' }]
29641
+ }] });
29642
+
28950
29643
  /**
28951
29644
  * PageLoadingService
28952
29645
  *
@@ -29238,36 +29931,18 @@ class MobileHomePageComponent {
29238
29931
  recentPosts = computed(() => this.postsService.posts()
29239
29932
  .filter(post => post.id !== 'post-4') // Exclude pinned post
29240
29933
  .slice(0, 3), ...(ngDevMode ? [{ debugName: "recentPosts" }] : []));
29241
- // Mock inquiry data
29242
- allInquiries = signal([
29243
- {
29244
- id: '1',
29245
- title: 'Tørretumbler virker ikke',
29246
- description: 'I de sidste tre dage har jeg oplevet vedvarende problemer med tørretumbleren. Den starter, men stopper efter få minutter.',
29247
- status: 'open',
29248
- timestamp: '12 dage siden'
29249
- },
29250
- {
29251
- id: '2',
29252
- title: 'Problem med vandtryk',
29253
- description: 'Lavt vandtryk i badeværelseshåndvasken. Det er blevet gradvist værre i løbet af den sidste uge.',
29254
- status: 'open',
29255
- timestamp: '5 dage siden'
29256
- },
29257
- {
29258
- id: '3',
29259
- title: 'Varme virker ikke ordentligt',
29260
- description: 'Varmesystemet holder ikke den indstillede temperatur. Lejligheden er meget koldere, end den burde være.',
29261
- status: 'closed',
29262
- timestamp: '2 måneder siden'
29263
- }
29264
- ], ...(ngDevMode ? [{ debugName: "allInquiries" }] : []));
29265
- // Filter for open inquiries and limit to 3
29266
- openInquiries = computed(() => this.allInquiries()
29267
- .filter(inquiry => inquiry.status === 'open')
29268
- .slice(0, 3), ...(ngDevMode ? [{ debugName: "openInquiries" }] : []));
29934
+ inquiriesService = inject(InquiriesService);
29935
+ openInquiries = computed(() => this.inquiriesService.openInquiries().slice(0, 3), ...(ngDevMode ? [{ debugName: "openInquiries" }] : []));
29269
29936
  recentPeerMessages = computed(() => this.peerMessaging.conversations().slice(0, 3), ...(ngDevMode ? [{ debugName: "recentPeerMessages" }] : []));
29937
+ allVendors = signal([
29938
+ { id: 'v-1', name: 'CleanTeam ApS', category: 'Rengøring', description: 'Trappevask og vinduespolering', phone: '+45 70 20 30 40', logo: '/Assets/dummy-logos/cleanteam-logo.svg', thumbnail: '/Assets/Dummy-photos/clean-team.jpg', fullDescription: '<h3>Rengøring</h3><p>CleanTeam ApS tilbyder professionel trappevask og vinduespolering for ejendommen. Servicen udføres ugentligt og kan tilpasses jeres behov.</p><h3>Pris</h3><p>350 kr. per besøg</p>' },
29939
+ { id: 'v-3', name: 'Blik Partner A/S', category: 'VVS', description: 'VVS-service og akut udkald', phone: '+45 33 44 55 66', thumbnail: '/Assets/Dummy-photos/plumbing.jpg', fullDescription: '<h3>VVS</h3><p>BlikPartner A/S er jeres VVS-partner til alt fra løbende vedligeholdelse til akutte udkald. Vi dækker reparation af vandrør, afløb, radiatorer og blandingsbatterier.</p><h3>Pris</h3><p>450 kr. per udkald + tid</p>' },
29940
+ { id: 'v-4', name: 'ElektroTek ApS', category: 'Elektriker', description: 'El-installationer og fejlsøgning', phone: '+45 23 45 67 89', logo: '/Assets/dummy-logos/electrician-logo.svg', thumbnail: '/Assets/Dummy-photos/electrician.jpg', heroImage: '/Assets/Dummy-photos/electrician.jpg', fullDescription: '<h3>Elektriker</h3><p>ElektroTek ApS varetager el-installationer, fejlsøgning og lovpligtige eftersyn for ejendommen. Vi udfører også småopgaver som udskiftning af kontakter og lampeudtag.</p><h3>Pris</h3><p>395 kr. per time</p>' },
29941
+ ], ...(ngDevMode ? [{ debugName: "allVendors" }] : []));
29942
+ previewVendors = computed(() => this.allVendors().slice(0, 3), ...(ngDevMode ? [{ debugName: "previewVendors" }] : []));
29270
29943
  modalCtrl = inject(ModalController);
29944
+ vendorModal = inject(DsMobileServiceVendorModalService);
29945
+ newInquiryModal = inject(DsMobileNewInquiryModalService);
29271
29946
  constructor(router, navCtrl, userService, postsService, postModal, trackingPermissionService, bottomSheet, familyAccessService, peerMessaging, peerChat) {
29272
29947
  this.router = router;
29273
29948
  this.navCtrl = navCtrl;
@@ -29346,6 +30021,48 @@ class MobileHomePageComponent {
29346
30021
  });
29347
30022
  await modal.present();
29348
30023
  }
30024
+ navigateToServices() {
30025
+ void this.navCtrl.navigateForward(['/services'], { animation: customPageTransition });
30026
+ }
30027
+ async openVendorSheet(vendor) {
30028
+ const modal = await this.vendorModal.open({
30029
+ vendorName: vendor.name,
30030
+ vendorDescription: vendor.fullDescription || vendor.description || '',
30031
+ vendorImage: vendor.heroImage || '',
30032
+ vendorLogo: vendor.logo,
30033
+ });
30034
+ const result = await modal.onWillDismiss();
30035
+ if (result.role === 'book') {
30036
+ await this.openInquiryForVendor(vendor);
30037
+ }
30038
+ }
30039
+ async openInquiryForVendor(vendor) {
30040
+ await this.newInquiryModal.open({
30041
+ titlePlaceholder: 'Emne for henvendelsen',
30042
+ descriptionPlaceholder: 'Beskriv hvad du har brug for…',
30043
+ submitButtonLabel: 'Send henvendelse',
30044
+ category: vendor.category,
30045
+ onSubmit: async (data) => {
30046
+ const inquiryId = `service-${Date.now()}`;
30047
+ this.inquiriesService.addInquiry({
30048
+ id: inquiryId,
30049
+ title: data.title,
30050
+ description: data.description,
30051
+ status: 'open',
30052
+ timestamp: 'Lige nu',
30053
+ category: data.category || vendor.category,
30054
+ vendorName: vendor.name,
30055
+ vendorLogo: vendor.logo,
30056
+ });
30057
+ await this.newInquiryModal.close();
30058
+ setTimeout(() => {
30059
+ this.navCtrl.navigateForward([`/inquiry-detail/${inquiryId}`], {
30060
+ animation: customPageTransition,
30061
+ });
30062
+ }, 300);
30063
+ },
30064
+ });
30065
+ }
29349
30066
  navigateToMessages() {
29350
30067
  void this.navCtrl.navigateForward(['/messages'], { animation: customPageTransition });
29351
30068
  }
@@ -29525,6 +30242,24 @@ class MobileHomePageComponent {
29525
30242
  </div>
29526
30243
  </ds-mobile-section>
29527
30244
 
30245
+ <!-- Services preview -->
30246
+ @if (previewVendors().length > 0) {
30247
+ <ds-mobile-section
30248
+ headline="Services"
30249
+ linkText="Se alle"
30250
+ contentGap="0px"
30251
+ (linkClick)="navigateToServices()">
30252
+ @for (vendor of previewVendors(); track vendor.id) {
30253
+ <ds-mobile-interactive-list-item-service
30254
+ [title]="vendor.name"
30255
+ [description]="vendor.description || ''"
30256
+ [logo]="vendor.logo || ''"
30257
+ (serviceClick)="openVendorSheet(vendor)"
30258
+ />
30259
+ }
30260
+ </ds-mobile-section>
30261
+ }
30262
+
29528
30263
  <!-- Recent Community Posts Section (empty state) -->
29529
30264
  <ds-mobile-section>
29530
30265
  <div class="empty-state">
@@ -29582,7 +30317,7 @@ class MobileHomePageComponent {
29582
30317
  </ds-mobile-page-main>
29583
30318
  } <!-- end @if (!isCoveringScreen()) -->
29584
30319
 
29585
- `, isInline: true, styles: [".posts-list,.messages-preview-list{display:flex;flex-direction:column}.property-banner-nav{display:block;width:100%;border-radius:12px;cursor:pointer;-webkit-tap-highlight-color:transparent}.property-banner-nav:focus-visible{outline:2px solid var(--color-accent, #6B5FF5);outline-offset:2px}.inquiries-list{display:flex;flex-direction:column}.empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:20px;text-align:center}.empty-state ds-button{display:block;margin-top:16px}.empty-state ds-button::ng-deep .btn{width:100%;border-radius:9999px}.empty-state-title{font-family:Brockmann,sans-serif;font-size:var(--font-size-base);font-weight:600;color:var(--color-text-primary);margin-top:-16px;z-index:4}.empty-state-description{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);color:var(--color-text-secondary);margin:0}@keyframes slideDown{0%{transform:translateY(-100%);opacity:0}to{transform:translateY(0);opacity:1}}.welcome-toast{padding:10px 14px;border-radius:12px;background:var(--color-background-brand-secondary, #EEF0FF);display:flex;align-items:flex-start;gap:10px;font-size:14px;font-weight:500;color:var(--color-accent, #6B5FF5);animation:slideDown .2s ease-out}.toast-icon{width:20px;height:20px;border-radius:50%;background:var(--color-accent, #6B5FF5);display:flex;align-items:center;justify-content:center;flex-shrink:0;color:#fff;margin-top:1px}.welcome-toast-content{flex:1;display:flex;flex-direction:column;gap:2px}.welcome-toast-heading{font-family:Brockmann,sans-serif;font-size:14px;font-weight:600;color:var(--color-brand-content, #3B3691);margin:0}.welcome-toast-text{font-family:Brockmann,sans-serif;font-size:13px;line-height:1.4;color:var(--color-brand-content, #3B3691);margin:0;opacity:.8}.welcome-toast-text strong{font-weight:600;opacity:1}.toast-dismiss{margin-left:auto;background:none;border:none;cursor:pointer;flex-shrink:0;color:var(--color-accent, #6B5FF5);display:flex;align-items:center;justify-content:center}.home-content--animating{animation:homeReveal .3s var(--spring-curve-smooth) both}@keyframes homeReveal{0%{opacity:0;transform:translateY(128px)}to{opacity:1;transform:translateY(0)}}\n"], dependencies: [{ kind: "component", type: DsButtonComponent, selector: "ds-button", inputs: ["variant", "size", "disabled", "loading", "pressed", "expanded", "leadingIcon", "trailingIcon", "ariaLabel", "iconOnly"], outputs: ["clicked", "focused", "blurred"] }, { kind: "component", type: DsIconComponent, selector: "ds-icon", inputs: ["name", "size", "color", "interactive"] }, { kind: "component", type: DsMobilePageMainComponent, selector: "ds-mobile-page-main", inputs: ["title", "headerTitle", "headerSubtitle", "firstEntry", "avatarType", "avatarInitials", "avatarSrc", "avatarIconName", "showRefresh", "showCondensedHeader", "scrollThreshold", "headerFadeDistance", "contentPadding", "profileMenuItems"], outputs: ["avatarClick", "profileActionSelected", "refresh", "scroll"] }, { kind: "component", type: DsMobileSectionComponent, selector: "ds-mobile-section", inputs: ["headline", "icon", "linkText", "padding", "paddingDesktop", "gap", "contentGap", "showBorder", "overflow"], outputs: ["linkClick"] }, { kind: "component", type: DsMobileIllustrationComponent, selector: "ds-mobile-illustration", inputs: ["variant", "size", "alt"] }, { kind: "component", type: DsMobilePropertyBannerComponent, selector: "ds-mobile-property-banner", inputs: ["address", "photoUrl", "tenantCount"] }, { kind: "component", type: DsMobileInteractiveListItemPostComponent, selector: "ds-mobile-interactive-list-item-post", inputs: ["authorName", "authorRole", "timestamp", "avatarInitials", "avatarType", "avatarSrc", "avatarIconName", "showBadge", "variant", "align", "clickable", "enableLongPress", "moreActions"], outputs: ["postClick", "commentClick", "longPress"] }, { kind: "component", type: DsMobileInteractiveListItemInquiryComponent, selector: "ds-mobile-interactive-list-item-inquiry", inputs: ["title", "description", "status", "statusLabel", "timestamp", "iconName", "iconColor", "variant", "align", "clickable", "showChevron", "enableLongPress", "moreActions"], outputs: ["inquiryClick", "longPress"] }, { kind: "component", type: DsMobileInteractiveListItemMessageComponent, selector: "ds-mobile-interactive-list-item-message", inputs: ["senderName", "senderRole", "timestamp", "message", "avatarInitials", "avatarType", "avatarSrc", "unread", "clickable", "align", "showAvatarBadge", "groupStackMembers", "groupCustomAvatarUrl", "groupStackExcludeParticipantId"], outputs: ["messageClick", "longPress"] }, { kind: "component", type: DsMobileOfflineBannerComponent, selector: "ds-mobile-offline-banner", inputs: ["icon", "title", "message"] }, { kind: "component", type: PostContentComponent, selector: "post-content" }, { kind: "component", type: PostTextComponent, selector: "post-text" }, { kind: "component", type: PostActionsComponent, selector: "post-actions" }, { kind: "component", type: ActionLikeComponent, selector: "action-like", inputs: ["active", "count"], outputs: ["activeChange", "countChange", "likeClick"] }, { kind: "component", type: ActionCommentComponent, selector: "action-comment", inputs: ["count"], outputs: ["commentClick"] }] });
30320
+ `, isInline: true, styles: [".posts-list,.messages-preview-list{display:flex;flex-direction:column}.property-banner-nav{display:block;width:100%;border-radius:12px;cursor:pointer;-webkit-tap-highlight-color:transparent}.property-banner-nav:focus-visible{outline:2px solid var(--color-accent, #6B5FF5);outline-offset:2px}.inquiries-list,.services-preview-list{display:flex;flex-direction:column}.empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:20px;text-align:center}.empty-state ds-button{display:block;margin-top:16px}.empty-state ds-button::ng-deep .btn{width:100%;border-radius:9999px}.empty-state-title{font-family:Brockmann,sans-serif;font-size:var(--font-size-base);font-weight:600;color:var(--color-text-primary);margin-top:-16px;z-index:4}.empty-state-description{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);color:var(--color-text-secondary);margin:0}@keyframes slideDown{0%{transform:translateY(-100%);opacity:0}to{transform:translateY(0);opacity:1}}.welcome-toast{padding:10px 14px;border-radius:12px;background:var(--color-background-brand-secondary, #EEF0FF);display:flex;align-items:flex-start;gap:10px;font-size:14px;font-weight:500;color:var(--color-accent, #6B5FF5);animation:slideDown .2s ease-out}.toast-icon{width:20px;height:20px;border-radius:50%;background:var(--color-accent, #6B5FF5);display:flex;align-items:center;justify-content:center;flex-shrink:0;color:#fff;margin-top:1px}.welcome-toast-content{flex:1;display:flex;flex-direction:column;gap:2px}.welcome-toast-heading{font-family:Brockmann,sans-serif;font-size:14px;font-weight:600;color:var(--color-brand-content, #3B3691);margin:0}.welcome-toast-text{font-family:Brockmann,sans-serif;font-size:13px;line-height:1.4;color:var(--color-brand-content, #3B3691);margin:0;opacity:.8}.welcome-toast-text strong{font-weight:600;opacity:1}.toast-dismiss{margin-left:auto;background:none;border:none;cursor:pointer;flex-shrink:0;color:var(--color-accent, #6B5FF5);display:flex;align-items:center;justify-content:center}.home-content--animating{animation:homeReveal .3s var(--spring-curve-smooth) both}@keyframes homeReveal{0%{opacity:0;transform:translateY(128px)}to{opacity:1;transform:translateY(0)}}\n"], dependencies: [{ kind: "component", type: DsButtonComponent, selector: "ds-button", inputs: ["variant", "size", "disabled", "loading", "pressed", "expanded", "leadingIcon", "trailingIcon", "ariaLabel", "iconOnly"], outputs: ["clicked", "focused", "blurred"] }, { kind: "component", type: DsIconComponent, selector: "ds-icon", inputs: ["name", "size", "color", "interactive"] }, { kind: "component", type: DsMobilePageMainComponent, selector: "ds-mobile-page-main", inputs: ["title", "headerTitle", "headerSubtitle", "firstEntry", "avatarType", "avatarInitials", "avatarSrc", "avatarIconName", "showRefresh", "showCondensedHeader", "scrollThreshold", "headerFadeDistance", "contentPadding", "profileMenuItems"], outputs: ["avatarClick", "profileActionSelected", "refresh", "scroll"] }, { kind: "component", type: DsMobileSectionComponent, selector: "ds-mobile-section", inputs: ["headline", "icon", "linkText", "padding", "paddingDesktop", "gap", "contentGap", "showBorder", "overflow"], outputs: ["linkClick"] }, { kind: "component", type: DsMobileIllustrationComponent, selector: "ds-mobile-illustration", inputs: ["variant", "size", "alt"] }, { kind: "component", type: DsMobilePropertyBannerComponent, selector: "ds-mobile-property-banner", inputs: ["address", "photoUrl", "tenantCount"] }, { kind: "component", type: DsMobileInteractiveListItemPostComponent, selector: "ds-mobile-interactive-list-item-post", inputs: ["authorName", "authorRole", "timestamp", "avatarInitials", "avatarType", "avatarSrc", "avatarIconName", "showBadge", "variant", "align", "clickable", "enableLongPress", "moreActions"], outputs: ["postClick", "commentClick", "longPress"] }, { kind: "component", type: DsMobileInteractiveListItemInquiryComponent, selector: "ds-mobile-interactive-list-item-inquiry", inputs: ["title", "description", "status", "statusLabel", "timestamp", "iconName", "iconColor", "variant", "align", "clickable", "showChevron", "enableLongPress", "moreActions"], outputs: ["inquiryClick", "longPress"] }, { kind: "component", type: DsMobileInteractiveListItemMessageComponent, selector: "ds-mobile-interactive-list-item-message", inputs: ["senderName", "senderRole", "timestamp", "message", "avatarInitials", "avatarType", "avatarSrc", "unread", "clickable", "align", "showAvatarBadge", "groupStackMembers", "groupCustomAvatarUrl", "groupStackExcludeParticipantId"], outputs: ["messageClick", "longPress"] }, { kind: "component", type: DsMobileInteractiveListItemServiceComponent, selector: "ds-mobile-interactive-list-item-service", inputs: ["title", "description", "logo", "showChevron"], outputs: ["serviceClick"] }, { kind: "component", type: DsMobileOfflineBannerComponent, selector: "ds-mobile-offline-banner", inputs: ["icon", "title", "message"] }, { kind: "component", type: PostContentComponent, selector: "post-content" }, { kind: "component", type: PostTextComponent, selector: "post-text" }, { kind: "component", type: PostActionsComponent, selector: "post-actions" }, { kind: "component", type: ActionLikeComponent, selector: "action-like", inputs: ["active", "count"], outputs: ["activeChange", "countChange", "likeClick"] }, { kind: "component", type: ActionCommentComponent, selector: "action-comment", inputs: ["count"], outputs: ["commentClick"] }] });
29586
30321
  }
29587
30322
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: MobileHomePageComponent, decorators: [{
29588
30323
  type: Component,
@@ -29596,6 +30331,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
29596
30331
  DsMobileInteractiveListItemPostComponent,
29597
30332
  DsMobileInteractiveListItemInquiryComponent,
29598
30333
  DsMobileInteractiveListItemMessageComponent,
30334
+ DsMobileInteractiveListItemBookingComponent,
30335
+ DsMobileInteractiveListItemServiceComponent,
29599
30336
  DsMobileOfflineBannerComponent,
29600
30337
  PostContentComponent,
29601
30338
  PostTextComponent,
@@ -29745,6 +30482,24 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
29745
30482
  </div>
29746
30483
  </ds-mobile-section>
29747
30484
 
30485
+ <!-- Services preview -->
30486
+ @if (previewVendors().length > 0) {
30487
+ <ds-mobile-section
30488
+ headline="Services"
30489
+ linkText="Se alle"
30490
+ contentGap="0px"
30491
+ (linkClick)="navigateToServices()">
30492
+ @for (vendor of previewVendors(); track vendor.id) {
30493
+ <ds-mobile-interactive-list-item-service
30494
+ [title]="vendor.name"
30495
+ [description]="vendor.description || ''"
30496
+ [logo]="vendor.logo || ''"
30497
+ (serviceClick)="openVendorSheet(vendor)"
30498
+ />
30499
+ }
30500
+ </ds-mobile-section>
30501
+ }
30502
+
29748
30503
  <!-- Recent Community Posts Section (empty state) -->
29749
30504
  <ds-mobile-section>
29750
30505
  <div class="empty-state">
@@ -29802,7 +30557,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
29802
30557
  </ds-mobile-page-main>
29803
30558
  } <!-- end @if (!isCoveringScreen()) -->
29804
30559
 
29805
- `, styles: [".posts-list,.messages-preview-list{display:flex;flex-direction:column}.property-banner-nav{display:block;width:100%;border-radius:12px;cursor:pointer;-webkit-tap-highlight-color:transparent}.property-banner-nav:focus-visible{outline:2px solid var(--color-accent, #6B5FF5);outline-offset:2px}.inquiries-list{display:flex;flex-direction:column}.empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:20px;text-align:center}.empty-state ds-button{display:block;margin-top:16px}.empty-state ds-button::ng-deep .btn{width:100%;border-radius:9999px}.empty-state-title{font-family:Brockmann,sans-serif;font-size:var(--font-size-base);font-weight:600;color:var(--color-text-primary);margin-top:-16px;z-index:4}.empty-state-description{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);color:var(--color-text-secondary);margin:0}@keyframes slideDown{0%{transform:translateY(-100%);opacity:0}to{transform:translateY(0);opacity:1}}.welcome-toast{padding:10px 14px;border-radius:12px;background:var(--color-background-brand-secondary, #EEF0FF);display:flex;align-items:flex-start;gap:10px;font-size:14px;font-weight:500;color:var(--color-accent, #6B5FF5);animation:slideDown .2s ease-out}.toast-icon{width:20px;height:20px;border-radius:50%;background:var(--color-accent, #6B5FF5);display:flex;align-items:center;justify-content:center;flex-shrink:0;color:#fff;margin-top:1px}.welcome-toast-content{flex:1;display:flex;flex-direction:column;gap:2px}.welcome-toast-heading{font-family:Brockmann,sans-serif;font-size:14px;font-weight:600;color:var(--color-brand-content, #3B3691);margin:0}.welcome-toast-text{font-family:Brockmann,sans-serif;font-size:13px;line-height:1.4;color:var(--color-brand-content, #3B3691);margin:0;opacity:.8}.welcome-toast-text strong{font-weight:600;opacity:1}.toast-dismiss{margin-left:auto;background:none;border:none;cursor:pointer;flex-shrink:0;color:var(--color-accent, #6B5FF5);display:flex;align-items:center;justify-content:center}.home-content--animating{animation:homeReveal .3s var(--spring-curve-smooth) both}@keyframes homeReveal{0%{opacity:0;transform:translateY(128px)}to{opacity:1;transform:translateY(0)}}\n"] }]
30560
+ `, styles: [".posts-list,.messages-preview-list{display:flex;flex-direction:column}.property-banner-nav{display:block;width:100%;border-radius:12px;cursor:pointer;-webkit-tap-highlight-color:transparent}.property-banner-nav:focus-visible{outline:2px solid var(--color-accent, #6B5FF5);outline-offset:2px}.inquiries-list,.services-preview-list{display:flex;flex-direction:column}.empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:20px;text-align:center}.empty-state ds-button{display:block;margin-top:16px}.empty-state ds-button::ng-deep .btn{width:100%;border-radius:9999px}.empty-state-title{font-family:Brockmann,sans-serif;font-size:var(--font-size-base);font-weight:600;color:var(--color-text-primary);margin-top:-16px;z-index:4}.empty-state-description{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);color:var(--color-text-secondary);margin:0}@keyframes slideDown{0%{transform:translateY(-100%);opacity:0}to{transform:translateY(0);opacity:1}}.welcome-toast{padding:10px 14px;border-radius:12px;background:var(--color-background-brand-secondary, #EEF0FF);display:flex;align-items:flex-start;gap:10px;font-size:14px;font-weight:500;color:var(--color-accent, #6B5FF5);animation:slideDown .2s ease-out}.toast-icon{width:20px;height:20px;border-radius:50%;background:var(--color-accent, #6B5FF5);display:flex;align-items:center;justify-content:center;flex-shrink:0;color:#fff;margin-top:1px}.welcome-toast-content{flex:1;display:flex;flex-direction:column;gap:2px}.welcome-toast-heading{font-family:Brockmann,sans-serif;font-size:14px;font-weight:600;color:var(--color-brand-content, #3B3691);margin:0}.welcome-toast-text{font-family:Brockmann,sans-serif;font-size:13px;line-height:1.4;color:var(--color-brand-content, #3B3691);margin:0;opacity:.8}.welcome-toast-text strong{font-weight:600;opacity:1}.toast-dismiss{margin-left:auto;background:none;border:none;cursor:pointer;flex-shrink:0;color:var(--color-accent, #6B5FF5);display:flex;align-items:center;justify-content:center}.home-content--animating{animation:homeReveal .3s var(--spring-curve-smooth) both}@keyframes homeReveal{0%{opacity:0;transform:translateY(128px)}to{opacity:1;transform:translateY(0)}}\n"] }]
29806
30561
  }], ctorParameters: () => [{ type: i1$3.Router }, { type: i1.NavController }, { type: UserService }, { type: PostsService }, { type: DsMobilePostDetailModalService }, { type: TrackingPermissionService }, { type: DsMobileBottomSheetService }, { type: FamilyAccessService }, { type: PeerMessagingService }, { type: PeerChatLauncherService }], propDecorators: { pageComponent: [{
29807
30562
  type: ViewChild,
29808
30563
  args: ['pageComponent']
@@ -29813,6 +30568,7 @@ class MobileInquiriesPageComponent {
29813
30568
  navCtrl;
29814
30569
  newInquiryModal;
29815
30570
  pageComponent;
30571
+ inquiriesService = inject(InquiriesService);
29816
30572
  constructor(userService, navCtrl, newInquiryModal) {
29817
30573
  this.userService = userService;
29818
30574
  this.navCtrl = navCtrl;
@@ -29824,52 +30580,13 @@ class MobileInquiriesPageComponent {
29824
30580
  { id: 'open', label: 'Åben' },
29825
30581
  { id: 'closed', label: 'Lukket' }
29826
30582
  ];
29827
- inquiries = signal([
29828
- {
29829
- id: '1',
29830
- title: 'Tørretumbler virker ikke',
29831
- description: 'I de sidste tre dage har jeg oplevet vedvarende problemer med tørretumbleren. Den starter, men stopper efter få minutter.',
29832
- status: 'open',
29833
- timestamp: '12 dage siden',
29834
- category: 'appliance'
29835
- },
29836
- {
29837
- id: '2',
29838
- title: 'Problem med vandtryk',
29839
- description: 'Lavt vandtryk i badeværelseshåndvasken. Det er blevet gradvist værre i løbet af den sidste uge.',
29840
- status: 'open',
29841
- timestamp: '5 dage siden',
29842
- category: 'plumbing'
29843
- },
29844
- {
29845
- id: '3',
29846
- title: 'Varme virker ikke ordentligt',
29847
- description: 'Varmesystemet holder ikke den indstillede temperatur. Lejligheden er meget koldere, end den burde være.',
29848
- status: 'closed',
29849
- timestamp: '2 måneder siden',
29850
- category: 'heating'
29851
- }
29852
- ], ...(ngDevMode ? [{ debugName: "inquiries" }] : []));
29853
- // Computed signals that automatically update when dependencies change
29854
30583
  filteredInquiries = computed(() => {
29855
- const all = this.inquiries();
30584
+ const all = this.inquiriesService.inquiries();
29856
30585
  const status = this.filterStatus();
29857
- if (status === 'all') {
30586
+ if (status === 'all')
29858
30587
  return all;
29859
- }
29860
- else if (status === 'open') {
29861
- return all.filter(i => i.status === 'open');
29862
- }
29863
- else {
29864
- return all.filter(i => i.status === 'closed');
29865
- }
30588
+ return all.filter(i => i.status === status);
29866
30589
  }, ...(ngDevMode ? [{ debugName: "filteredInquiries" }] : []));
29867
- openInquiries = computed(() => {
29868
- return this.inquiries().filter(i => i.status === 'open');
29869
- }, ...(ngDevMode ? [{ debugName: "openInquiries" }] : []));
29870
- closedInquiries = computed(() => {
29871
- return this.inquiries().filter(i => i.status === 'closed');
29872
- }, ...(ngDevMode ? [{ debugName: "closedInquiries" }] : []));
29873
30590
  setFilter(status) {
29874
30591
  this.filterStatus.set(status);
29875
30592
  }
@@ -29908,16 +30625,14 @@ class MobileInquiriesPageComponent {
29908
30625
  console.log('New inquiry submitted:', data);
29909
30626
  // In a real app, call your API to create the inquiry
29910
30627
  // await this.inquiryService.createInquiry(data);
29911
- // Add the new inquiry to the list (mock for now)
29912
- const newInquiry = {
30628
+ this.inquiriesService.addInquiry({
29913
30629
  id: `inquiry-${Date.now()}`,
29914
30630
  title: data.title,
29915
30631
  description: data.description,
29916
30632
  status: 'open',
29917
- timestamp: 'Just now',
29918
- category: 'other'
29919
- };
29920
- this.inquiries.update(inquiries => [newInquiry, ...inquiries]);
30633
+ timestamp: 'Lige nu',
30634
+ category: data.category || 'other',
30635
+ });
29921
30636
  // Close the modal
29922
30637
  await this.newInquiryModal.close();
29923
30638
  }
@@ -30086,12 +30801,25 @@ class MobileInquiryDetailPageComponent {
30086
30801
  userService;
30087
30802
  lightbox;
30088
30803
  chatModal;
30804
+ route = inject(ActivatedRoute);
30805
+ inquiriesService = inject(InquiriesService);
30089
30806
  inquiryTitle = 'Tørretumbler virker ikke';
30807
+ inquiryDescription = 'I de sidste tre dage har vi oplevet vedvarende problemer med tørretumbleren i vores lejlighed. På trods af at vi følger betjeningsvejledningen, fejler maskinen konsekvent i at fuldføre sine tørrecyklusser.';
30808
+ inquiryCategory = 'Husholdningsapparater';
30809
+ inquiryTimestamp = '22. feb 2025';
30810
+ vendorName = '';
30811
+ vendorInitials = '';
30812
+ vendorLogo = '';
30813
+ isServiceInquiry = false;
30090
30814
  activeTab = signal('details', ...(ngDevMode ? [{ debugName: "activeTab" }] : []));
30091
30815
  tabItems = [
30092
30816
  { id: 'details', label: 'Detaljer' },
30093
30817
  { id: 'messages', label: 'Beskeder', badge: 0 }
30094
30818
  ];
30819
+ serviceMessageThread = [];
30820
+ get activeMessages() {
30821
+ return this.isServiceInquiry ? this.serviceMessageThread : this.messageThreads;
30822
+ }
30095
30823
  messageThreads = [
30096
30824
  {
30097
30825
  id: '1',
@@ -30114,16 +30842,13 @@ class MobileInquiryDetailPageComponent {
30114
30842
  unread: false
30115
30843
  }
30116
30844
  ];
30117
- unreadMessagesCount = computed(() => {
30118
- const count = this.messageThreads.length;
30119
- // Update badge in tab items
30845
+ updateMessagesBadge() {
30846
+ const count = this.activeMessages.length;
30120
30847
  const messagesTab = this.tabItems.find(t => t.id === 'messages');
30121
30848
  if (messagesTab) {
30122
30849
  messagesTab.badge = count;
30123
30850
  }
30124
- return count;
30125
- }, ...(ngDevMode ? [{ debugName: "unreadMessagesCount" }] : []));
30126
- // Photos for lightbox
30851
+ }
30127
30852
  photos = [
30128
30853
  { type: 'image', src: '/Assets/Dummy-photos/handyman.jpg', alt: 'Handyman', title: 'Handyman' },
30129
30854
  { type: 'image', src: '/Assets/Dummy-photos/balcony-view.jpg', alt: 'Balcony view', title: 'Balcony view' },
@@ -30131,7 +30856,6 @@ class MobileInquiryDetailPageComponent {
30131
30856
  { type: 'image', src: '/Assets/Dummy-photos/yard.jpg', alt: 'Yard', title: 'Yard' },
30132
30857
  { type: 'image', src: '/Assets/Dummy-photos/mailboxes.jpg', alt: 'Mailboxes', title: 'Mailboxes' }
30133
30858
  ];
30134
- // Photo URLs for inline-photo component
30135
30859
  get photoUrls() {
30136
30860
  return this.photos.map(photo => photo.src);
30137
30861
  }
@@ -30139,16 +30863,48 @@ class MobileInquiryDetailPageComponent {
30139
30863
  this.userService = userService;
30140
30864
  this.lightbox = lightbox;
30141
30865
  this.chatModal = chatModal;
30142
- // Trigger initial badge update
30143
- this.unreadMessagesCount();
30866
+ this.updateMessagesBadge();
30867
+ }
30868
+ ngOnInit() {
30869
+ const id = this.route.snapshot.paramMap.get('id');
30870
+ if (id) {
30871
+ const inquiry = this.inquiriesService.getById(id);
30872
+ if (inquiry) {
30873
+ this.inquiryTitle = inquiry.title;
30874
+ this.inquiryDescription = inquiry.description;
30875
+ this.inquiryCategory = inquiry.category;
30876
+ this.inquiryTimestamp = inquiry.timestamp;
30877
+ if (inquiry.vendorName) {
30878
+ this.isServiceInquiry = true;
30879
+ this.vendorName = inquiry.vendorName;
30880
+ this.vendorInitials = inquiry.vendorName
30881
+ .split(/\s+/)
30882
+ .filter(w => w.length > 0)
30883
+ .slice(0, 2)
30884
+ .map(w => w[0].toUpperCase())
30885
+ .join('');
30886
+ this.vendorLogo = inquiry.vendorLogo || '';
30887
+ this.serviceMessageThread = [
30888
+ {
30889
+ id: 'service-msg-1',
30890
+ senderName: this.userService.displayName() || this.userService.avatarInitials(),
30891
+ senderAvatar: '',
30892
+ senderInitials: this.userService.avatarInitials(),
30893
+ message: inquiry.description,
30894
+ role: 'Beboer',
30895
+ timestamp: inquiry.timestamp,
30896
+ unread: false,
30897
+ },
30898
+ ];
30899
+ }
30900
+ }
30901
+ }
30902
+ this.updateMessagesBadge();
30144
30903
  }
30145
30904
  setActiveTab(tabId) {
30146
30905
  this.activeTab.set(tabId);
30147
30906
  }
30148
- goBack() {
30149
- // Navigation is handled by ds-mobile-page-details component
30150
- // This is just for any custom logic if needed
30151
- }
30907
+ goBack() { }
30152
30908
  handleRefresh(event) {
30153
30909
  console.log('Pull-to-refresh triggered');
30154
30910
  setTimeout(() => {
@@ -30156,30 +30912,21 @@ class MobileInquiryDetailPageComponent {
30156
30912
  event.target.complete();
30157
30913
  }, 1000);
30158
30914
  }
30159
- /**
30160
- * Check if there are unread messages
30161
- */
30162
30915
  hasUnreadMessages() {
30163
- return this.messageThreads.some(m => m.unread);
30916
+ return !this.isServiceInquiry && this.messageThreads.some(m => m.unread);
30164
30917
  }
30165
- /**
30166
- * Navigate to messages tab when banner is clicked
30167
- */
30168
30918
  navigateToMessagesTab() {
30169
30919
  this.setActiveTab('messages');
30170
30920
  }
30171
30921
  async openMessage(messageId) {
30172
- console.log('Opening message:', messageId);
30173
- // Find the message thread
30174
- const messageThread = this.messageThreads.find(m => m.id === messageId);
30175
- if (!messageThread) {
30176
- console.error('Message thread not found:', messageId);
30922
+ if (this.isServiceInquiry) {
30923
+ await this.openVendorChat();
30177
30924
  return;
30178
30925
  }
30179
- // Check if this is an empty state chat (no timestamp and system message)
30926
+ const messageThread = this.messageThreads.find(m => m.id === messageId);
30927
+ if (!messageThread)
30928
+ return;
30180
30929
  const isEmptyChat = messageThread.message.includes('har overtaget din henvendelse') && !messageThread.timestamp;
30181
- // Prepare chat modal data
30182
- // In a real app, you would fetch the actual messages from your API
30183
30930
  const chatData = {
30184
30931
  participant: {
30185
30932
  id: messageId,
@@ -30189,14 +30936,13 @@ class MobileInquiryDetailPageComponent {
30189
30936
  avatarType: 'initials'
30190
30937
  },
30191
30938
  messages: isEmptyChat ? [] : [
30192
- // Day 1 - Yesterday morning (9:15 AM)
30193
30939
  {
30194
30940
  id: '1',
30195
30941
  content: 'Godmorgen! Jeg ville lige følge op på din henvendelse vedrørende vedligeholdelsesplanen.',
30196
30942
  senderId: messageId,
30197
30943
  senderName: messageThread.senderName,
30198
30944
  senderRole: messageThread.role,
30199
- timestamp: new Date(Date.now() - 86400000 - 32700000), // Yesterday 9:15 AM
30945
+ timestamp: new Date(Date.now() - 86400000 - 32700000),
30200
30946
  isOwnMessage: false,
30201
30947
  avatarInitials: messageThread.senderInitials,
30202
30948
  avatarType: 'initials',
@@ -30207,7 +30953,7 @@ class MobileInquiryDetailPageComponent {
30207
30953
  senderId: messageId,
30208
30954
  senderName: messageThread.senderName,
30209
30955
  senderRole: messageThread.role,
30210
- timestamp: new Date(Date.now() - 86400000 - 32520000), // Yesterday 9:18 AM (grouped with previous)
30956
+ timestamp: new Date(Date.now() - 86400000 - 32520000),
30211
30957
  isOwnMessage: false,
30212
30958
  avatarInitials: messageThread.senderInitials,
30213
30959
  avatarType: 'initials',
@@ -30217,7 +30963,7 @@ class MobileInquiryDetailPageComponent {
30217
30963
  content: 'Tak fordi du kiggede på det! Hvad fandt du?',
30218
30964
  senderId: 'current-user',
30219
30965
  senderName: 'You',
30220
- timestamp: new Date(Date.now() - 86400000 - 32100000), // Yesterday 9:25 AM (new group - 7 min gap)
30966
+ timestamp: new Date(Date.now() - 86400000 - 32100000),
30221
30967
  isOwnMessage: true,
30222
30968
  avatarInitials: this.userService.avatarInitials(),
30223
30969
  avatarType: 'initials',
@@ -30227,19 +30973,18 @@ class MobileInquiryDetailPageComponent {
30227
30973
  content: 'Kan du også sende mig vedligeholdelsesrapporten?',
30228
30974
  senderId: 'current-user',
30229
30975
  senderName: 'You',
30230
- timestamp: new Date(Date.now() - 86400000 - 31980000), // Yesterday 9:27 AM (grouped with previous)
30976
+ timestamp: new Date(Date.now() - 86400000 - 31980000),
30231
30977
  isOwnMessage: true,
30232
30978
  avatarInitials: this.userService.avatarInitials(),
30233
30979
  avatarType: 'initials',
30234
30980
  },
30235
- // Day 1 - Yesterday afternoon (2:30 PM - large time gap)
30236
30981
  {
30237
30982
  id: '5',
30238
30983
  content: messageThread.message,
30239
30984
  senderId: messageId,
30240
30985
  senderName: messageThread.senderName,
30241
30986
  senderRole: messageThread.role,
30242
- timestamp: new Date(Date.now() - 86400000 - 13800000), // Yesterday 2:30 PM (new group - 5 hour gap)
30987
+ timestamp: new Date(Date.now() - 86400000 - 13800000),
30243
30988
  isOwnMessage: false,
30244
30989
  avatarInitials: messageThread.senderInitials,
30245
30990
  avatarType: 'initials',
@@ -30250,18 +30995,17 @@ class MobileInquiryDetailPageComponent {
30250
30995
  senderId: messageId,
30251
30996
  senderName: messageThread.senderName,
30252
30997
  senderRole: messageThread.role,
30253
- timestamp: new Date(Date.now() - 86400000 - 13620000), // Yesterday 2:33 PM (grouped with previous)
30998
+ timestamp: new Date(Date.now() - 86400000 - 13620000),
30254
30999
  isOwnMessage: false,
30255
31000
  avatarInitials: messageThread.senderInitials,
30256
31001
  avatarType: 'initials',
30257
31002
  },
30258
- // Day 2 - Today morning (10:45 AM - new day)
30259
31003
  {
30260
31004
  id: '7',
30261
31005
  content: 'Perfekt! Jeg har gennemgået rapporten, og alt ser godt ud.',
30262
31006
  senderId: 'current-user',
30263
31007
  senderName: 'You',
30264
- timestamp: new Date(Date.now() - 7500000), // Today 10:45 AM (new group - new day)
31008
+ timestamp: new Date(Date.now() - 7500000),
30265
31009
  isOwnMessage: true,
30266
31010
  avatarInitials: this.userService.avatarInitials(),
30267
31011
  avatarType: 'initials',
@@ -30271,19 +31015,18 @@ class MobileInquiryDetailPageComponent {
30271
31015
  content: 'Hvornår kan vi planlægge vedligeholdelsesarbejdet?',
30272
31016
  senderId: 'current-user',
30273
31017
  senderName: 'You',
30274
- timestamp: new Date(Date.now() - 7320000), // Today 10:48 AM (grouped with previous)
31018
+ timestamp: new Date(Date.now() - 7320000),
30275
31019
  isOwnMessage: true,
30276
31020
  avatarInitials: this.userService.avatarInitials(),
30277
31021
  avatarType: 'initials',
30278
31022
  },
30279
- // Day 2 - Today (just now - 2 minutes ago)
30280
31023
  {
30281
31024
  id: '9',
30282
31025
  content: 'Dejligt at høre! Jeg kan planlægge det til næste tirsdag kl. 09.00. Passer det dig?',
30283
31026
  senderId: messageId,
30284
31027
  senderName: messageThread.senderName,
30285
31028
  senderRole: messageThread.role,
30286
- timestamp: new Date(Date.now() - 120000), // 2 minutes ago (new group - several hours gap)
31029
+ timestamp: new Date(Date.now() - 120000),
30287
31030
  isOwnMessage: false,
30288
31031
  avatarInitials: messageThread.senderInitials,
30289
31032
  avatarType: 'initials',
@@ -30294,7 +31037,7 @@ class MobileInquiryDetailPageComponent {
30294
31037
  senderId: messageId,
30295
31038
  senderName: messageThread.senderName,
30296
31039
  senderRole: messageThread.role,
30297
- timestamp: new Date(Date.now() - 60000), // 1 minute ago (grouped with previous)
31040
+ timestamp: new Date(Date.now() - 60000),
30298
31041
  isOwnMessage: false,
30299
31042
  avatarInitials: messageThread.senderInitials,
30300
31043
  avatarType: 'initials',
@@ -30305,7 +31048,37 @@ class MobileInquiryDetailPageComponent {
30305
31048
  currentUserAvatarType: 'initials',
30306
31049
  autoFocus: false
30307
31050
  };
30308
- // Open the chat modal
31051
+ await this.chatModal.open(chatData);
31052
+ }
31053
+ async openVendorChat() {
31054
+ const chatData = {
31055
+ participant: {
31056
+ id: 'vendor',
31057
+ name: this.vendorName,
31058
+ role: 'Leverandør',
31059
+ avatarInitials: this.vendorInitials,
31060
+ avatarType: this.vendorLogo ? 'photo' : 'initials',
31061
+ avatarSrc: this.vendorLogo,
31062
+ avatarShape: 'squircle',
31063
+ },
31064
+ messages: [
31065
+ {
31066
+ id: 'service-initial',
31067
+ content: this.inquiryDescription,
31068
+ senderId: 'current-user',
31069
+ senderName: 'You',
31070
+ timestamp: new Date(),
31071
+ isOwnMessage: true,
31072
+ avatarInitials: this.userService.avatarInitials(),
31073
+ avatarType: 'initials',
31074
+ },
31075
+ ],
31076
+ threadContext: 'peer',
31077
+ currentUserId: 'current-user',
31078
+ currentUserInitials: this.userService.avatarInitials(),
31079
+ currentUserAvatarType: 'initials',
31080
+ autoFocus: true,
31081
+ };
30309
31082
  await this.chatModal.open(chatData);
30310
31083
  }
30311
31084
  async openPhotoLightbox(index) {
@@ -30330,26 +31103,35 @@ class MobileInquiryDetailPageComponent {
30330
31103
 
30331
31104
  <!-- Messages Tab Content -->
30332
31105
  @if (activeTab() === 'messages') {
30333
- <ds-mobile-section contentGap="0">
30334
- @for (message of messageThreads; track message.id) {
30335
- <ds-mobile-interactive-list-item-message
30336
- [senderName]="message.senderName"
30337
- [senderRole]="message.role"
30338
- [timestamp]="message.timestamp"
30339
- [message]="message.message"
30340
- [avatarInitials]="message.senderInitials"
30341
- [showAvatarBadge]="true"
30342
- [unread]="message.unread"
30343
- (messageClick)="openMessage(message.id)">
30344
- </ds-mobile-interactive-list-item-message>
30345
- }
30346
- </ds-mobile-section>
31106
+ @if (activeMessages.length > 0) {
31107
+ <ds-mobile-section contentGap="0">
31108
+ @for (message of activeMessages; track message.id) {
31109
+ <ds-mobile-interactive-list-item-message
31110
+ [senderName]="message.senderName"
31111
+ [senderRole]="message.role"
31112
+ [timestamp]="message.timestamp"
31113
+ [message]="message.message"
31114
+ [avatarInitials]="message.senderInitials"
31115
+ [showAvatarBadge]="!isServiceInquiry"
31116
+ [unread]="message.unread"
31117
+ (messageClick)="openMessage(message.id)">
31118
+ </ds-mobile-interactive-list-item-message>
31119
+ }
31120
+ </ds-mobile-section>
31121
+ } @else {
31122
+ <ds-mobile-section>
31123
+ <div class="empty-messages">
31124
+ <img class="empty-messages-image" src="/Assets/Empty state-chat.png" alt="Ingen beskeder" />
31125
+ <p class="empty-messages-text">Ingen beskeder endnu</p>
31126
+ </div>
31127
+ </ds-mobile-section>
31128
+ }
30347
31129
  }
30348
31130
 
30349
31131
  <!-- Details Tab Content -->
30350
31132
  @if (activeTab() === 'details') {
30351
- <!-- Unread Messages Banner -->
30352
- @if (hasUnreadMessages()) {
31133
+ <!-- Unread Messages Banner (legacy only) -->
31134
+ @if (!isServiceInquiry && hasUnreadMessages()) {
30353
31135
  <ds-mobile-section>
30354
31136
  <ds-mobile-card-inline-banner
30355
31137
  [title]="'Du har ulæste beskeder'"
@@ -30360,41 +31142,57 @@ class MobileInquiryDetailPageComponent {
30360
31142
  </ds-mobile-section>
30361
31143
  }
30362
31144
 
30363
- <!-- All Details in One Section -->
30364
31145
  <ds-mobile-section contentGap="0">
30365
- <!-- Assignee -->
30366
- <ds-mobile-list-item [leadingSize]="'32px'" [showDivider]="true">
30367
- <div content-leading>
30368
- <ds-avatar-with-badge
30369
- [size]="'sm'"
30370
- [type]="'initials'"
30371
- [initials]="'R'" />
30372
- </div>
30373
- <div content-main>
30374
- <div class="detail-label">Sagsbehandler</div>
30375
- <div class="detail-value">Ricki Meihlen</div>
30376
- </div>
30377
- </ds-mobile-list-item>
30378
-
30379
- <!-- Technician -->
30380
- <ds-mobile-list-item [leadingSize]="'32px'" [showDivider]="true">
30381
- <div content-leading>
30382
- <ds-avatar-with-badge
30383
- [size]="'sm'"
30384
- [type]="'initials'"
30385
- [initials]="'M'" />
30386
- </div>
30387
- <div content-main>
30388
- <div class="detail-label">Tekniker</div>
30389
- <div class="detail-value">Martin Smith</div>
30390
- </div>
30391
- </ds-mobile-list-item>
31146
+ <!-- Vendor company (service inquiries) -->
31147
+ @if (isServiceInquiry && vendorName) {
31148
+ <ds-mobile-list-item [leadingSize]="'32px'" [showDivider]="true">
31149
+ <div content-leading>
31150
+ <ds-mobile-vendor-avatar
31151
+ [name]="vendorName"
31152
+ [logo]="vendorLogo"
31153
+ size="md" />
31154
+ </div>
31155
+ <div content-main>
31156
+ <div class="detail-label">Leverandør</div>
31157
+ <div class="detail-value">{{ vendorName }}</div>
31158
+ </div>
31159
+ </ds-mobile-list-item>
31160
+ }
31161
+
31162
+ <!-- Assignee + Technician (legacy inquiries only) -->
31163
+ @if (!isServiceInquiry) {
31164
+ <ds-mobile-list-item [leadingSize]="'32px'" [showDivider]="true">
31165
+ <div content-leading>
31166
+ <ds-avatar-with-badge
31167
+ [size]="'sm'"
31168
+ [type]="'initials'"
31169
+ [initials]="'R'" />
31170
+ </div>
31171
+ <div content-main>
31172
+ <div class="detail-label">Sagsbehandler</div>
31173
+ <div class="detail-value">Ricki Meihlen</div>
31174
+ </div>
31175
+ </ds-mobile-list-item>
31176
+
31177
+ <ds-mobile-list-item [leadingSize]="'32px'" [showDivider]="true">
31178
+ <div content-leading>
31179
+ <ds-avatar-with-badge
31180
+ [size]="'sm'"
31181
+ [type]="'initials'"
31182
+ [initials]="'M'" />
31183
+ </div>
31184
+ <div content-main>
31185
+ <div class="detail-label">Tekniker</div>
31186
+ <div class="detail-value">Martin Smith</div>
31187
+ </div>
31188
+ </ds-mobile-list-item>
31189
+ }
30392
31190
 
30393
31191
  <!-- Creation Date -->
30394
31192
  <ds-mobile-list-item [leadingSize]="'32px'" [showDivider]="true" [align]="'center'">
30395
31193
  <ds-icon content-leading name="remixTimeLine" size="20px" color="tertiary" />
30396
31194
  <div content-main>
30397
- <div class="detail-value">22. feb 2025</div>
31195
+ <div class="detail-value">{{ inquiryTimestamp }}</div>
30398
31196
  </div>
30399
31197
  </ds-mobile-list-item>
30400
31198
 
@@ -30407,30 +31205,32 @@ class MobileInquiryDetailPageComponent {
30407
31205
  </ds-mobile-list-item>
30408
31206
 
30409
31207
  <!-- Description -->
30410
- <ds-mobile-list-item [leadingSize]="'32px'" [showDivider]="photoUrls.length > 0">
31208
+ <ds-mobile-list-item [leadingSize]="'32px'" [showDivider]="!isServiceInquiry && photoUrls.length > 0">
30411
31209
  <ds-icon content-leading name="remixAlignLeft" size="20px" color="tertiary" />
30412
31210
  <div content-main style="display:flex;flex-direction:column;gap:8px">
30413
31211
  <div class="detail-value description-text">
30414
- I de sidste tre dage har vi oplevet vedvarende problemer med tørretumbleren i vores lejlighed. På trods af at vi følger betjeningsvejledningen, fejler maskinen konsekvent i at fuldføre sine tørrecyklusser.
31212
+ {{ inquiryDescription }}
30415
31213
  </div>
30416
- <ds-badge content="Husholdningsapparater" size="sm"/>
31214
+ <ds-badge [content]="inquiryCategory" size="sm"/>
30417
31215
  </div>
30418
31216
  </ds-mobile-list-item>
30419
31217
 
30420
- <!-- Photos -->
30421
- <ds-mobile-list-item [leadingSize]="'32px'" [showDivider]="false">
30422
- <ds-icon content-leading name="remixCameraLine" size="20px" color="tertiary" />
30423
- <div content-main>
30424
- <ds-mobile-inline-photo
30425
- [images]="photoUrls"
30426
- [useGrid]="false"
30427
- (photoClick)="openPhotoLightbox($event.index)" />
30428
- </div>
30429
- </ds-mobile-list-item>
31218
+ <!-- Photos (legacy inquiries only) -->
31219
+ @if (!isServiceInquiry) {
31220
+ <ds-mobile-list-item [leadingSize]="'32px'" [showDivider]="false">
31221
+ <ds-icon content-leading name="remixCameraLine" size="20px" color="tertiary" />
31222
+ <div content-main>
31223
+ <ds-mobile-inline-photo
31224
+ [images]="photoUrls"
31225
+ [useGrid]="false"
31226
+ (photoClick)="openPhotoLightbox($event.index)" />
31227
+ </div>
31228
+ </ds-mobile-list-item>
31229
+ }
30430
31230
  </ds-mobile-section>
30431
31231
  }
30432
31232
  </ds-mobile-page-details>
30433
- `, isInline: true, styles: [".activity-list{display:flex;flex-direction:column;gap:12px;position:relative}.activity-list ds-mobile-list-item:not(:last-child) [content-leading]:after{content:\"\";position:absolute;top:40px;left:50%;transform:translate(-50%);width:1px;height:calc(100% - 2px);background:var(--border-color-default, #e5e5e5);z-index:0}.activity-icon-wrapper{width:100%;height:100%;border-radius:8px;background:var(--color-background-neutral-secondary, #f5f5f5);display:flex;align-items:center;justify-content:center;flex-shrink:0;position:relative;z-index:1}.avatar-wrapper{position:relative;display:flex;align-items:start;justify-content:center;flex-shrink:0;width:100%;height:100%;z-index:1}.avatar-badge{position:absolute;bottom:-6px;right:-6px;width:20px;height:20px;border-radius:8px;background:var(--color-brand-secondary, #5d5fef);display:flex;align-items:center;justify-content:center;border:2px solid var(--color-background-primary, #ffffff)}.avatar-badge svg{width:10px;position:relative;top:1px;fill:#fff}.activity-content{display:flex;flex-direction:column;gap:4px}.activity-title{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);font-weight:500;line-height:20px;letter-spacing:-.3px;color:var(--text-color-default-primary, #202227);margin:0}.activity-title .actor-name{font-weight:600;color:var(--text-color-default-primary, #202227)}.activity-title .activity-text{color:var(--text-color-default-secondary, #545B66);font-weight:400}.activity-description{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);font-weight:400;line-height:20px;letter-spacing:-.3px;color:var(--text-color-default-secondary, #545B66);margin:0}.activity-timestamp{font-family:Brockmann,sans-serif;font-size:var(--font-size-xs);font-weight:400;line-height:1.2;letter-spacing:-.26px;color:var(--text-color-default-tertiary, #737373);display:flex;align-items:center;gap:4px;margin-top:2px}.detail-label{font-family:Brockmann,sans-serif;font-size:var(--font-size-xs);font-weight:400;line-height:1.2;letter-spacing:-.26px;color:var(--text-color-default-tertiary, #737373)}.detail-value{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);font-weight:400;line-height:24px;letter-spacing:-.3px;color:var(--text-color-default-primary, #202227)}.detail-tag{display:inline-flex;align-items:center;padding:4px 12px;border-radius:12px;background:var(--color-background-neutral-secondary, #f5f5f5);font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);font-weight:500;color:var(--text-color-default-secondary, #525866);margin-top:4px;margin-bottom:10px;width:-moz-fit-content;width:fit-content}.photo-grid{display:grid;grid-template-columns:repeat(6,1fr);gap:8px}.photo-add{width:100%;aspect-ratio:1;border-radius:12px;border:1px dashed var(--border-color-default, #e5e5e5);background:var(--color-background-neutral-secondary, #f5f5f5);display:flex;align-items:center;justify-content:center;cursor:pointer}.photo-item{width:100%;aspect-ratio:1;border-radius:12px;-o-object-fit:cover;object-fit:cover}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: DsIconComponent, selector: "ds-icon", inputs: ["name", "size", "color", "interactive"] }, { kind: "component", type: DsAvatarWithBadgeComponent, selector: "ds-avatar-with-badge", inputs: ["type", "size", "initials", "src", "iconName", "showBadge", "badgePosition"] }, { kind: "component", type: DsMobilePageDetailsComponent, selector: "ds-mobile-page-details", inputs: ["title", "backRoute", "contentPadding", "tabs", "activeTab", "showRefresh", "scrollThreshold", "headerFadeDistance"], outputs: ["back", "tabChange", "refresh", "scroll"] }, { kind: "component", type: DsMobileInteractiveListItemMessageComponent, selector: "ds-mobile-interactive-list-item-message", inputs: ["senderName", "senderRole", "timestamp", "message", "avatarInitials", "avatarType", "avatarSrc", "unread", "clickable", "align", "showAvatarBadge", "groupStackMembers", "groupCustomAvatarUrl", "groupStackExcludeParticipantId"], outputs: ["messageClick", "longPress"] }, { kind: "component", type: DsMobileListItemComponent, selector: "ds-mobile-list-item", inputs: ["leadingSize", "variant", "align", "flushTop", "interactive", "disabled", "loading", "enableLongPress", "showDesktopMoreButton", "moreActions", "moreButtonAriaLabel", "interactiveOffset", "title", "subtitle", "showDivider", "dividerSpacing"], outputs: ["itemClick", "moreButtonClick"] }, { kind: "component", type: DsBadgeComponent, selector: "ds-badge", inputs: ["variant", "contentType", "content", "leadingIcon", "indicatorShape"] }, { kind: "component", type: DsMobileCardInlineBannerComponent, selector: "ds-mobile-card-inline-banner", inputs: ["title", "timestamp", "unreadCount", "layout"], outputs: ["bannerClick"] }, { kind: "component", type: DsMobileSectionComponent, selector: "ds-mobile-section", inputs: ["headline", "icon", "linkText", "padding", "paddingDesktop", "gap", "contentGap", "showBorder", "overflow"], outputs: ["linkClick"] }, { kind: "component", type: DsMobileInlinePhotoComponent, selector: "ds-mobile-inline-photo", inputs: ["images", "loadingStates", "author", "maxVisible", "useGrid"], outputs: ["photoClick"] }] });
31233
+ `, isInline: true, styles: [".activity-list{display:flex;flex-direction:column;gap:12px;position:relative}.activity-list ds-mobile-list-item:not(:last-child) [content-leading]:after{content:\"\";position:absolute;top:40px;left:50%;transform:translate(-50%);width:1px;height:calc(100% - 2px);background:var(--border-color-default, #e5e5e5);z-index:0}.activity-icon-wrapper{width:100%;height:100%;border-radius:8px;background:var(--color-background-neutral-secondary, #f5f5f5);display:flex;align-items:center;justify-content:center;flex-shrink:0;position:relative;z-index:1}.avatar-wrapper{position:relative;display:flex;align-items:start;justify-content:center;flex-shrink:0;width:100%;height:100%;z-index:1}.avatar-badge{position:absolute;bottom:-6px;right:-6px;width:20px;height:20px;border-radius:8px;background:var(--color-brand-secondary, #5d5fef);display:flex;align-items:center;justify-content:center;border:2px solid var(--color-background-primary, #ffffff)}.avatar-badge svg{width:10px;position:relative;top:1px;fill:#fff}.activity-content{display:flex;flex-direction:column;gap:4px}.activity-title{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);font-weight:500;line-height:20px;letter-spacing:-.3px;color:var(--text-color-default-primary, #202227);margin:0}.activity-title .actor-name{font-weight:600;color:var(--text-color-default-primary, #202227)}.activity-title .activity-text{color:var(--text-color-default-secondary, #545B66);font-weight:400}.activity-description{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);font-weight:400;line-height:20px;letter-spacing:-.3px;color:var(--text-color-default-secondary, #545B66);margin:0}.activity-timestamp{font-family:Brockmann,sans-serif;font-size:var(--font-size-xs);font-weight:400;line-height:1.2;letter-spacing:-.26px;color:var(--text-color-default-tertiary, #737373);display:flex;align-items:center;gap:4px;margin-top:2px}.detail-label{font-family:Brockmann,sans-serif;font-size:var(--font-size-xs);font-weight:400;line-height:1.2;letter-spacing:-.26px;color:var(--text-color-default-tertiary, #737373)}.detail-value{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);font-weight:400;line-height:24px;letter-spacing:-.3px;color:var(--text-color-default-primary, #202227)}.detail-tag{display:inline-flex;align-items:center;padding:4px 12px;border-radius:12px;background:var(--color-background-neutral-secondary, #f5f5f5);font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);font-weight:500;color:var(--text-color-default-secondary, #525866);margin-top:4px;margin-bottom:10px;width:-moz-fit-content;width:fit-content}.photo-grid{display:grid;grid-template-columns:repeat(6,1fr);gap:8px}.photo-add{width:100%;aspect-ratio:1;border-radius:12px;border:1px dashed var(--border-color-default, #e5e5e5);background:var(--color-background-neutral-secondary, #f5f5f5);display:flex;align-items:center;justify-content:center;cursor:pointer}.photo-item{width:100%;aspect-ratio:1;border-radius:12px;-o-object-fit:cover;object-fit:cover}.empty-messages{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:60px 20px;gap:12px}.empty-messages-image{width:96px;height:96px;-o-object-fit:contain;object-fit:contain}.empty-messages-text{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm, 14px);color:var(--text-color-default-secondary, #71727a);margin:0}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: DsIconComponent, selector: "ds-icon", inputs: ["name", "size", "color", "interactive"] }, { kind: "component", type: DsAvatarWithBadgeComponent, selector: "ds-avatar-with-badge", inputs: ["type", "size", "initials", "src", "iconName", "showBadge", "badgePosition"] }, { kind: "component", type: DsMobileVendorAvatarComponent, selector: "ds-mobile-vendor-avatar", inputs: ["name", "logo", "size"] }, { kind: "component", type: DsMobilePageDetailsComponent, selector: "ds-mobile-page-details", inputs: ["title", "backRoute", "contentPadding", "tabs", "activeTab", "showRefresh", "scrollThreshold", "headerFadeDistance"], outputs: ["back", "tabChange", "refresh", "scroll"] }, { kind: "component", type: DsMobileInteractiveListItemMessageComponent, selector: "ds-mobile-interactive-list-item-message", inputs: ["senderName", "senderRole", "timestamp", "message", "avatarInitials", "avatarType", "avatarSrc", "unread", "clickable", "align", "showAvatarBadge", "groupStackMembers", "groupCustomAvatarUrl", "groupStackExcludeParticipantId"], outputs: ["messageClick", "longPress"] }, { kind: "component", type: DsMobileListItemComponent, selector: "ds-mobile-list-item", inputs: ["leadingSize", "variant", "align", "flushTop", "interactive", "disabled", "loading", "enableLongPress", "showDesktopMoreButton", "moreActions", "moreButtonAriaLabel", "interactiveOffset", "title", "subtitle", "showDivider", "dividerSpacing"], outputs: ["itemClick", "moreButtonClick"] }, { kind: "component", type: DsBadgeComponent, selector: "ds-badge", inputs: ["variant", "contentType", "content", "leadingIcon", "indicatorShape"] }, { kind: "component", type: DsMobileCardInlineBannerComponent, selector: "ds-mobile-card-inline-banner", inputs: ["title", "timestamp", "unreadCount", "layout"], outputs: ["bannerClick"] }, { kind: "component", type: DsMobileSectionComponent, selector: "ds-mobile-section", inputs: ["headline", "icon", "linkText", "padding", "paddingDesktop", "gap", "contentGap", "showBorder", "overflow"], outputs: ["linkClick"] }, { kind: "component", type: DsMobileInlinePhotoComponent, selector: "ds-mobile-inline-photo", inputs: ["images", "loadingStates", "author", "maxVisible", "useGrid"], outputs: ["photoClick"] }] });
30434
31234
  }
30435
31235
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: MobileInquiryDetailPageComponent, decorators: [{
30436
31236
  type: Component,
@@ -30438,6 +31238,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
30438
31238
  CommonModule,
30439
31239
  DsIconComponent,
30440
31240
  DsAvatarWithBadgeComponent,
31241
+ DsMobileVendorAvatarComponent,
30441
31242
  DsMobilePageDetailsComponent,
30442
31243
  DsMobileInteractiveListItemMessageComponent,
30443
31244
  DsMobileListItemComponent,
@@ -30458,26 +31259,35 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
30458
31259
 
30459
31260
  <!-- Messages Tab Content -->
30460
31261
  @if (activeTab() === 'messages') {
30461
- <ds-mobile-section contentGap="0">
30462
- @for (message of messageThreads; track message.id) {
30463
- <ds-mobile-interactive-list-item-message
30464
- [senderName]="message.senderName"
30465
- [senderRole]="message.role"
30466
- [timestamp]="message.timestamp"
30467
- [message]="message.message"
30468
- [avatarInitials]="message.senderInitials"
30469
- [showAvatarBadge]="true"
30470
- [unread]="message.unread"
30471
- (messageClick)="openMessage(message.id)">
30472
- </ds-mobile-interactive-list-item-message>
30473
- }
30474
- </ds-mobile-section>
31262
+ @if (activeMessages.length > 0) {
31263
+ <ds-mobile-section contentGap="0">
31264
+ @for (message of activeMessages; track message.id) {
31265
+ <ds-mobile-interactive-list-item-message
31266
+ [senderName]="message.senderName"
31267
+ [senderRole]="message.role"
31268
+ [timestamp]="message.timestamp"
31269
+ [message]="message.message"
31270
+ [avatarInitials]="message.senderInitials"
31271
+ [showAvatarBadge]="!isServiceInquiry"
31272
+ [unread]="message.unread"
31273
+ (messageClick)="openMessage(message.id)">
31274
+ </ds-mobile-interactive-list-item-message>
31275
+ }
31276
+ </ds-mobile-section>
31277
+ } @else {
31278
+ <ds-mobile-section>
31279
+ <div class="empty-messages">
31280
+ <img class="empty-messages-image" src="/Assets/Empty state-chat.png" alt="Ingen beskeder" />
31281
+ <p class="empty-messages-text">Ingen beskeder endnu</p>
31282
+ </div>
31283
+ </ds-mobile-section>
31284
+ }
30475
31285
  }
30476
31286
 
30477
31287
  <!-- Details Tab Content -->
30478
31288
  @if (activeTab() === 'details') {
30479
- <!-- Unread Messages Banner -->
30480
- @if (hasUnreadMessages()) {
31289
+ <!-- Unread Messages Banner (legacy only) -->
31290
+ @if (!isServiceInquiry && hasUnreadMessages()) {
30481
31291
  <ds-mobile-section>
30482
31292
  <ds-mobile-card-inline-banner
30483
31293
  [title]="'Du har ulæste beskeder'"
@@ -30488,41 +31298,57 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
30488
31298
  </ds-mobile-section>
30489
31299
  }
30490
31300
 
30491
- <!-- All Details in One Section -->
30492
31301
  <ds-mobile-section contentGap="0">
30493
- <!-- Assignee -->
30494
- <ds-mobile-list-item [leadingSize]="'32px'" [showDivider]="true">
30495
- <div content-leading>
30496
- <ds-avatar-with-badge
30497
- [size]="'sm'"
30498
- [type]="'initials'"
30499
- [initials]="'R'" />
30500
- </div>
30501
- <div content-main>
30502
- <div class="detail-label">Sagsbehandler</div>
30503
- <div class="detail-value">Ricki Meihlen</div>
30504
- </div>
30505
- </ds-mobile-list-item>
30506
-
30507
- <!-- Technician -->
30508
- <ds-mobile-list-item [leadingSize]="'32px'" [showDivider]="true">
30509
- <div content-leading>
30510
- <ds-avatar-with-badge
30511
- [size]="'sm'"
30512
- [type]="'initials'"
30513
- [initials]="'M'" />
30514
- </div>
30515
- <div content-main>
30516
- <div class="detail-label">Tekniker</div>
30517
- <div class="detail-value">Martin Smith</div>
30518
- </div>
30519
- </ds-mobile-list-item>
31302
+ <!-- Vendor company (service inquiries) -->
31303
+ @if (isServiceInquiry && vendorName) {
31304
+ <ds-mobile-list-item [leadingSize]="'32px'" [showDivider]="true">
31305
+ <div content-leading>
31306
+ <ds-mobile-vendor-avatar
31307
+ [name]="vendorName"
31308
+ [logo]="vendorLogo"
31309
+ size="md" />
31310
+ </div>
31311
+ <div content-main>
31312
+ <div class="detail-label">Leverandør</div>
31313
+ <div class="detail-value">{{ vendorName }}</div>
31314
+ </div>
31315
+ </ds-mobile-list-item>
31316
+ }
31317
+
31318
+ <!-- Assignee + Technician (legacy inquiries only) -->
31319
+ @if (!isServiceInquiry) {
31320
+ <ds-mobile-list-item [leadingSize]="'32px'" [showDivider]="true">
31321
+ <div content-leading>
31322
+ <ds-avatar-with-badge
31323
+ [size]="'sm'"
31324
+ [type]="'initials'"
31325
+ [initials]="'R'" />
31326
+ </div>
31327
+ <div content-main>
31328
+ <div class="detail-label">Sagsbehandler</div>
31329
+ <div class="detail-value">Ricki Meihlen</div>
31330
+ </div>
31331
+ </ds-mobile-list-item>
31332
+
31333
+ <ds-mobile-list-item [leadingSize]="'32px'" [showDivider]="true">
31334
+ <div content-leading>
31335
+ <ds-avatar-with-badge
31336
+ [size]="'sm'"
31337
+ [type]="'initials'"
31338
+ [initials]="'M'" />
31339
+ </div>
31340
+ <div content-main>
31341
+ <div class="detail-label">Tekniker</div>
31342
+ <div class="detail-value">Martin Smith</div>
31343
+ </div>
31344
+ </ds-mobile-list-item>
31345
+ }
30520
31346
 
30521
31347
  <!-- Creation Date -->
30522
31348
  <ds-mobile-list-item [leadingSize]="'32px'" [showDivider]="true" [align]="'center'">
30523
31349
  <ds-icon content-leading name="remixTimeLine" size="20px" color="tertiary" />
30524
31350
  <div content-main>
30525
- <div class="detail-value">22. feb 2025</div>
31351
+ <div class="detail-value">{{ inquiryTimestamp }}</div>
30526
31352
  </div>
30527
31353
  </ds-mobile-list-item>
30528
31354
 
@@ -30535,30 +31361,32 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
30535
31361
  </ds-mobile-list-item>
30536
31362
 
30537
31363
  <!-- Description -->
30538
- <ds-mobile-list-item [leadingSize]="'32px'" [showDivider]="photoUrls.length > 0">
31364
+ <ds-mobile-list-item [leadingSize]="'32px'" [showDivider]="!isServiceInquiry && photoUrls.length > 0">
30539
31365
  <ds-icon content-leading name="remixAlignLeft" size="20px" color="tertiary" />
30540
31366
  <div content-main style="display:flex;flex-direction:column;gap:8px">
30541
31367
  <div class="detail-value description-text">
30542
- I de sidste tre dage har vi oplevet vedvarende problemer med tørretumbleren i vores lejlighed. På trods af at vi følger betjeningsvejledningen, fejler maskinen konsekvent i at fuldføre sine tørrecyklusser.
31368
+ {{ inquiryDescription }}
30543
31369
  </div>
30544
- <ds-badge content="Husholdningsapparater" size="sm"/>
31370
+ <ds-badge [content]="inquiryCategory" size="sm"/>
30545
31371
  </div>
30546
31372
  </ds-mobile-list-item>
30547
31373
 
30548
- <!-- Photos -->
30549
- <ds-mobile-list-item [leadingSize]="'32px'" [showDivider]="false">
30550
- <ds-icon content-leading name="remixCameraLine" size="20px" color="tertiary" />
30551
- <div content-main>
30552
- <ds-mobile-inline-photo
30553
- [images]="photoUrls"
30554
- [useGrid]="false"
30555
- (photoClick)="openPhotoLightbox($event.index)" />
30556
- </div>
30557
- </ds-mobile-list-item>
31374
+ <!-- Photos (legacy inquiries only) -->
31375
+ @if (!isServiceInquiry) {
31376
+ <ds-mobile-list-item [leadingSize]="'32px'" [showDivider]="false">
31377
+ <ds-icon content-leading name="remixCameraLine" size="20px" color="tertiary" />
31378
+ <div content-main>
31379
+ <ds-mobile-inline-photo
31380
+ [images]="photoUrls"
31381
+ [useGrid]="false"
31382
+ (photoClick)="openPhotoLightbox($event.index)" />
31383
+ </div>
31384
+ </ds-mobile-list-item>
31385
+ }
30558
31386
  </ds-mobile-section>
30559
31387
  }
30560
31388
  </ds-mobile-page-details>
30561
- `, styles: [".activity-list{display:flex;flex-direction:column;gap:12px;position:relative}.activity-list ds-mobile-list-item:not(:last-child) [content-leading]:after{content:\"\";position:absolute;top:40px;left:50%;transform:translate(-50%);width:1px;height:calc(100% - 2px);background:var(--border-color-default, #e5e5e5);z-index:0}.activity-icon-wrapper{width:100%;height:100%;border-radius:8px;background:var(--color-background-neutral-secondary, #f5f5f5);display:flex;align-items:center;justify-content:center;flex-shrink:0;position:relative;z-index:1}.avatar-wrapper{position:relative;display:flex;align-items:start;justify-content:center;flex-shrink:0;width:100%;height:100%;z-index:1}.avatar-badge{position:absolute;bottom:-6px;right:-6px;width:20px;height:20px;border-radius:8px;background:var(--color-brand-secondary, #5d5fef);display:flex;align-items:center;justify-content:center;border:2px solid var(--color-background-primary, #ffffff)}.avatar-badge svg{width:10px;position:relative;top:1px;fill:#fff}.activity-content{display:flex;flex-direction:column;gap:4px}.activity-title{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);font-weight:500;line-height:20px;letter-spacing:-.3px;color:var(--text-color-default-primary, #202227);margin:0}.activity-title .actor-name{font-weight:600;color:var(--text-color-default-primary, #202227)}.activity-title .activity-text{color:var(--text-color-default-secondary, #545B66);font-weight:400}.activity-description{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);font-weight:400;line-height:20px;letter-spacing:-.3px;color:var(--text-color-default-secondary, #545B66);margin:0}.activity-timestamp{font-family:Brockmann,sans-serif;font-size:var(--font-size-xs);font-weight:400;line-height:1.2;letter-spacing:-.26px;color:var(--text-color-default-tertiary, #737373);display:flex;align-items:center;gap:4px;margin-top:2px}.detail-label{font-family:Brockmann,sans-serif;font-size:var(--font-size-xs);font-weight:400;line-height:1.2;letter-spacing:-.26px;color:var(--text-color-default-tertiary, #737373)}.detail-value{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);font-weight:400;line-height:24px;letter-spacing:-.3px;color:var(--text-color-default-primary, #202227)}.detail-tag{display:inline-flex;align-items:center;padding:4px 12px;border-radius:12px;background:var(--color-background-neutral-secondary, #f5f5f5);font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);font-weight:500;color:var(--text-color-default-secondary, #525866);margin-top:4px;margin-bottom:10px;width:-moz-fit-content;width:fit-content}.photo-grid{display:grid;grid-template-columns:repeat(6,1fr);gap:8px}.photo-add{width:100%;aspect-ratio:1;border-radius:12px;border:1px dashed var(--border-color-default, #e5e5e5);background:var(--color-background-neutral-secondary, #f5f5f5);display:flex;align-items:center;justify-content:center;cursor:pointer}.photo-item{width:100%;aspect-ratio:1;border-radius:12px;-o-object-fit:cover;object-fit:cover}\n"] }]
31389
+ `, styles: [".activity-list{display:flex;flex-direction:column;gap:12px;position:relative}.activity-list ds-mobile-list-item:not(:last-child) [content-leading]:after{content:\"\";position:absolute;top:40px;left:50%;transform:translate(-50%);width:1px;height:calc(100% - 2px);background:var(--border-color-default, #e5e5e5);z-index:0}.activity-icon-wrapper{width:100%;height:100%;border-radius:8px;background:var(--color-background-neutral-secondary, #f5f5f5);display:flex;align-items:center;justify-content:center;flex-shrink:0;position:relative;z-index:1}.avatar-wrapper{position:relative;display:flex;align-items:start;justify-content:center;flex-shrink:0;width:100%;height:100%;z-index:1}.avatar-badge{position:absolute;bottom:-6px;right:-6px;width:20px;height:20px;border-radius:8px;background:var(--color-brand-secondary, #5d5fef);display:flex;align-items:center;justify-content:center;border:2px solid var(--color-background-primary, #ffffff)}.avatar-badge svg{width:10px;position:relative;top:1px;fill:#fff}.activity-content{display:flex;flex-direction:column;gap:4px}.activity-title{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);font-weight:500;line-height:20px;letter-spacing:-.3px;color:var(--text-color-default-primary, #202227);margin:0}.activity-title .actor-name{font-weight:600;color:var(--text-color-default-primary, #202227)}.activity-title .activity-text{color:var(--text-color-default-secondary, #545B66);font-weight:400}.activity-description{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);font-weight:400;line-height:20px;letter-spacing:-.3px;color:var(--text-color-default-secondary, #545B66);margin:0}.activity-timestamp{font-family:Brockmann,sans-serif;font-size:var(--font-size-xs);font-weight:400;line-height:1.2;letter-spacing:-.26px;color:var(--text-color-default-tertiary, #737373);display:flex;align-items:center;gap:4px;margin-top:2px}.detail-label{font-family:Brockmann,sans-serif;font-size:var(--font-size-xs);font-weight:400;line-height:1.2;letter-spacing:-.26px;color:var(--text-color-default-tertiary, #737373)}.detail-value{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);font-weight:400;line-height:24px;letter-spacing:-.3px;color:var(--text-color-default-primary, #202227)}.detail-tag{display:inline-flex;align-items:center;padding:4px 12px;border-radius:12px;background:var(--color-background-neutral-secondary, #f5f5f5);font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);font-weight:500;color:var(--text-color-default-secondary, #525866);margin-top:4px;margin-bottom:10px;width:-moz-fit-content;width:fit-content}.photo-grid{display:grid;grid-template-columns:repeat(6,1fr);gap:8px}.photo-add{width:100%;aspect-ratio:1;border-radius:12px;border:1px dashed var(--border-color-default, #e5e5e5);background:var(--color-background-neutral-secondary, #f5f5f5);display:flex;align-items:center;justify-content:center;cursor:pointer}.photo-item{width:100%;aspect-ratio:1;border-radius:12px;-o-object-fit:cover;object-fit:cover}.empty-messages{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:60px 20px;gap:12px}.empty-messages-image{width:96px;height:96px;-o-object-fit:contain;object-fit:contain}.empty-messages-text{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm, 14px);color:var(--text-color-default-secondary, #71727a);margin:0}\n"] }]
30562
31390
  }], ctorParameters: () => [{ type: UserService }, { type: DsMobileLightboxService }, { type: DsMobileChatModalService }] });
30563
31391
 
30564
31392
  /**
@@ -31727,6 +32555,12 @@ class MobileTabsExampleComponent {
31727
32555
  icon: 'remixGroupLine',
31728
32556
  destructive: false,
31729
32557
  },
32558
+ {
32559
+ action: 'manage-admins',
32560
+ title: 'Fællesskabsadministrator',
32561
+ icon: 'remixUserStarLine',
32562
+ destructive: false,
32563
+ },
31730
32564
  ];
31731
32565
  if (this.trackingPermissionService.shouldShowSettingsReminder()) {
31732
32566
  accountActions.push({
@@ -31829,6 +32663,13 @@ class MobileTabsExampleComponent {
31829
32663
  iconActive: 'remixMessage3Fill',
31830
32664
  route: 'messages',
31831
32665
  },
32666
+ {
32667
+ id: 'services',
32668
+ label: 'Services',
32669
+ icon: 'remixServiceLine',
32670
+ iconActive: 'remixServiceFill',
32671
+ route: 'services',
32672
+ },
31832
32673
  ];
31833
32674
  /**
31834
32675
  * Profile menu items configuration.
@@ -31854,6 +32695,11 @@ class MobileTabsExampleComponent {
31854
32695
  animation: customPageTransition
31855
32696
  });
31856
32697
  }
32698
+ if (result.action === 'manage-admins') {
32699
+ this.navCtrl.navigateForward(['/community-admins'], {
32700
+ animation: customPageTransition
32701
+ });
32702
+ }
31857
32703
  // Handle appearance action here (opens modal)
31858
32704
  if (result.action === 'appearance') {
31859
32705
  console.log('Opening whitelabel demo...');
@@ -34533,12 +35379,15 @@ class FamilyAccessPageComponent {
34533
35379
  <ds-mobile-section>
34534
35380
  <div class="members-list">
34535
35381
  @for (member of service.members(); track member.id; let isFirst = $first; let isLast = $last) {
34536
- <ds-mobile-list-item [showDivider]="!isLast" [leadingSize]="'36px'" [flushTop]="isFirst">
35382
+ <ds-mobile-list-item [showDivider]="!isLast" [leadingSize]="'32px'" [flushTop]="isFirst">
34537
35383
 
34538
35384
  <div content-leading>
34539
- <div class="member-avatar member-avatar--{{ member.status }}">
34540
- {{ member.initials }}
34541
- </div>
35385
+ <ds-avatar-with-badge
35386
+ type="initials"
35387
+ [initials]="member.initials"
35388
+ size="md"
35389
+ [showBadge]="false"
35390
+ />
34542
35391
  </div>
34543
35392
 
34544
35393
  <div content-main class="member-details">
@@ -34581,7 +35430,7 @@ class FamilyAccessPageComponent {
34581
35430
  }
34582
35431
 
34583
35432
  </ds-mobile-page-details>
34584
- `, isInline: true, styles: [".empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:20px;text-align:center}.empty-state-title{font-family:Brockmann,sans-serif;font-size:var(--font-size-base);font-weight:600;color:var(--color-text-primary);margin-top:-16px;z-index:4}.empty-state-description{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);color:var(--color-text-secondary);margin:0}.empty-state ds-button{display:block;margin-top:16px}.empty-state ds-button::ng-deep .btn{width:100%;border-radius:9999px}.invite-cta{padding:8px 0 4px}.invite-cta ds-button{display:block;width:100%}.invite-cta ::ng-deep ds-button>button{width:100%;border-radius:9999px}.members-list{display:flex;flex-direction:column;gap:0}.member-avatar{width:36px;height:36px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:13px;font-weight:600}.member-avatar--active{background:var(--color-background-brand-secondary, #EEF0FF);color:var(--color-brand-secondary, #6B5FF5)}.member-avatar--pending{background:var(--color-background-warning-secondary, #FEF3C7);color:var(--color-warning-base, #d97706)}.member-avatar--expired{background:var(--color-background-error-secondary, #FEE2E2);color:var(--color-error-base, #dc2626)}.member-details{display:flex;flex-direction:column;gap:2px;min-width:0;flex:1}.member-name{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);font-weight:600;line-height:20px;letter-spacing:-.3px;color:var(--color-text-primary, #1a1a1a);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.member-status-row{display:flex;align-items:center;gap:6px;font-family:Brockmann,sans-serif;font-size:var(--font-size-xs);font-weight:400;line-height:1.2;letter-spacing:-.26px;color:var(--color-text-tertiary, #737373)}.status-dot{width:7px;height:7px;border-radius:50%;flex-shrink:0}.status-dot--active{background:var(--color-success-base, #158452)}.status-dot--pending{background:var(--color-warning-base, #d97706)}.status-dot--expired{background:var(--color-error-base, #dc2626)}.member-trailing-action{display:flex;align-items:center}.member-trailing-action ds-icon-button::ng-deep button{box-sizing:border-box;width:2rem;height:2rem;min-width:2rem;border-radius:50%!important}@keyframes slideDown{0%{transform:translateY(-100%);opacity:0}to{transform:translateY(0);opacity:1}}.success-toast{padding:10px 14px;border-radius:12px;background:var(--color-background-success-secondary, #DCFCE7);display:flex;align-items:center;gap:10px;font-size:14px;font-weight:500;color:var(--color-success-base, #158452);animation:slideDown .2s ease-out}.toast-icon{width:20px;height:20px;border-radius:50%;background:var(--color-success-base, #158452);display:flex;align-items:center;justify-content:center;flex-shrink:0}.toast-dismiss{margin-left:auto;background:none;border:none;cursor:pointer;flex-shrink:0}\n"], dependencies: [{ kind: "component", type: DsMobilePageDetailsComponent, selector: "ds-mobile-page-details", inputs: ["title", "backRoute", "contentPadding", "tabs", "activeTab", "showRefresh", "scrollThreshold", "headerFadeDistance"], outputs: ["back", "tabChange", "refresh", "scroll"] }, { kind: "component", type: DsMobileSectionComponent, selector: "ds-mobile-section", inputs: ["headline", "icon", "linkText", "padding", "paddingDesktop", "gap", "contentGap", "showBorder", "overflow"], outputs: ["linkClick"] }, { kind: "component", type: DsMobileIllustrationComponent, selector: "ds-mobile-illustration", inputs: ["variant", "size", "alt"] }, { kind: "component", type: DsMobileListItemComponent, selector: "ds-mobile-list-item", inputs: ["leadingSize", "variant", "align", "flushTop", "interactive", "disabled", "loading", "enableLongPress", "showDesktopMoreButton", "moreActions", "moreButtonAriaLabel", "interactiveOffset", "title", "subtitle", "showDivider", "dividerSpacing"], outputs: ["itemClick", "moreButtonClick"] }, { kind: "component", type: DsButtonComponent, selector: "ds-button", inputs: ["variant", "size", "disabled", "loading", "pressed", "expanded", "leadingIcon", "trailingIcon", "ariaLabel", "iconOnly"], outputs: ["clicked", "focused", "blurred"] }, { kind: "component", type: DsIconButtonComponent, selector: "ds-icon-button", inputs: ["variant", "size", "icon", "disabled", "loading", "pressed", "expanded", "ariaLabel", "tooltip", "tooltipDisabled", "tooltipPlacement"], outputs: ["clicked", "focused", "blurred"] }] });
35433
+ `, isInline: true, styles: [".empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:20px;text-align:center}.empty-state-title{font-family:Brockmann,sans-serif;font-size:var(--font-size-base);font-weight:600;color:var(--color-text-primary);margin-top:-16px;z-index:4}.empty-state-description{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);color:var(--color-text-secondary);margin:0}.empty-state ds-button{display:block;margin-top:16px}.empty-state ds-button::ng-deep .btn{width:100%;border-radius:9999px}.invite-cta{padding:8px 0 4px}.invite-cta ds-button{display:block;width:100%}.invite-cta ::ng-deep ds-button>button{width:100%;border-radius:9999px}.members-list{display:flex;flex-direction:column;gap:0}.member-details{display:flex;flex-direction:column;gap:2px;min-width:0;flex:1}.member-name{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);font-weight:600;line-height:20px;letter-spacing:-.3px;color:var(--color-text-primary, #1a1a1a);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.member-status-row{display:flex;align-items:center;gap:6px;font-family:Brockmann,sans-serif;font-size:var(--font-size-xs);font-weight:400;line-height:1.2;letter-spacing:-.26px;color:var(--color-text-tertiary, #737373)}.status-dot{width:7px;height:7px;border-radius:50%;flex-shrink:0}.status-dot--active{background:var(--color-success-base, #158452)}.status-dot--pending{background:var(--color-warning-base, #d97706)}.status-dot--expired{background:var(--color-error-base, #dc2626)}.member-trailing-action{display:flex;align-items:center}.member-trailing-action ds-icon-button::ng-deep button{box-sizing:border-box;width:2rem;height:2rem;min-width:2rem;border-radius:50%!important}@keyframes slideDown{0%{transform:translateY(-100%);opacity:0}to{transform:translateY(0);opacity:1}}.success-toast{padding:10px 14px;border-radius:12px;background:var(--color-background-success-secondary, #DCFCE7);display:flex;align-items:center;gap:10px;font-size:14px;font-weight:500;color:var(--color-success-base, #158452);animation:slideDown .2s ease-out}.toast-icon{width:20px;height:20px;border-radius:50%;background:var(--color-success-base, #158452);display:flex;align-items:center;justify-content:center;flex-shrink:0}.toast-dismiss{margin-left:auto;background:none;border:none;cursor:pointer;flex-shrink:0}\n"], dependencies: [{ kind: "component", type: DsMobilePageDetailsComponent, selector: "ds-mobile-page-details", inputs: ["title", "backRoute", "contentPadding", "tabs", "activeTab", "showRefresh", "scrollThreshold", "headerFadeDistance"], outputs: ["back", "tabChange", "refresh", "scroll"] }, { kind: "component", type: DsMobileSectionComponent, selector: "ds-mobile-section", inputs: ["headline", "icon", "linkText", "padding", "paddingDesktop", "gap", "contentGap", "showBorder", "overflow"], outputs: ["linkClick"] }, { kind: "component", type: DsMobileIllustrationComponent, selector: "ds-mobile-illustration", inputs: ["variant", "size", "alt"] }, { kind: "component", type: DsMobileListItemComponent, selector: "ds-mobile-list-item", inputs: ["leadingSize", "variant", "align", "flushTop", "interactive", "disabled", "loading", "enableLongPress", "showDesktopMoreButton", "moreActions", "moreButtonAriaLabel", "interactiveOffset", "title", "subtitle", "showDivider", "dividerSpacing"], outputs: ["itemClick", "moreButtonClick"] }, { kind: "component", type: DsAvatarWithBadgeComponent, selector: "ds-avatar-with-badge", inputs: ["type", "size", "initials", "src", "iconName", "showBadge", "badgePosition"] }, { kind: "component", type: DsButtonComponent, selector: "ds-button", inputs: ["variant", "size", "disabled", "loading", "pressed", "expanded", "leadingIcon", "trailingIcon", "ariaLabel", "iconOnly"], outputs: ["clicked", "focused", "blurred"] }, { kind: "component", type: DsIconButtonComponent, selector: "ds-icon-button", inputs: ["variant", "size", "icon", "disabled", "loading", "pressed", "expanded", "ariaLabel", "tooltip", "tooltipDisabled", "tooltipPlacement"], outputs: ["clicked", "focused", "blurred"] }] });
34585
35434
  }
34586
35435
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: FamilyAccessPageComponent, decorators: [{
34587
35436
  type: Component,
@@ -34590,6 +35439,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
34590
35439
  DsMobileSectionComponent,
34591
35440
  DsMobileIllustrationComponent,
34592
35441
  DsMobileListItemComponent,
35442
+ DsAvatarWithBadgeComponent,
34593
35443
  DsButtonComponent,
34594
35444
  DsIconButtonComponent,
34595
35445
  ], template: `
@@ -34634,12 +35484,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
34634
35484
  <ds-mobile-section>
34635
35485
  <div class="members-list">
34636
35486
  @for (member of service.members(); track member.id; let isFirst = $first; let isLast = $last) {
34637
- <ds-mobile-list-item [showDivider]="!isLast" [leadingSize]="'36px'" [flushTop]="isFirst">
35487
+ <ds-mobile-list-item [showDivider]="!isLast" [leadingSize]="'32px'" [flushTop]="isFirst">
34638
35488
 
34639
35489
  <div content-leading>
34640
- <div class="member-avatar member-avatar--{{ member.status }}">
34641
- {{ member.initials }}
34642
- </div>
35490
+ <ds-avatar-with-badge
35491
+ type="initials"
35492
+ [initials]="member.initials"
35493
+ size="md"
35494
+ [showBadge]="false"
35495
+ />
34643
35496
  </div>
34644
35497
 
34645
35498
  <div content-main class="member-details">
@@ -34682,7 +35535,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
34682
35535
  }
34683
35536
 
34684
35537
  </ds-mobile-page-details>
34685
- `, styles: [".empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:20px;text-align:center}.empty-state-title{font-family:Brockmann,sans-serif;font-size:var(--font-size-base);font-weight:600;color:var(--color-text-primary);margin-top:-16px;z-index:4}.empty-state-description{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);color:var(--color-text-secondary);margin:0}.empty-state ds-button{display:block;margin-top:16px}.empty-state ds-button::ng-deep .btn{width:100%;border-radius:9999px}.invite-cta{padding:8px 0 4px}.invite-cta ds-button{display:block;width:100%}.invite-cta ::ng-deep ds-button>button{width:100%;border-radius:9999px}.members-list{display:flex;flex-direction:column;gap:0}.member-avatar{width:36px;height:36px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:13px;font-weight:600}.member-avatar--active{background:var(--color-background-brand-secondary, #EEF0FF);color:var(--color-brand-secondary, #6B5FF5)}.member-avatar--pending{background:var(--color-background-warning-secondary, #FEF3C7);color:var(--color-warning-base, #d97706)}.member-avatar--expired{background:var(--color-background-error-secondary, #FEE2E2);color:var(--color-error-base, #dc2626)}.member-details{display:flex;flex-direction:column;gap:2px;min-width:0;flex:1}.member-name{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);font-weight:600;line-height:20px;letter-spacing:-.3px;color:var(--color-text-primary, #1a1a1a);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.member-status-row{display:flex;align-items:center;gap:6px;font-family:Brockmann,sans-serif;font-size:var(--font-size-xs);font-weight:400;line-height:1.2;letter-spacing:-.26px;color:var(--color-text-tertiary, #737373)}.status-dot{width:7px;height:7px;border-radius:50%;flex-shrink:0}.status-dot--active{background:var(--color-success-base, #158452)}.status-dot--pending{background:var(--color-warning-base, #d97706)}.status-dot--expired{background:var(--color-error-base, #dc2626)}.member-trailing-action{display:flex;align-items:center}.member-trailing-action ds-icon-button::ng-deep button{box-sizing:border-box;width:2rem;height:2rem;min-width:2rem;border-radius:50%!important}@keyframes slideDown{0%{transform:translateY(-100%);opacity:0}to{transform:translateY(0);opacity:1}}.success-toast{padding:10px 14px;border-radius:12px;background:var(--color-background-success-secondary, #DCFCE7);display:flex;align-items:center;gap:10px;font-size:14px;font-weight:500;color:var(--color-success-base, #158452);animation:slideDown .2s ease-out}.toast-icon{width:20px;height:20px;border-radius:50%;background:var(--color-success-base, #158452);display:flex;align-items:center;justify-content:center;flex-shrink:0}.toast-dismiss{margin-left:auto;background:none;border:none;cursor:pointer;flex-shrink:0}\n"] }]
35538
+ `, styles: [".empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:20px;text-align:center}.empty-state-title{font-family:Brockmann,sans-serif;font-size:var(--font-size-base);font-weight:600;color:var(--color-text-primary);margin-top:-16px;z-index:4}.empty-state-description{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);color:var(--color-text-secondary);margin:0}.empty-state ds-button{display:block;margin-top:16px}.empty-state ds-button::ng-deep .btn{width:100%;border-radius:9999px}.invite-cta{padding:8px 0 4px}.invite-cta ds-button{display:block;width:100%}.invite-cta ::ng-deep ds-button>button{width:100%;border-radius:9999px}.members-list{display:flex;flex-direction:column;gap:0}.member-details{display:flex;flex-direction:column;gap:2px;min-width:0;flex:1}.member-name{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);font-weight:600;line-height:20px;letter-spacing:-.3px;color:var(--color-text-primary, #1a1a1a);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.member-status-row{display:flex;align-items:center;gap:6px;font-family:Brockmann,sans-serif;font-size:var(--font-size-xs);font-weight:400;line-height:1.2;letter-spacing:-.26px;color:var(--color-text-tertiary, #737373)}.status-dot{width:7px;height:7px;border-radius:50%;flex-shrink:0}.status-dot--active{background:var(--color-success-base, #158452)}.status-dot--pending{background:var(--color-warning-base, #d97706)}.status-dot--expired{background:var(--color-error-base, #dc2626)}.member-trailing-action{display:flex;align-items:center}.member-trailing-action ds-icon-button::ng-deep button{box-sizing:border-box;width:2rem;height:2rem;min-width:2rem;border-radius:50%!important}@keyframes slideDown{0%{transform:translateY(-100%);opacity:0}to{transform:translateY(0);opacity:1}}.success-toast{padding:10px 14px;border-radius:12px;background:var(--color-background-success-secondary, #DCFCE7);display:flex;align-items:center;gap:10px;font-size:14px;font-weight:500;color:var(--color-success-base, #158452);animation:slideDown .2s ease-out}.toast-icon{width:20px;height:20px;border-radius:50%;background:var(--color-success-base, #158452);display:flex;align-items:center;justify-content:center;flex-shrink:0}.toast-dismiss{margin-left:auto;background:none;border:none;cursor:pointer;flex-shrink:0}\n"] }]
34686
35539
  }] });
34687
35540
 
34688
35541
  class AcceptInvitePageComponent {
@@ -35105,6 +35958,228 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
35105
35958
  `, styles: [".empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:64px 20px;text-align:center}.empty-state-image{width:96px;height:96px;margin-bottom:24px;opacity:.4}.empty-state-title{font-family:Brockmann,sans-serif;font-size:var(--font-size-base);font-weight:600;color:var(--color-text-primary);margin:0 0 8px}.empty-state-description{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);color:var(--color-text-secondary);margin:0}\n"] }]
35106
35959
  }] });
35107
35960
 
35961
+ const DEFAULT_SERVICE_PAGE_LABELS = {
35962
+ pageTitle: 'Services',
35963
+ emptyState: 'Ingen services tilknyttet',
35964
+ emptyStateDescription: 'Der er ingen serviceaftaler knyttet til din ejendom endnu.',
35965
+ };
35966
+ function stripHtml(html) {
35967
+ const div = document.createElement('div');
35968
+ div.innerHTML = html;
35969
+ return div.textContent?.trim() || '';
35970
+ }
35971
+ const MOCK_VENDORS = [
35972
+ {
35973
+ id: 'v-1',
35974
+ name: 'CleanTeam ApS',
35975
+ category: 'Rengøring',
35976
+ description: 'Trappevask og vinduespolering',
35977
+ phone: '+45 70 20 30 40',
35978
+ logo: '/Assets/dummy-logos/cleanteam-logo.svg',
35979
+ thumbnail: '/Assets/Dummy-photos/clean-team.jpg',
35980
+ fullDescription: '<h3>Rengøring</h3><p>CleanTeam ApS tilbyder professionel trappevask og vinduespolering for ejendommen. Servicen udføres ugentligt og kan tilpasses jeres behov.</p><h3>Pris</h3><p>350 kr. per besøg</p>',
35981
+ price: '350 kr. per besøg',
35982
+ availabilityStatus: 'available-today',
35983
+ statusLabel: 'Ledig i dag',
35984
+ },
35985
+ {
35986
+ id: 'v-2',
35987
+ name: 'Nordisk Rengøring',
35988
+ category: 'Rengøring',
35989
+ description: 'Erhvervs- og boligrengøring',
35990
+ logo: '/Assets/dummy-logos/nordiccleaning-logo.svg',
35991
+ thumbnail: '/Assets/Dummy-photos/nordic-cleaning.jpg',
35992
+ heroImage: '/Assets/Dummy-photos/nordic-cleaning.jpg',
35993
+ fullDescription: '<h3>Rengøring</h3><p>Nordisk Rengøring leverer fleksibel erhvervs- og boligrengøring. Vi tilpasser rengøringen til jeres specifikke behov.</p><h3>Pris</h3><p>275 kr. per time</p>',
35994
+ price: '275 kr. per time',
35995
+ availabilityStatus: 'available-from',
35996
+ statusLabel: 'Ledig fra 5. maj',
35997
+ },
35998
+ {
35999
+ id: 'v-3',
36000
+ name: 'Blik Partner A/S',
36001
+ category: 'VVS',
36002
+ description: 'VVS-service og akut udkald',
36003
+ phone: '+45 33 44 55 66',
36004
+ thumbnail: '/Assets/Dummy-photos/plumbing.jpg',
36005
+ fullDescription: '<h3>VVS</h3><p>BlikPartner A/S er jeres VVS-partner til alt fra løbende vedligeholdelse til akutte udkald. Vi dækker reparation af vandrør, afløb, radiatorer og blandingsbatterier.</p><h3>Pris</h3><p>450 kr. per udkald + tid</p>',
36006
+ price: '450 kr. per udkald + tid',
36007
+ availabilityStatus: 'available-today',
36008
+ statusLabel: 'Ledig i dag',
36009
+ },
36010
+ {
36011
+ id: 'v-4',
36012
+ name: 'ElektroTek ApS',
36013
+ category: 'Elektriker',
36014
+ description: 'El-installationer og fejlsøgning',
36015
+ phone: '+45 23 45 67 89',
36016
+ logo: '/Assets/dummy-logos/electrician-logo.svg',
36017
+ thumbnail: '/Assets/Dummy-photos/electrician.jpg',
36018
+ heroImage: '/Assets/Dummy-photos/electrician.jpg',
36019
+ fullDescription: '<h3>Elektriker</h3><p>ElektroTek ApS varetager el-installationer, fejlsøgning og lovpligtige eftersyn for ejendommen. Vi udfører også småopgaver som udskiftning af kontakter og lampeudtag.</p><h3>Pris</h3><p>395 kr. per time</p>',
36020
+ price: '395 kr. per time',
36021
+ availabilityStatus: 'available-today',
36022
+ statusLabel: 'Ledig i dag',
36023
+ },
36024
+ {
36025
+ id: 'v-5',
36026
+ name: 'HaveService Danmark',
36027
+ category: 'Have & Grønne arealer',
36028
+ description: 'Pleje af fællesarealer og haver',
36029
+ logo: '/Assets/dummy-logos/gardener-logo.svg',
36030
+ thumbnail: '/Assets/Dummy-photos/gardener.jpg',
36031
+ heroImage: '/Assets/Dummy-photos/gardener.jpg',
36032
+ fullDescription: '<h3>Have & Grønne arealer</h3><p>HaveService Danmark står for den løbende pleje af fællesarealer og haver — herunder græsslåning, hækklipning, ukrudtsbekæmpelse og sæsonbeplantning.</p><h3>Pris</h3><p>500 kr. per besøg</p>',
36033
+ price: '500 kr. per besøg',
36034
+ availabilityStatus: 'unavailable',
36035
+ statusLabel: 'Ikke tilgængelig',
36036
+ },
36037
+ ];
36038
+ class ServicesPageComponent {
36039
+ pageComponent;
36040
+ vendorModal = inject(DsMobileServiceVendorModalService);
36041
+ newInquiryModal = inject(DsMobileNewInquiryModalService);
36042
+ inquiriesService = inject(InquiriesService);
36043
+ navCtrl = inject(NavController);
36044
+ userService = inject(UserService);
36045
+ lbl = { ...DEFAULT_SERVICE_PAGE_LABELS };
36046
+ vendors = signal(MOCK_VENDORS, ...(ngDevMode ? [{ debugName: "vendors" }] : []));
36047
+ stripHtml = stripHtml;
36048
+ async openVendorSheet(vendor) {
36049
+ const modal = await this.vendorModal.open({
36050
+ vendorName: vendor.name,
36051
+ vendorDescription: vendor.fullDescription || vendor.description || '',
36052
+ vendorImage: vendor.heroImage || '',
36053
+ vendorLogo: vendor.logo,
36054
+ });
36055
+ const result = await modal.onWillDismiss();
36056
+ if (result.role === 'book') {
36057
+ await this.openInquiryForVendor(vendor);
36058
+ }
36059
+ }
36060
+ async openInquiryForVendor(vendor) {
36061
+ await this.newInquiryModal.open({
36062
+ titlePlaceholder: 'Emne for henvendelsen',
36063
+ descriptionPlaceholder: 'Beskriv hvad du har brug for…',
36064
+ submitButtonLabel: 'Send henvendelse',
36065
+ category: vendor.category,
36066
+ onSubmit: async (data) => {
36067
+ const inquiryId = `service-${Date.now()}`;
36068
+ this.inquiriesService.addInquiry({
36069
+ id: inquiryId,
36070
+ title: data.title,
36071
+ description: data.description,
36072
+ status: 'open',
36073
+ timestamp: 'Lige nu',
36074
+ category: data.category || vendor.category,
36075
+ vendorName: vendor.name,
36076
+ vendorLogo: vendor.logo,
36077
+ });
36078
+ await this.newInquiryModal.close();
36079
+ setTimeout(() => {
36080
+ this.navCtrl.navigateForward([`/inquiry-detail/${inquiryId}`], {
36081
+ animation: customPageTransition,
36082
+ });
36083
+ }, 300);
36084
+ },
36085
+ });
36086
+ }
36087
+ handleRefresh(event) {
36088
+ setTimeout(() => {
36089
+ event.target?.complete?.();
36090
+ }, 1000);
36091
+ }
36092
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: ServicesPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
36093
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: ServicesPageComponent, isStandalone: true, selector: "app-services-page", viewQueries: [{ propertyName: "pageComponent", first: true, predicate: ["pageComponent"], descendants: true }], ngImport: i0, template: `
36094
+ <ds-mobile-page-main
36095
+ #pageComponent
36096
+ [title]="lbl.pageTitle"
36097
+ [avatarInitials]="userService.avatarInitials()"
36098
+ [avatarType]="userService.avatarType()"
36099
+ (refresh)="handleRefresh($event)"
36100
+ >
36101
+ @if (pageComponent.isOffline()) {
36102
+ <ds-mobile-offline-banner
36103
+ offline-indicator
36104
+ title="Ingen internetforbindelse"
36105
+ message="Nogle funktioner kan være utilgængelige"
36106
+ />
36107
+ }
36108
+
36109
+ @if (vendors().length === 0) {
36110
+ <ds-mobile-section>
36111
+ <div class="empty-state">
36112
+ <ds-mobile-illustration variant="inquiry" [alt]="lbl.emptyState" />
36113
+ <h3 class="empty-state-title">{{ lbl.emptyState }}</h3>
36114
+ <p class="empty-state-description">{{ lbl.emptyStateDescription }}</p>
36115
+ </div>
36116
+ </ds-mobile-section>
36117
+ } @else {
36118
+ <ds-mobile-section contentGap="0px">
36119
+ @for (vendor of vendors(); track vendor.id) {
36120
+ <ds-mobile-interactive-list-item-service
36121
+ [title]="vendor.name"
36122
+ [description]="stripHtml(vendor.fullDescription || vendor.description || '')"
36123
+ [logo]="vendor.logo || ''"
36124
+ (serviceClick)="openVendorSheet(vendor)"
36125
+ />
36126
+ }
36127
+ </ds-mobile-section>
36128
+ }
36129
+ </ds-mobile-page-main>
36130
+ `, isInline: true, styles: [".empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:40px 20px;text-align:center}.empty-state-title{font-family:Brockmann,sans-serif;font-size:var(--font-size-base);font-weight:600;color:var(--color-text-primary);margin-top:-16px;z-index:4}.empty-state-description{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);color:var(--color-text-secondary);margin:0}\n"], dependencies: [{ kind: "component", type: DsMobilePageMainComponent, selector: "ds-mobile-page-main", inputs: ["title", "headerTitle", "headerSubtitle", "firstEntry", "avatarType", "avatarInitials", "avatarSrc", "avatarIconName", "showRefresh", "showCondensedHeader", "scrollThreshold", "headerFadeDistance", "contentPadding", "profileMenuItems"], outputs: ["avatarClick", "profileActionSelected", "refresh", "scroll"] }, { kind: "component", type: DsMobileSectionComponent, selector: "ds-mobile-section", inputs: ["headline", "icon", "linkText", "padding", "paddingDesktop", "gap", "contentGap", "showBorder", "overflow"], outputs: ["linkClick"] }, { kind: "component", type: DsMobileIllustrationComponent, selector: "ds-mobile-illustration", inputs: ["variant", "size", "alt"] }, { kind: "component", type: DsMobileInteractiveListItemServiceComponent, selector: "ds-mobile-interactive-list-item-service", inputs: ["title", "description", "logo", "showChevron"], outputs: ["serviceClick"] }, { kind: "component", type: DsMobileOfflineBannerComponent, selector: "ds-mobile-offline-banner", inputs: ["icon", "title", "message"] }] });
36131
+ }
36132
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: ServicesPageComponent, decorators: [{
36133
+ type: Component,
36134
+ args: [{ selector: 'app-services-page', standalone: true, imports: [
36135
+ DsMobilePageMainComponent,
36136
+ DsMobileSectionComponent,
36137
+ DsMobileIllustrationComponent,
36138
+ DsMobileInteractiveListItemServiceComponent,
36139
+ DsMobileOfflineBannerComponent,
36140
+ ], template: `
36141
+ <ds-mobile-page-main
36142
+ #pageComponent
36143
+ [title]="lbl.pageTitle"
36144
+ [avatarInitials]="userService.avatarInitials()"
36145
+ [avatarType]="userService.avatarType()"
36146
+ (refresh)="handleRefresh($event)"
36147
+ >
36148
+ @if (pageComponent.isOffline()) {
36149
+ <ds-mobile-offline-banner
36150
+ offline-indicator
36151
+ title="Ingen internetforbindelse"
36152
+ message="Nogle funktioner kan være utilgængelige"
36153
+ />
36154
+ }
36155
+
36156
+ @if (vendors().length === 0) {
36157
+ <ds-mobile-section>
36158
+ <div class="empty-state">
36159
+ <ds-mobile-illustration variant="inquiry" [alt]="lbl.emptyState" />
36160
+ <h3 class="empty-state-title">{{ lbl.emptyState }}</h3>
36161
+ <p class="empty-state-description">{{ lbl.emptyStateDescription }}</p>
36162
+ </div>
36163
+ </ds-mobile-section>
36164
+ } @else {
36165
+ <ds-mobile-section contentGap="0px">
36166
+ @for (vendor of vendors(); track vendor.id) {
36167
+ <ds-mobile-interactive-list-item-service
36168
+ [title]="vendor.name"
36169
+ [description]="stripHtml(vendor.fullDescription || vendor.description || '')"
36170
+ [logo]="vendor.logo || ''"
36171
+ (serviceClick)="openVendorSheet(vendor)"
36172
+ />
36173
+ }
36174
+ </ds-mobile-section>
36175
+ }
36176
+ </ds-mobile-page-main>
36177
+ `, styles: [".empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:40px 20px;text-align:center}.empty-state-title{font-family:Brockmann,sans-serif;font-size:var(--font-size-base);font-weight:600;color:var(--color-text-primary);margin-top:-16px;z-index:4}.empty-state-description{font-family:Brockmann,sans-serif;font-size:var(--font-size-sm);color:var(--color-text-secondary);margin:0}\n"] }]
36178
+ }], propDecorators: { pageComponent: [{
36179
+ type: ViewChild,
36180
+ args: ['pageComponent']
36181
+ }] } });
36182
+
35108
36183
  /**
35109
36184
  * Services Barrel File
35110
36185
  *
@@ -35128,5 +36203,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
35128
36203
  * Generated bundle index. Do not edit.
35129
36204
  */
35130
36205
 
35131
- export { AcceptInvitePageComponent, ActionCommentComponent, ActionLikeComponent, AvatarUploadPageComponent, BaseModalService, ContentRowComponent, CreateAccountPageComponent, DsAppIconComponent, DsAvatarWithBadgeComponent, DsLogoComponent, DsMobileAccessSheetComponent, DsMobileActionListItemComponent, DsMobileActionsBottomSheetComponent, DsMobileAddGroupTenantsModalComponent, DsMobileAppLoadingComponent, DsMobileAttachmentPreviewComponent, DsMobileBookingConfirmationWrapperComponent, DsMobileBookingModalComponent, DsMobileBookingModalService, DsMobileBookingSummaryComponent, DsMobileBottomSheetHeaderComponent, DsMobileBottomSheetService, DsMobileBottomSheetWrapperComponent, DsMobileCapacitySheetComponent, DsMobileCardInlineBannerComponent, DsMobileCardInlineComponent, DsMobileCardInlineContactComponent, DsMobileCardInlineFileComponent, DsMobileChatModalComponent, DsMobileChatModalService, DsMobileActionsBottomSheetComponent as DsMobileCommentActionsBottomSheetComponent, DsMobileCommentComponent, DsMobileConfirmationSheetComponent, DsMobileContactListItemComponent, DsMobileContentComponent, DsMobileCreateGroupModalComponent, DsMobileDropdownComponent, DsMobileEditGroupModalComponent, DsMobileEmptyStateComponent, DsMobileFabComponent, DsMobileFacilityArchiveConfirmationComponent, DsMobileFacilityCreationConfirmationWrapperComponent, DsMobileFacilityCreationModalComponent, DsMobileFacilityCreationModalService, DsMobileFacilityDeleteConfirmationComponent, DsMobileFacilityDetailModalComponent, DsMobileFacilityDetailModalService, DsMobileFileAttachmentComponent, DsMobileGroupAvatarStackComponent, DsMobileGroupMembersModalComponent, DsMobileHandbookDetailModalComponent, DsMobileHandbookDetailModalService, DsMobileHandbookFolderComponent, DsMobileHandbookFolderMiniComponent, DsMobileHeaderContentComponent, DsMobileHeaderContentTileComponent, DsMobileIllustrationComponent, DsMobileImagePlaceholderComponent, DsMobileInlinePhotoComponent, DsMobileInlineTabsComponent, DsMobileInteractiveListItemBookingComponent, DsMobileInteractiveListItemInquiryComponent, DsMobileInteractiveListItemMessageComponent, DsMobileInteractiveListItemPostComponent, DsMobileLightboxImageComponent as DsMobileLightboxComponent, DsMobileLightboxFooterComponent, DsMobileLightboxHeaderComponent, DsMobileLightboxImageComponent, DsMobileLightboxPdfComponent, DsMobileLightboxService, DsMobileListItemComponent, DsMobileListItemStaticComponent, DsMobileListSearchComponent, DsMobileLoaderOverlayComponent, DsMobileLongPressDirective, DsMobileMediaActionsPanelComponent, DsMobileMessageBubbleComponent, DsMobileMessageComposerComponent, DsMobileModalBaseComponent, DsMobileModalService, DsMobileNewInquiryModalComponent, DsMobileNewInquiryModalService, DsMobileOfflineBannerComponent, DsMobilePageDetailsComponent, DsMobilePageMainComponent, DsMobilePillComponent, DsMobileActionsBottomSheetComponent as DsMobilePostActionsBottomSheetComponent, DsMobilePostComposerComponent, DsMobilePostCreateBottomSheetComponent, DsMobilePostDetailModalComponent, DsMobilePostDetailModalService, DsMobilePriceSheetComponent, DsMobileProfileActionsSheetComponent, DsMobilePromptBottomSheetComponent, DsMobilePropertyBannerComponent, DsMobileRichTextEditorComponent, DsMobileSectionComponent, DsMobileSwiperComponent, DsMobileSwiperWithNavComponent, DsMobileSystemMessageBannerComponent, DsMobileTabBarComponent, DsMobileTabsComponent, DsMobileTenantPickerModalComponent, DsMobileWhenCanBookSheetComponent, DsMobileWhoCanBookSheetComponent, DsTextInputComponent, FamilyAccessPageComponent, FamilyAccessService, InviteSuccessPageComponent, MediaPickerService, MobileBookingPageComponent, MobileCommunityPageComponent, MobileHandbookPageComponent, MobileHomePageComponent, MobileInquiriesPageComponent, MobileInquiryDetailPageComponent, MobileModalBase, MobilePageBase, MobilePostDetailPageComponent, MobileTabsExampleComponent, PageLoadingService, PostActionsComponent, PostAttachmentsComponent, PostContentComponent, PostCreatePageComponent, PostMediaComponent, PostPdfAttachmentComponent, PostTextComponent, PostsService, SectionHeaderComponent, SignInPageComponent, SignInToAcceptPageComponent, TenantChatPageComponent, TileContentComponent, TileIconComponent, TileLabelComponent, TileValueComponent, TrackingPermissionService, UserService, WhitelabelDemoModalComponent, WhitelabelDemoModalService, WhitelabelService, customBackTransition, customPageTransition };
36206
+ export { AcceptInvitePageComponent, ActionCommentComponent, ActionLikeComponent, AvatarUploadPageComponent, BaseModalService, ContentRowComponent, CreateAccountPageComponent, DEFAULT_SERVICE_PAGE_LABELS, DsAppIconComponent, DsAvatarWithBadgeComponent, DsLogoComponent, DsMobileAccessSheetComponent, DsMobileActionListItemComponent, DsMobileActionsBottomSheetComponent, DsMobileAddGroupTenantsModalComponent, DsMobileAppLoadingComponent, DsMobileAttachmentPreviewComponent, DsMobileBookingConfirmationWrapperComponent, DsMobileBookingModalComponent, DsMobileBookingModalService, DsMobileBookingSummaryComponent, DsMobileBottomSheetHeaderComponent, DsMobileBottomSheetService, DsMobileBottomSheetWrapperComponent, DsMobileCapacitySheetComponent, DsMobileCardInlineBannerComponent, DsMobileCardInlineComponent, DsMobileCardInlineContactComponent, DsMobileCardInlineFileComponent, DsMobileChatModalComponent, DsMobileChatModalService, DsMobileActionsBottomSheetComponent as DsMobileCommentActionsBottomSheetComponent, DsMobileCommentComponent, DsMobileCommunityAdminPickerComponent, DsMobileCommunityAdminsModalComponent, DsMobileConfirmationSheetComponent, DsMobileContactListItemComponent, DsMobileContentComponent, DsMobileCreateGroupModalComponent, DsMobileDropdownComponent, DsMobileEditGroupModalComponent, DsMobileEmptyStateComponent, DsMobileFabComponent, DsMobileFacilityArchiveConfirmationComponent, DsMobileFacilityCreationConfirmationWrapperComponent, DsMobileFacilityCreationModalComponent, DsMobileFacilityCreationModalService, DsMobileFacilityDeleteConfirmationComponent, DsMobileFacilityDetailModalComponent, DsMobileFacilityDetailModalService, DsMobileFileAttachmentComponent, DsMobileGroupAvatarStackComponent, DsMobileGroupMembersModalComponent, DsMobileHandbookDetailModalComponent, DsMobileHandbookDetailModalService, DsMobileHandbookFolderComponent, DsMobileHandbookFolderMiniComponent, DsMobileHeaderContentComponent, DsMobileHeaderContentTileComponent, DsMobileIllustrationComponent, DsMobileImagePlaceholderComponent, DsMobileInlinePhotoComponent, DsMobileInlineTabsComponent, DsMobileInteractiveListItemBookingComponent, DsMobileInteractiveListItemInquiryComponent, DsMobileInteractiveListItemMessageComponent, DsMobileInteractiveListItemPostComponent, DsMobileLightboxImageComponent as DsMobileLightboxComponent, DsMobileLightboxFooterComponent, DsMobileLightboxHeaderComponent, DsMobileLightboxImageComponent, DsMobileLightboxPdfComponent, DsMobileLightboxService, DsMobileListItemComponent, DsMobileListItemStaticComponent, DsMobileListSearchComponent, DsMobileLoaderOverlayComponent, DsMobileLongPressDirective, DsMobileMediaActionsPanelComponent, DsMobileMessageBubbleComponent, DsMobileMessageComposerComponent, DsMobileModalBaseComponent, DsMobileModalService, DsMobileNewInquiryModalComponent, DsMobileNewInquiryModalService, DsMobileOfflineBannerComponent, DsMobilePageDetailsComponent, DsMobilePageMainComponent, DsMobilePillComponent, DsMobileActionsBottomSheetComponent as DsMobilePostActionsBottomSheetComponent, DsMobilePostComposerComponent, DsMobilePostCreateBottomSheetComponent, DsMobilePostDetailModalComponent, DsMobilePostDetailModalService, DsMobilePriceSheetComponent, DsMobileProfileActionsSheetComponent, DsMobilePromptBottomSheetComponent, DsMobilePropertyBannerComponent, DsMobileRichTextEditorComponent, DsMobileSectionComponent, DsMobileServiceVendorModalService, DsMobileServiceVendorSheetComponent, DsMobileSwiperComponent, DsMobileSwiperWithNavComponent, DsMobileSystemMessageBannerComponent, DsMobileTabBarComponent, DsMobileTabsComponent, DsMobileTenantPickerModalComponent, DsMobileWhenCanBookSheetComponent, DsMobileWhoCanBookSheetComponent, DsTextInputComponent, FamilyAccessPageComponent, FamilyAccessService, InquiriesService, InviteSuccessPageComponent, MediaPickerService, MobileBookingPageComponent, MobileCommunityPageComponent, MobileHandbookPageComponent, MobileHomePageComponent, MobileInquiriesPageComponent, MobileInquiryDetailPageComponent, MobileModalBase, MobilePageBase, MobilePostDetailPageComponent, MobileTabsExampleComponent, PageLoadingService, PostActionsComponent, PostAttachmentsComponent, PostContentComponent, PostCreatePageComponent, PostMediaComponent, PostPdfAttachmentComponent, PostTextComponent, PostsService, SectionHeaderComponent, ServicesPageComponent, SignInPageComponent, SignInToAcceptPageComponent, TenantChatPageComponent, TileContentComponent, TileIconComponent, TileLabelComponent, TileValueComponent, TrackingPermissionService, UserService, WhitelabelDemoModalComponent, WhitelabelDemoModalService, WhitelabelService, customBackTransition, customPageTransition };
35132
36207
  //# sourceMappingURL=propbinder-mobile-design.mjs.map