@propbinder/mobile-design 0.2.4 → 0.2.5
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.
- package/fesm2022/propbinder-mobile-design.mjs +5510 -3000
- package/fesm2022/propbinder-mobile-design.mjs.map +1 -1
- package/index.d.ts +1084 -280
- package/package.json +1 -1
- package/styles/ionic.css +84 -73
- package/styles/mobile-common.css +41 -0
- package/styles/mobile-page-base.css +9 -7
package/index.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import * as _angular_core from '@angular/core';
|
|
2
|
-
import { AfterViewInit, OnInit, ElementRef, OnDestroy, EventEmitter, ApplicationRef, EnvironmentInjector, Type } from '@angular/core';
|
|
3
|
-
import { ModalController, IonContent, NavController, GestureController } from '@ionic/angular/standalone';
|
|
2
|
+
import { AfterViewInit, OnInit, ElementRef, OnDestroy, EventEmitter, ApplicationRef, EnvironmentInjector, Type, AfterContentInit, ChangeDetectorRef } from '@angular/core';
|
|
3
|
+
import { ModalController, IonContent, NavController, GestureController, ModalOptions as ModalOptions$1 } from '@ionic/angular/standalone';
|
|
4
4
|
import { ImpactStyle } from '@capacitor/haptics';
|
|
5
|
+
import { DsTextareaComponent } from '@propbinder/design-system';
|
|
5
6
|
import { ControlValueAccessor } from '@angular/forms';
|
|
6
7
|
import { Router, ActivatedRoute } from '@angular/router';
|
|
7
8
|
import { Animation } from '@ionic/angular';
|
|
@@ -403,13 +404,58 @@ declare class DsMobilePageMainComponent extends MobilePageBase implements AfterV
|
|
|
403
404
|
static ɵcmp: _angular_core.ɵɵComponentDeclaration<DsMobilePageMainComponent, "ds-mobile-page-main", never, { "title": { "alias": "title"; "required": true; "isSignal": true; }; "headerTitle": { "alias": "headerTitle"; "required": false; "isSignal": true; }; "headerSubtitle": { "alias": "headerSubtitle"; "required": false; "isSignal": true; }; "avatarType": { "alias": "avatarType"; "required": false; "isSignal": true; }; "avatarInitials": { "alias": "avatarInitials"; "required": false; "isSignal": true; }; "avatarSrc": { "alias": "avatarSrc"; "required": false; "isSignal": true; }; "avatarIconName": { "alias": "avatarIconName"; "required": false; "isSignal": true; }; "showRefresh": { "alias": "showRefresh"; "required": false; "isSignal": true; }; "showCondensedHeader": { "alias": "showCondensedHeader"; "required": false; "isSignal": true; }; "scrollThreshold": { "alias": "scrollThreshold"; "required": false; "isSignal": true; }; "headerFadeDistance": { "alias": "headerFadeDistance"; "required": false; "isSignal": true; }; "profileMenuItems": { "alias": "profileMenuItems"; "required": false; "isSignal": true; }; }, { "avatarClick": "avatarClick"; "profileActionSelected": "profileActionSelected"; "refresh": "refresh"; "scroll": "scroll"; }, never, ["[header-content]", "*"], true, never>;
|
|
404
405
|
}
|
|
405
406
|
|
|
407
|
+
interface InlineTabItem {
|
|
408
|
+
id: string;
|
|
409
|
+
label: string;
|
|
410
|
+
badge?: number;
|
|
411
|
+
}
|
|
412
|
+
/**
|
|
413
|
+
* DsMobileInlineTabsComponent
|
|
414
|
+
*
|
|
415
|
+
* Pill-style inline tabs for filtering/switching views
|
|
416
|
+
* Used in the purple header section of pages
|
|
417
|
+
*
|
|
418
|
+
* @example
|
|
419
|
+
* ```html
|
|
420
|
+
* <ds-mobile-inline-tabs
|
|
421
|
+
* [tabs]="[
|
|
422
|
+
* { id: 'all', label: 'All' },
|
|
423
|
+
* { id: 'open', label: 'Open' },
|
|
424
|
+
* { id: 'closed', label: 'Closed' }
|
|
425
|
+
* ]"
|
|
426
|
+
* [activeTab]="'all'"
|
|
427
|
+
* (tabChange)="handleTabChange($event)">
|
|
428
|
+
* </ds-mobile-inline-tabs>
|
|
429
|
+
* ```
|
|
430
|
+
*/
|
|
431
|
+
declare class DsMobileInlineTabsComponent {
|
|
432
|
+
/**
|
|
433
|
+
* Array of tab items to display
|
|
434
|
+
*/
|
|
435
|
+
tabs: _angular_core.InputSignal<InlineTabItem[]>;
|
|
436
|
+
/**
|
|
437
|
+
* Currently active tab ID
|
|
438
|
+
*/
|
|
439
|
+
activeTab: _angular_core.InputSignal<string>;
|
|
440
|
+
/**
|
|
441
|
+
* Emitted when a tab is clicked
|
|
442
|
+
*/
|
|
443
|
+
tabChange: _angular_core.OutputEmitterRef<string>;
|
|
444
|
+
handleTabClick(tabId: string): void;
|
|
445
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<DsMobileInlineTabsComponent, never>;
|
|
446
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<DsMobileInlineTabsComponent, "ds-mobile-inline-tabs", never, { "tabs": { "alias": "tabs"; "required": true; "isSignal": true; }; "activeTab": { "alias": "activeTab"; "required": true; "isSignal": true; }; }, { "tabChange": "tabChange"; }, never, never, true, never>;
|
|
447
|
+
}
|
|
448
|
+
|
|
406
449
|
/**
|
|
407
450
|
* DsMobilePageDetailsComponent
|
|
408
451
|
*
|
|
409
|
-
* A mobile page layout for detail/drill-down pages with:
|
|
410
|
-
* -
|
|
411
|
-
* -
|
|
412
|
-
* -
|
|
452
|
+
* A complete mobile page layout for detail/drill-down pages with:
|
|
453
|
+
* - Fixed header with back button + title (fades in on scroll)
|
|
454
|
+
* - Purple expandable header section (scrolls with content)
|
|
455
|
+
* - Optional inline tabs in expandable header
|
|
456
|
+
* - White rounded content wrapper
|
|
457
|
+
* - Pull-to-refresh support (native platforms only)
|
|
458
|
+
* - Auto scroll title fade-in and header fade-out
|
|
413
459
|
*
|
|
414
460
|
* @example
|
|
415
461
|
* ```html
|
|
@@ -422,47 +468,63 @@ declare class DsMobilePageMainComponent extends MobilePageBase implements AfterV
|
|
|
422
468
|
* </div>
|
|
423
469
|
* </ds-mobile-page-details>
|
|
424
470
|
*
|
|
425
|
-
* <!-- With
|
|
471
|
+
* <!-- With tabs -->
|
|
426
472
|
* <ds-mobile-page-details
|
|
427
|
-
* title="
|
|
428
|
-
*
|
|
473
|
+
* title="Inquiry Details"
|
|
474
|
+
* [tabs]="tabItems"
|
|
475
|
+
* [activeTab]="activeTab()"
|
|
476
|
+
* (tabChange)="setActiveTab($event)"
|
|
477
|
+
* (back)="goBack()">
|
|
429
478
|
* <div class="page-content">
|
|
430
479
|
* <!-- Your content -->
|
|
431
480
|
* </div>
|
|
432
481
|
* </ds-mobile-page-details>
|
|
433
482
|
* ```
|
|
434
483
|
*/
|
|
435
|
-
declare class DsMobilePageDetailsComponent extends MobilePageBase {
|
|
484
|
+
declare class DsMobilePageDetailsComponent extends MobilePageBase implements AfterViewInit {
|
|
436
485
|
private navCtrl;
|
|
437
486
|
private elementRef;
|
|
487
|
+
ionContent?: IonContent;
|
|
488
|
+
private platform;
|
|
489
|
+
isNativePlatform: _angular_core.Signal<boolean>;
|
|
438
490
|
title: _angular_core.InputSignal<string>;
|
|
439
491
|
backRoute: _angular_core.InputSignal<string>;
|
|
492
|
+
tabs: _angular_core.InputSignal<InlineTabItem[] | undefined>;
|
|
493
|
+
activeTab: _angular_core.InputSignal<string>;
|
|
494
|
+
showRefresh: _angular_core.InputSignal<boolean>;
|
|
495
|
+
scrollThreshold: _angular_core.InputSignal<number>;
|
|
496
|
+
headerFadeDistance: _angular_core.InputSignal<number>;
|
|
440
497
|
back: _angular_core.OutputEmitterRef<void>;
|
|
498
|
+
tabChange: _angular_core.OutputEmitterRef<string>;
|
|
499
|
+
refresh: _angular_core.OutputEmitterRef<any>;
|
|
500
|
+
scroll: _angular_core.OutputEmitterRef<any>;
|
|
441
501
|
constructor(navCtrl: NavController, elementRef: ElementRef);
|
|
502
|
+
ngAfterViewInit(): void;
|
|
442
503
|
/**
|
|
443
504
|
* Handle back navigation
|
|
444
505
|
*
|
|
445
506
|
* By default, navigates using the provided backRoute or browser back.
|
|
446
507
|
* Parent components can listen to the (back) event to override this behavior.
|
|
447
|
-
*
|
|
448
|
-
* @example
|
|
449
|
-
* ```html
|
|
450
|
-
* <!-- Default behavior: uses backRoute or browser back -->
|
|
451
|
-
* <ds-mobile-page-details
|
|
452
|
-
* title="Details"
|
|
453
|
-
* backRoute="/home">
|
|
454
|
-
* </ds-mobile-page-details>
|
|
455
|
-
*
|
|
456
|
-
* <!-- Custom behavior: parent handles navigation -->
|
|
457
|
-
* <ds-mobile-page-details
|
|
458
|
-
* title="Details"
|
|
459
|
-
* (back)="customBackHandler()">
|
|
460
|
-
* </ds-mobile-page-details>
|
|
461
|
-
* ```
|
|
462
508
|
*/
|
|
463
509
|
handleBack(): void;
|
|
510
|
+
/**
|
|
511
|
+
* Handle tab change
|
|
512
|
+
*/
|
|
513
|
+
handleTabChange(tabId: string): void;
|
|
514
|
+
/**
|
|
515
|
+
* Handle scroll events
|
|
516
|
+
* - Shows title in fixed header when scrolled past threshold
|
|
517
|
+
* - Fades out expandable header content based on scroll position
|
|
518
|
+
* - Emits scroll event for custom handling
|
|
519
|
+
*/
|
|
520
|
+
handleScroll(event: any): void;
|
|
521
|
+
/**
|
|
522
|
+
* Handle pull-to-refresh
|
|
523
|
+
* Emits refresh event - parent should call event.target.complete()
|
|
524
|
+
*/
|
|
525
|
+
handleRefresh(event: any): Promise<void>;
|
|
464
526
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<DsMobilePageDetailsComponent, never>;
|
|
465
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<DsMobilePageDetailsComponent, "ds-mobile-page-details", never, { "title": { "alias": "title"; "required": true; "isSignal": true; }; "backRoute": { "alias": "backRoute"; "required": false; "isSignal": true; }; }, { "back": "back"; }, never, ["*"], true, never>;
|
|
527
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<DsMobilePageDetailsComponent, "ds-mobile-page-details", never, { "title": { "alias": "title"; "required": true; "isSignal": true; }; "backRoute": { "alias": "backRoute"; "required": false; "isSignal": true; }; "tabs": { "alias": "tabs"; "required": false; "isSignal": true; }; "activeTab": { "alias": "activeTab"; "required": false; "isSignal": true; }; "showRefresh": { "alias": "showRefresh"; "required": false; "isSignal": true; }; "scrollThreshold": { "alias": "scrollThreshold"; "required": false; "isSignal": true; }; "headerFadeDistance": { "alias": "headerFadeDistance"; "required": false; "isSignal": true; }; }, { "back": "back"; "tabChange": "tabChange"; "refresh": "refresh"; "scroll": "scroll"; }, never, ["*"], true, never>;
|
|
466
528
|
}
|
|
467
529
|
|
|
468
530
|
/**
|
|
@@ -814,6 +876,72 @@ declare class DsMobilePostComposerComponent {
|
|
|
814
876
|
static ɵcmp: _angular_core.ɵɵComponentDeclaration<DsMobilePostComposerComponent, "ds-mobile-post-composer", never, { "avatarInitials": { "alias": "avatarInitials"; "required": false; "isSignal": true; }; "avatarType": { "alias": "avatarType"; "required": false; "isSignal": true; }; "avatarSrc": { "alias": "avatarSrc"; "required": false; "isSignal": true; }; "avatarIconName": { "alias": "avatarIconName"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "buttonText": { "alias": "buttonText"; "required": false; "isSignal": true; }; }, { "composerClick": "composerClick"; }, never, never, true, never>;
|
|
815
877
|
}
|
|
816
878
|
|
|
879
|
+
/**
|
|
880
|
+
* File type for attachment preview
|
|
881
|
+
*/
|
|
882
|
+
type AttachmentFileType = 'image' | 'pdf' | 'doc' | 'docx' | 'xls' | 'xlsx' | 'other';
|
|
883
|
+
/**
|
|
884
|
+
* Attachment data interface
|
|
885
|
+
*/
|
|
886
|
+
interface AttachmentData {
|
|
887
|
+
id: string;
|
|
888
|
+
src: string;
|
|
889
|
+
type: AttachmentFileType;
|
|
890
|
+
name?: string;
|
|
891
|
+
size?: string;
|
|
892
|
+
}
|
|
893
|
+
/**
|
|
894
|
+
* DsMobileAttachmentPreviewComponent
|
|
895
|
+
*
|
|
896
|
+
* Reusable component for displaying attachment previews.
|
|
897
|
+
* Supports both image previews and file type indicators (PDF, DOCX, etc.).
|
|
898
|
+
*
|
|
899
|
+
* Features:
|
|
900
|
+
* - Image preview for photos
|
|
901
|
+
* - File type indicator box for documents
|
|
902
|
+
* - Remove button overlay
|
|
903
|
+
* - Consistent 96x96 size
|
|
904
|
+
*
|
|
905
|
+
* @example
|
|
906
|
+
* ```html
|
|
907
|
+
* <!-- Image attachment -->
|
|
908
|
+
* <ds-mobile-attachment-preview
|
|
909
|
+
* [attachment]="{ id: '1', src: 'photo.jpg', type: 'image' }"
|
|
910
|
+
* (remove)="handleRemove($event)">
|
|
911
|
+
* </ds-mobile-attachment-preview>
|
|
912
|
+
*
|
|
913
|
+
* <!-- PDF attachment -->
|
|
914
|
+
* <ds-mobile-attachment-preview
|
|
915
|
+
* [attachment]="{ id: '2', src: 'doc.pdf', type: 'pdf', name: 'Document.pdf' }"
|
|
916
|
+
* (remove)="handleRemove($event)">
|
|
917
|
+
* </ds-mobile-attachment-preview>
|
|
918
|
+
* ```
|
|
919
|
+
*/
|
|
920
|
+
declare class DsMobileAttachmentPreviewComponent {
|
|
921
|
+
/**
|
|
922
|
+
* Attachment data to display
|
|
923
|
+
*/
|
|
924
|
+
attachment: _angular_core.InputSignal<AttachmentData>;
|
|
925
|
+
/**
|
|
926
|
+
* Emits when the remove button is clicked
|
|
927
|
+
*/
|
|
928
|
+
remove: _angular_core.OutputEmitterRef<string>;
|
|
929
|
+
/**
|
|
930
|
+
* Get the file type label (PDF, DOCX, etc.)
|
|
931
|
+
*/
|
|
932
|
+
getFileTypeLabel(): string;
|
|
933
|
+
/**
|
|
934
|
+
* Get the appropriate icon name based on file type
|
|
935
|
+
*/
|
|
936
|
+
getIconName(): string;
|
|
937
|
+
/**
|
|
938
|
+
* Handle remove button click
|
|
939
|
+
*/
|
|
940
|
+
handleRemove(): void;
|
|
941
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<DsMobileAttachmentPreviewComponent, never>;
|
|
942
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<DsMobileAttachmentPreviewComponent, "ds-mobile-attachment-preview", never, { "attachment": { "alias": "attachment"; "required": true; "isSignal": true; }; }, { "remove": "remove"; }, never, never, true, never>;
|
|
943
|
+
}
|
|
944
|
+
|
|
817
945
|
/**
|
|
818
946
|
* DsMobileMessageComposerComponent
|
|
819
947
|
*
|
|
@@ -859,6 +987,14 @@ declare class DsMobileMessageComposerComponent implements AfterViewInit, OnDestr
|
|
|
859
987
|
* Send button aria label
|
|
860
988
|
*/
|
|
861
989
|
sendButtonLabel: _angular_core.InputSignal<string>;
|
|
990
|
+
/**
|
|
991
|
+
* Attachment button aria label
|
|
992
|
+
*/
|
|
993
|
+
attachmentButtonLabel: _angular_core.InputSignal<string>;
|
|
994
|
+
/**
|
|
995
|
+
* Whether to show the attachment button
|
|
996
|
+
*/
|
|
997
|
+
showAttachmentButton: _angular_core.InputSignal<boolean>;
|
|
862
998
|
/**
|
|
863
999
|
* Edit indicator text (when editing)
|
|
864
1000
|
*/
|
|
@@ -887,10 +1023,18 @@ declare class DsMobileMessageComposerComponent implements AfterViewInit, OnDestr
|
|
|
887
1023
|
* ViewChild for message input
|
|
888
1024
|
*/
|
|
889
1025
|
messageInput?: ElementRef<HTMLTextAreaElement>;
|
|
1026
|
+
/**
|
|
1027
|
+
* ViewChild for file input
|
|
1028
|
+
*/
|
|
1029
|
+
fileInput?: ElementRef<HTMLInputElement>;
|
|
890
1030
|
/**
|
|
891
1031
|
* Message text signal
|
|
892
1032
|
*/
|
|
893
1033
|
messageText: _angular_core.WritableSignal<string>;
|
|
1034
|
+
/**
|
|
1035
|
+
* Attachments signal
|
|
1036
|
+
*/
|
|
1037
|
+
attachments: _angular_core.WritableSignal<AttachmentData[]>;
|
|
894
1038
|
/**
|
|
895
1039
|
* Editing message state (optional)
|
|
896
1040
|
*/
|
|
@@ -930,6 +1074,7 @@ declare class DsMobileMessageComposerComponent implements AfterViewInit, OnDestr
|
|
|
930
1074
|
isReply?: boolean;
|
|
931
1075
|
replyTo?: string;
|
|
932
1076
|
isEdit?: boolean;
|
|
1077
|
+
attachments?: AttachmentData[];
|
|
933
1078
|
}>;
|
|
934
1079
|
/**
|
|
935
1080
|
* Emits when edit is cancelled
|
|
@@ -945,6 +1090,10 @@ declare class DsMobileMessageComposerComponent implements AfterViewInit, OnDestr
|
|
|
945
1090
|
mentionSelected: _angular_core.OutputEmitterRef<{
|
|
946
1091
|
userName: string;
|
|
947
1092
|
}>;
|
|
1093
|
+
/**
|
|
1094
|
+
* Emits when attachment button is clicked
|
|
1095
|
+
*/
|
|
1096
|
+
attachmentClicked: _angular_core.OutputEmitterRef<void>;
|
|
948
1097
|
ngAfterViewInit(): void;
|
|
949
1098
|
ngOnDestroy(): void;
|
|
950
1099
|
/**
|
|
@@ -959,6 +1108,10 @@ declare class DsMobileMessageComposerComponent implements AfterViewInit, OnDestr
|
|
|
959
1108
|
* Show the keyboard when user interacts with input
|
|
960
1109
|
*/
|
|
961
1110
|
showKeyboard(): void;
|
|
1111
|
+
/**
|
|
1112
|
+
* Handle keyboard shortcuts (Shift+Enter to send)
|
|
1113
|
+
*/
|
|
1114
|
+
handleKeyDown(event: KeyboardEvent): void;
|
|
962
1115
|
/**
|
|
963
1116
|
* Handle input changes and detect @ mentions
|
|
964
1117
|
*/
|
|
@@ -991,12 +1144,32 @@ declare class DsMobileMessageComposerComponent implements AfterViewInit, OnDestr
|
|
|
991
1144
|
* Focus the input
|
|
992
1145
|
*/
|
|
993
1146
|
focus(): void;
|
|
1147
|
+
/**
|
|
1148
|
+
* Handle attachment button click
|
|
1149
|
+
*/
|
|
1150
|
+
handleAttachmentClick(): void;
|
|
1151
|
+
/**
|
|
1152
|
+
* Detect file type from file name or mime type
|
|
1153
|
+
*/
|
|
1154
|
+
private detectFileType;
|
|
1155
|
+
/**
|
|
1156
|
+
* Format file size for display
|
|
1157
|
+
*/
|
|
1158
|
+
private formatFileSize;
|
|
1159
|
+
/**
|
|
1160
|
+
* Handle file selection from file input
|
|
1161
|
+
*/
|
|
1162
|
+
handleFileSelect(event: Event): void;
|
|
1163
|
+
/**
|
|
1164
|
+
* Remove an attachment from the list
|
|
1165
|
+
*/
|
|
1166
|
+
removeAttachment(attachmentId: string): void;
|
|
994
1167
|
/**
|
|
995
1168
|
* Send message
|
|
996
1169
|
*/
|
|
997
1170
|
sendMessage(): void;
|
|
998
1171
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<DsMobileMessageComposerComponent, never>;
|
|
999
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<DsMobileMessageComposerComponent, "ds-mobile-message-composer", never, { "avatarInitials": { "alias": "avatarInitials"; "required": false; "isSignal": true; }; "avatarType": { "alias": "avatarType"; "required": false; "isSignal": true; }; "avatarSrc": { "alias": "avatarSrc"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "sendButtonLabel": { "alias": "sendButtonLabel"; "required": false; "isSignal": true; }; "editIndicatorText": { "alias": "editIndicatorText"; "required": false; "isSignal": true; }; "replyIndicatorText": { "alias": "replyIndicatorText"; "required": false; "isSignal": true; }; "enableMentions": { "alias": "enableMentions"; "required": false; "isSignal": true; }; "mentionUsers": { "alias": "mentionUsers"; "required": false; "isSignal": true; }; "autoFocus": { "alias": "autoFocus"; "required": false; "isSignal": true; }; }, { "messageSent": "messageSent"; "editCancelled": "editCancelled"; "replyCancelled": "replyCancelled"; "mentionSelected": "mentionSelected"; }, never, never, true, never>;
|
|
1172
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<DsMobileMessageComposerComponent, "ds-mobile-message-composer", never, { "avatarInitials": { "alias": "avatarInitials"; "required": false; "isSignal": true; }; "avatarType": { "alias": "avatarType"; "required": false; "isSignal": true; }; "avatarSrc": { "alias": "avatarSrc"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "sendButtonLabel": { "alias": "sendButtonLabel"; "required": false; "isSignal": true; }; "attachmentButtonLabel": { "alias": "attachmentButtonLabel"; "required": false; "isSignal": true; }; "showAttachmentButton": { "alias": "showAttachmentButton"; "required": false; "isSignal": true; }; "editIndicatorText": { "alias": "editIndicatorText"; "required": false; "isSignal": true; }; "replyIndicatorText": { "alias": "replyIndicatorText"; "required": false; "isSignal": true; }; "enableMentions": { "alias": "enableMentions"; "required": false; "isSignal": true; }; "mentionUsers": { "alias": "mentionUsers"; "required": false; "isSignal": true; }; "autoFocus": { "alias": "autoFocus"; "required": false; "isSignal": true; }; }, { "messageSent": "messageSent"; "editCancelled": "editCancelled"; "replyCancelled": "replyCancelled"; "mentionSelected": "mentionSelected"; "attachmentClicked": "attachmentClicked"; }, never, never, true, never>;
|
|
1000
1173
|
}
|
|
1001
1174
|
|
|
1002
1175
|
/**
|
|
@@ -1064,6 +1237,10 @@ declare class DsMobileMessageBubbleComponent {
|
|
|
1064
1237
|
* Timestamp text (e.g., "12:34", "08-12-2025 13:18")
|
|
1065
1238
|
*/
|
|
1066
1239
|
timestamp: _angular_core.InputSignal<string>;
|
|
1240
|
+
/**
|
|
1241
|
+
* Whether to show the timestamp below the bubble
|
|
1242
|
+
*/
|
|
1243
|
+
showTimestamp: _angular_core.InputSignal<boolean>;
|
|
1067
1244
|
/**
|
|
1068
1245
|
* Avatar initials
|
|
1069
1246
|
*/
|
|
@@ -1095,6 +1272,10 @@ declare class DsMobileMessageBubbleComponent {
|
|
|
1095
1272
|
* Emits when the message is long-pressed
|
|
1096
1273
|
*/
|
|
1097
1274
|
longPress: _angular_core.OutputEmitterRef<void>;
|
|
1275
|
+
/**
|
|
1276
|
+
* Emits when the message is clicked (to toggle timestamp)
|
|
1277
|
+
*/
|
|
1278
|
+
messageClick: _angular_core.OutputEmitterRef<void>;
|
|
1098
1279
|
/**
|
|
1099
1280
|
* Long press tracking
|
|
1100
1281
|
*/
|
|
@@ -1104,16 +1285,21 @@ declare class DsMobileMessageBubbleComponent {
|
|
|
1104
1285
|
private touchStartY;
|
|
1105
1286
|
private readonly LONG_PRESS_DURATION;
|
|
1106
1287
|
private readonly MOVE_THRESHOLD;
|
|
1288
|
+
private clickStartTime;
|
|
1107
1289
|
/**
|
|
1108
1290
|
* Handle attachment click
|
|
1109
1291
|
*/
|
|
1110
1292
|
handleAttachmentClick(attachment: ChatAttachment): void;
|
|
1293
|
+
/**
|
|
1294
|
+
* Handle click (for web/mouse support)
|
|
1295
|
+
*/
|
|
1296
|
+
handleClick(event: MouseEvent): void;
|
|
1111
1297
|
/**
|
|
1112
1298
|
* Handle touch start for long press detection
|
|
1113
1299
|
*/
|
|
1114
1300
|
handleTouchStart(event: TouchEvent): void;
|
|
1115
1301
|
/**
|
|
1116
|
-
* Handle touch end to clear long press timer
|
|
1302
|
+
* Handle touch end to clear long press timer and detect short tap
|
|
1117
1303
|
*/
|
|
1118
1304
|
handleTouchEnd(event: TouchEvent): void;
|
|
1119
1305
|
/**
|
|
@@ -1125,7 +1311,7 @@ declare class DsMobileMessageBubbleComponent {
|
|
|
1125
1311
|
*/
|
|
1126
1312
|
handleContextMenu(event: Event): void;
|
|
1127
1313
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<DsMobileMessageBubbleComponent, never>;
|
|
1128
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<DsMobileMessageBubbleComponent, "ds-mobile-message-bubble", never, { "content": { "alias": "content"; "required": true; "isSignal": true; }; "isOwnMessage": { "alias": "isOwnMessage"; "required": false; "isSignal": true; }; "senderName": { "alias": "senderName"; "required": false; "isSignal": true; }; "timestamp": { "alias": "timestamp"; "required": true; "isSignal": true; }; "avatarInitials": { "alias": "avatarInitials"; "required": false; "isSignal": true; }; "avatarType": { "alias": "avatarType"; "required": false; "isSignal": true; }; "avatarSrc": { "alias": "avatarSrc"; "required": false; "isSignal": true; }; "attachments": { "alias": "attachments"; "required": false; "isSignal": true; }; "clickable": { "alias": "clickable"; "required": false; "isSignal": true; }; }, { "attachmentClick": "attachmentClick"; "longPress": "longPress"; }, never, never, true, never>;
|
|
1314
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<DsMobileMessageBubbleComponent, "ds-mobile-message-bubble", never, { "content": { "alias": "content"; "required": true; "isSignal": true; }; "isOwnMessage": { "alias": "isOwnMessage"; "required": false; "isSignal": true; }; "senderName": { "alias": "senderName"; "required": false; "isSignal": true; }; "timestamp": { "alias": "timestamp"; "required": true; "isSignal": true; }; "showTimestamp": { "alias": "showTimestamp"; "required": false; "isSignal": true; }; "avatarInitials": { "alias": "avatarInitials"; "required": false; "isSignal": true; }; "avatarType": { "alias": "avatarType"; "required": false; "isSignal": true; }; "avatarSrc": { "alias": "avatarSrc"; "required": false; "isSignal": true; }; "attachments": { "alias": "attachments"; "required": false; "isSignal": true; }; "clickable": { "alias": "clickable"; "required": false; "isSignal": true; }; }, { "attachmentClick": "attachmentClick"; "longPress": "longPress"; "messageClick": "messageClick"; }, never, never, true, never>;
|
|
1129
1315
|
}
|
|
1130
1316
|
|
|
1131
1317
|
/**
|
|
@@ -2058,48 +2244,6 @@ declare class DsMobileTabsComponent implements OnInit {
|
|
|
2058
2244
|
static ɵcmp: _angular_core.ɵɵComponentDeclaration<DsMobileTabsComponent, "ds-mobile-tabs", never, { "tabs": { "alias": "tabs"; "required": false; }; "avatarType": { "alias": "avatarType"; "required": false; }; "avatarInitials": { "alias": "avatarInitials"; "required": false; }; "avatarSrc": { "alias": "avatarSrc"; "required": false; }; "avatarIconName": { "alias": "avatarIconName"; "required": false; }; }, { "avatarClick": "avatarClick"; }, never, never, true, never>;
|
|
2059
2245
|
}
|
|
2060
2246
|
|
|
2061
|
-
interface InlineTabItem {
|
|
2062
|
-
id: string;
|
|
2063
|
-
label: string;
|
|
2064
|
-
badge?: number;
|
|
2065
|
-
}
|
|
2066
|
-
/**
|
|
2067
|
-
* DsMobileInlineTabsComponent
|
|
2068
|
-
*
|
|
2069
|
-
* Pill-style inline tabs for filtering/switching views
|
|
2070
|
-
* Used in the purple header section of pages
|
|
2071
|
-
*
|
|
2072
|
-
* @example
|
|
2073
|
-
* ```html
|
|
2074
|
-
* <ds-mobile-inline-tabs
|
|
2075
|
-
* [tabs]="[
|
|
2076
|
-
* { id: 'all', label: 'All' },
|
|
2077
|
-
* { id: 'open', label: 'Open' },
|
|
2078
|
-
* { id: 'closed', label: 'Closed' }
|
|
2079
|
-
* ]"
|
|
2080
|
-
* [activeTab]="'all'"
|
|
2081
|
-
* (tabChange)="handleTabChange($event)">
|
|
2082
|
-
* </ds-mobile-inline-tabs>
|
|
2083
|
-
* ```
|
|
2084
|
-
*/
|
|
2085
|
-
declare class DsMobileInlineTabsComponent {
|
|
2086
|
-
/**
|
|
2087
|
-
* Array of tab items to display
|
|
2088
|
-
*/
|
|
2089
|
-
tabs: _angular_core.InputSignal<InlineTabItem[]>;
|
|
2090
|
-
/**
|
|
2091
|
-
* Currently active tab ID
|
|
2092
|
-
*/
|
|
2093
|
-
activeTab: _angular_core.InputSignal<string>;
|
|
2094
|
-
/**
|
|
2095
|
-
* Emitted when a tab is clicked
|
|
2096
|
-
*/
|
|
2097
|
-
tabChange: _angular_core.OutputEmitterRef<string>;
|
|
2098
|
-
handleTabClick(tabId: string): void;
|
|
2099
|
-
static ɵfac: _angular_core.ɵɵFactoryDeclaration<DsMobileInlineTabsComponent, never>;
|
|
2100
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<DsMobileInlineTabsComponent, "ds-mobile-inline-tabs", never, { "tabs": { "alias": "tabs"; "required": true; "isSignal": true; }; "activeTab": { "alias": "activeTab"; "required": true; "isSignal": true; }; }, { "tabChange": "tabChange"; }, never, never, true, never>;
|
|
2101
|
-
}
|
|
2102
|
-
|
|
2103
2247
|
/**
|
|
2104
2248
|
* Media file types supported by the lightbox
|
|
2105
2249
|
*/
|
|
@@ -2809,86 +2953,304 @@ declare class DsMobileModalService {
|
|
|
2809
2953
|
}
|
|
2810
2954
|
|
|
2811
2955
|
/**
|
|
2812
|
-
*
|
|
2813
|
-
*
|
|
2814
|
-
* Represents a post with its content, author info, and comments.
|
|
2815
|
-
* Use this interface to map your API response data to the component.
|
|
2956
|
+
* MobileModalBase
|
|
2816
2957
|
*
|
|
2817
|
-
*
|
|
2818
|
-
*
|
|
2819
|
-
* const postData: PostDetailData = {
|
|
2820
|
-
* postId: '123',
|
|
2821
|
-
* authorName: 'John Doe',
|
|
2822
|
-
* authorRole: 'Tenant',
|
|
2823
|
-
* timestamp: '2h ago',
|
|
2824
|
-
* avatarInitials: 'JD',
|
|
2825
|
-
* content: 'Post content here...',
|
|
2826
|
-
* likeCount: 42,
|
|
2827
|
-
* commentCount: 12,
|
|
2828
|
-
* comments: [...]
|
|
2829
|
-
* };
|
|
2830
|
-
* ```
|
|
2831
|
-
*/
|
|
2832
|
-
interface PostDetailData {
|
|
2833
|
-
/** Unique post identifier */
|
|
2834
|
-
postId: string;
|
|
2835
|
-
/** Post author name */
|
|
2836
|
-
authorName: string;
|
|
2837
|
-
/** Author role (e.g., 'Tenant', 'Manager') */
|
|
2838
|
-
authorRole: string;
|
|
2839
|
-
/** Post timestamp (e.g., '2h ago', 'Yesterday') */
|
|
2840
|
-
timestamp: string;
|
|
2841
|
-
/** Author avatar initials (1-2 letters) */
|
|
2842
|
-
avatarInitials?: string;
|
|
2843
|
-
/** Avatar display type */
|
|
2844
|
-
avatarType?: 'photo' | 'initials';
|
|
2845
|
-
/** Author avatar image URL */
|
|
2846
|
-
avatarSrc?: string;
|
|
2847
|
-
/** Post text content */
|
|
2848
|
-
content: string;
|
|
2849
|
-
/** Optional post image URL */
|
|
2850
|
-
imageSrc?: string;
|
|
2851
|
-
/** Image alt text */
|
|
2852
|
-
imageAlt?: string;
|
|
2853
|
-
/** Whether the current user has liked this post */
|
|
2854
|
-
isLiked?: boolean;
|
|
2855
|
-
/** Number of likes */
|
|
2856
|
-
likeCount?: number;
|
|
2857
|
-
/** Number of comments */
|
|
2858
|
-
commentCount?: number;
|
|
2859
|
-
/** Array of comments */
|
|
2860
|
-
comments?: CommentData[];
|
|
2861
|
-
/** Auto-focus comment input when modal opens */
|
|
2862
|
-
focusComment?: boolean;
|
|
2863
|
-
}
|
|
2864
|
-
/**
|
|
2865
|
-
* Comment data interface
|
|
2958
|
+
* Shared base class for mobile modal components.
|
|
2959
|
+
* Provides consistent modal behavior, state management, and keyboard handling.
|
|
2866
2960
|
*
|
|
2867
|
-
*
|
|
2961
|
+
* **Key Features:**
|
|
2962
|
+
* - Loading and error state management
|
|
2963
|
+
* - Header configuration (title, meta)
|
|
2964
|
+
* - Automatic keyboard height tracking (iOS/Android)
|
|
2965
|
+
* - Fixed bottom component support
|
|
2966
|
+
* - Consistent close behavior
|
|
2868
2967
|
*
|
|
2869
|
-
*
|
|
2968
|
+
* **Usage:**
|
|
2870
2969
|
* ```typescript
|
|
2871
|
-
*
|
|
2872
|
-
*
|
|
2873
|
-
*
|
|
2874
|
-
*
|
|
2875
|
-
*
|
|
2876
|
-
* content: 'Great post!',
|
|
2877
|
-
* isLiked: false,
|
|
2878
|
-
* likeCount: 5,
|
|
2879
|
-
* isOwnComment: false
|
|
2880
|
-
* };
|
|
2970
|
+
* export class MyModalComponent extends MobileModalBase {
|
|
2971
|
+
* constructor() {
|
|
2972
|
+
* super();
|
|
2973
|
+
* }
|
|
2974
|
+
* }
|
|
2881
2975
|
* ```
|
|
2976
|
+
*
|
|
2977
|
+
* @internal This is a base class and should not be used directly.
|
|
2882
2978
|
*/
|
|
2883
|
-
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
|
|
2979
|
+
declare abstract class MobileModalBase implements OnInit, OnDestroy {
|
|
2980
|
+
protected modalController: ModalController;
|
|
2981
|
+
/**
|
|
2982
|
+
* Reference to IonContent for accessing scroll element
|
|
2983
|
+
*/
|
|
2984
|
+
protected ionContent?: IonContent;
|
|
2985
|
+
/**
|
|
2986
|
+
* ResizeObserver for tracking fixed bottom height
|
|
2987
|
+
*/
|
|
2988
|
+
private fixedBottomObserver?;
|
|
2989
|
+
/**
|
|
2990
|
+
* Loading state - when true, shows loading indicator
|
|
2991
|
+
* @default false
|
|
2992
|
+
*/
|
|
2993
|
+
loading: _angular_core.InputSignal<boolean>;
|
|
2994
|
+
/**
|
|
2995
|
+
* Error state - when set, shows error message
|
|
2996
|
+
* @default undefined
|
|
2997
|
+
*/
|
|
2998
|
+
error: _angular_core.InputSignal<string | undefined>;
|
|
2999
|
+
/**
|
|
3000
|
+
* Modal header title
|
|
3001
|
+
* @default ''
|
|
3002
|
+
*/
|
|
3003
|
+
headerTitle: _angular_core.InputSignal<string>;
|
|
3004
|
+
/**
|
|
3005
|
+
* Modal header metadata (subtitle/secondary text)
|
|
3006
|
+
* @default ''
|
|
3007
|
+
*/
|
|
3008
|
+
headerMeta: _angular_core.InputSignal<string>;
|
|
3009
|
+
/**
|
|
3010
|
+
* Accessibility label for close button
|
|
3011
|
+
* @default 'Close'
|
|
3012
|
+
*/
|
|
3013
|
+
closeButtonLabel: _angular_core.InputSignal<string>;
|
|
3014
|
+
/**
|
|
3015
|
+
* Enable automatic keyboard height tracking
|
|
3016
|
+
* When enabled, sets --keyboard-height CSS variable for sliding content
|
|
3017
|
+
* @default false
|
|
3018
|
+
*/
|
|
3019
|
+
enableKeyboardHandling: _angular_core.InputSignal<boolean>;
|
|
3020
|
+
/**
|
|
3021
|
+
* Whether modal has a fixed bottom component
|
|
3022
|
+
* Used to manage spacing and keyboard interactions
|
|
3023
|
+
* @default false
|
|
3024
|
+
*/
|
|
3025
|
+
hasFixedBottom: _angular_core.InputSignal<boolean>;
|
|
3026
|
+
/**
|
|
3027
|
+
* Emitted when modal is closed
|
|
3028
|
+
*/
|
|
3029
|
+
closed: _angular_core.OutputEmitterRef<void>;
|
|
3030
|
+
ngOnInit(): void;
|
|
3031
|
+
ngOnDestroy(): void;
|
|
3032
|
+
/**
|
|
3033
|
+
* Close the modal
|
|
3034
|
+
* Emits closed event and dismisses the modal
|
|
3035
|
+
*/
|
|
3036
|
+
close(): void;
|
|
3037
|
+
/**
|
|
3038
|
+
* Set up keyboard event listeners to adjust component position
|
|
3039
|
+
* Uses --keyboard-height for fixed bottom composer and adds padding to scroll area
|
|
3040
|
+
* @protected
|
|
3041
|
+
*/
|
|
3042
|
+
protected setupKeyboardListeners(): void;
|
|
3043
|
+
/**
|
|
3044
|
+
* Set up ResizeObserver to track fixed bottom height and apply as CSS variable
|
|
3045
|
+
* This allows dynamic bottom padding that adjusts to content
|
|
3046
|
+
* @protected
|
|
3047
|
+
*/
|
|
3048
|
+
protected setupFixedBottomObserver(): Promise<void>;
|
|
3049
|
+
/**
|
|
3050
|
+
* Clean up keyboard event listeners
|
|
3051
|
+
* @protected
|
|
3052
|
+
*/
|
|
3053
|
+
protected cleanupKeyboardListeners(): void;
|
|
3054
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<MobileModalBase, never>;
|
|
3055
|
+
static ɵdir: _angular_core.ɵɵDirectiveDeclaration<MobileModalBase, never, never, { "loading": { "alias": "loading"; "required": false; "isSignal": true; }; "error": { "alias": "error"; "required": false; "isSignal": true; }; "headerTitle": { "alias": "headerTitle"; "required": false; "isSignal": true; }; "headerMeta": { "alias": "headerMeta"; "required": false; "isSignal": true; }; "closeButtonLabel": { "alias": "closeButtonLabel"; "required": false; "isSignal": true; }; "enableKeyboardHandling": { "alias": "enableKeyboardHandling"; "required": false; "isSignal": true; }; "hasFixedBottom": { "alias": "hasFixedBottom"; "required": false; "isSignal": true; }; }, { "closed": "closed"; }, never, never, true, never>;
|
|
3056
|
+
}
|
|
3057
|
+
|
|
3058
|
+
/**
|
|
3059
|
+
* DsMobileModalBaseComponent
|
|
3060
|
+
*
|
|
3061
|
+
* Base modal component providing consistent layout and behavior for all modals.
|
|
3062
|
+
*
|
|
3063
|
+
* **Features:**
|
|
3064
|
+
* - Optional header with auto-detection of content
|
|
3065
|
+
* - Flexible header with slots for leading content (avatar, icon)
|
|
3066
|
+
* - Title and metadata inputs or custom header slot
|
|
3067
|
+
* - Default loading and error state templates (with override capability)
|
|
3068
|
+
* - Fixed bottom component support (e.g., message composer)
|
|
3069
|
+
* - Automatic keyboard handling
|
|
3070
|
+
* - Safe area support
|
|
3071
|
+
*
|
|
3072
|
+
* **Slot Structure:**
|
|
3073
|
+
* - `[header-leading]` - Left side of header (avatar, icon)
|
|
3074
|
+
* - `[header-main]` - Custom header content (replaces title/meta)
|
|
3075
|
+
* - `[loading-state]` - Custom loading template
|
|
3076
|
+
* - `[error-state]` - Custom error template
|
|
3077
|
+
* - `[footer]` or `[fixed-bottom]` - Fixed bottom component (slides with keyboard)
|
|
3078
|
+
* - Default slot - Main modal content
|
|
3079
|
+
*
|
|
3080
|
+
* @example
|
|
3081
|
+
* ```html
|
|
3082
|
+
* <!-- Simple title modal -->
|
|
3083
|
+
* <ds-mobile-modal-base
|
|
3084
|
+
* headerTitle="Settings"
|
|
3085
|
+
* closeButtonLabel="Close">
|
|
3086
|
+
* <div class="content">...</div>
|
|
3087
|
+
* </ds-mobile-modal-base>
|
|
3088
|
+
*
|
|
3089
|
+
* <!-- Avatar header modal -->
|
|
3090
|
+
* <ds-mobile-modal-base
|
|
3091
|
+
* headerTitle="John Doe"
|
|
3092
|
+
* headerMeta="Tenant · 2h ago"
|
|
3093
|
+
* [hasFixedBottom]="true"
|
|
3094
|
+
* [enableKeyboardHandling]="true">
|
|
3095
|
+
*
|
|
3096
|
+
* <ds-avatar header-leading [initials]="'JD'" size="md" />
|
|
3097
|
+
*
|
|
3098
|
+
* <div class="content">...</div>
|
|
3099
|
+
*
|
|
3100
|
+
* <div fixed-bottom class="composer">...</div>
|
|
3101
|
+
* </ds-mobile-modal-base>
|
|
3102
|
+
*
|
|
3103
|
+
* <!-- Headerless modal (close button positioned absolutely) -->
|
|
3104
|
+
* <ds-mobile-modal-base [showHeader]="false">
|
|
3105
|
+
* <div class="full-width-content">...</div>
|
|
3106
|
+
* </ds-mobile-modal-base>
|
|
3107
|
+
*
|
|
3108
|
+
* <!-- Modal with footer actions (slides with keyboard) -->
|
|
3109
|
+
* <ds-mobile-modal-base
|
|
3110
|
+
* headerTitle="Create Inquiry"
|
|
3111
|
+
* [hasFixedBottom]="true"
|
|
3112
|
+
* [enableKeyboardHandling]="true">
|
|
3113
|
+
*
|
|
3114
|
+
* <div class="content">
|
|
3115
|
+
* <input type="text" placeholder="Type something..." />
|
|
3116
|
+
* </div>
|
|
3117
|
+
*
|
|
3118
|
+
* <div footer class="action-bar">
|
|
3119
|
+
* <button>Cancel</button>
|
|
3120
|
+
* <button>Submit</button>
|
|
3121
|
+
* </div>
|
|
3122
|
+
* </ds-mobile-modal-base>
|
|
3123
|
+
* ```
|
|
3124
|
+
*/
|
|
3125
|
+
declare class DsMobileModalBaseComponent extends MobileModalBase implements AfterContentInit {
|
|
3126
|
+
private cdr;
|
|
3127
|
+
/**
|
|
3128
|
+
* Reference to ion-content for keyboard handling
|
|
3129
|
+
*/
|
|
3130
|
+
ionContent?: IonContent;
|
|
3131
|
+
/**
|
|
3132
|
+
* Control header visibility
|
|
3133
|
+
* - true: Always show header
|
|
3134
|
+
* - false: Never show header (close button becomes absolute)
|
|
3135
|
+
* - 'auto' (default): Auto-detect based on header content
|
|
3136
|
+
*/
|
|
3137
|
+
showHeader: _angular_core.InputSignal<boolean | "auto">;
|
|
3138
|
+
/**
|
|
3139
|
+
* Detect if custom loading state is provided
|
|
3140
|
+
*/
|
|
3141
|
+
customLoadingState?: ElementRef;
|
|
3142
|
+
/**
|
|
3143
|
+
* Detect if custom error state is provided
|
|
3144
|
+
*/
|
|
3145
|
+
customErrorState?: ElementRef;
|
|
3146
|
+
/**
|
|
3147
|
+
* Detect if header leading content is provided
|
|
3148
|
+
*/
|
|
3149
|
+
headerLeading?: ElementRef;
|
|
3150
|
+
/**
|
|
3151
|
+
* Detect if header main content is provided
|
|
3152
|
+
*/
|
|
3153
|
+
headerMain?: ElementRef;
|
|
3154
|
+
/**
|
|
3155
|
+
* Flag to track if content has been initialized
|
|
3156
|
+
*/
|
|
3157
|
+
hasCustomLoadingState: boolean;
|
|
3158
|
+
hasCustomErrorState: boolean;
|
|
3159
|
+
constructor(cdr: ChangeDetectorRef);
|
|
3160
|
+
ngAfterContentInit(): void;
|
|
3161
|
+
/**
|
|
3162
|
+
* Determine if header should be shown based on showHeader input and content detection
|
|
3163
|
+
*/
|
|
3164
|
+
shouldShowHeader(): boolean;
|
|
3165
|
+
/**
|
|
3166
|
+
* Check if a content child slot has actual content
|
|
3167
|
+
*/
|
|
3168
|
+
private hasContentInSlot;
|
|
3169
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<DsMobileModalBaseComponent, never>;
|
|
3170
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<DsMobileModalBaseComponent, "ds-mobile-modal-base", never, { "showHeader": { "alias": "showHeader"; "required": false; "isSignal": true; }; }, {}, ["customLoadingState", "customErrorState", "headerLeading", "headerMain"], ["[header-leading]", "[header-main]", "[loading-state]", "[error-state]", "*", "[fixed-bottom]", "[footer]"], true, never>;
|
|
3171
|
+
}
|
|
3172
|
+
|
|
3173
|
+
/**
|
|
3174
|
+
* Post data interface for the modal
|
|
3175
|
+
*
|
|
3176
|
+
* Represents a post with its content, author info, and comments.
|
|
3177
|
+
* Use this interface to map your API response data to the component.
|
|
3178
|
+
*
|
|
3179
|
+
* @example
|
|
3180
|
+
* ```typescript
|
|
3181
|
+
* const postData: PostDetailData = {
|
|
3182
|
+
* postId: '123',
|
|
3183
|
+
* authorName: 'John Doe',
|
|
3184
|
+
* authorRole: 'Tenant',
|
|
3185
|
+
* timestamp: '2h ago',
|
|
3186
|
+
* avatarInitials: 'JD',
|
|
3187
|
+
* content: 'Post content here...',
|
|
3188
|
+
* likeCount: 42,
|
|
3189
|
+
* commentCount: 12,
|
|
3190
|
+
* comments: [...]
|
|
3191
|
+
* };
|
|
3192
|
+
* ```
|
|
3193
|
+
*/
|
|
3194
|
+
interface PostDetailData {
|
|
3195
|
+
/** Unique post identifier */
|
|
3196
|
+
postId: string;
|
|
3197
|
+
/** Post author name */
|
|
3198
|
+
authorName: string;
|
|
3199
|
+
/** Author role (e.g., 'Tenant', 'Manager') */
|
|
3200
|
+
authorRole: string;
|
|
3201
|
+
/** Post timestamp (e.g., '2h ago', 'Yesterday') */
|
|
3202
|
+
timestamp: string;
|
|
3203
|
+
/** Author avatar initials (1-2 letters) */
|
|
3204
|
+
avatarInitials?: string;
|
|
3205
|
+
/** Avatar display type */
|
|
3206
|
+
avatarType?: 'photo' | 'initials';
|
|
3207
|
+
/** Author avatar image URL */
|
|
3208
|
+
avatarSrc?: string;
|
|
3209
|
+
/** Post text content */
|
|
3210
|
+
content: string;
|
|
3211
|
+
/** Optional post image URL */
|
|
3212
|
+
imageSrc?: string;
|
|
3213
|
+
/** Image alt text */
|
|
3214
|
+
imageAlt?: string;
|
|
3215
|
+
/** Whether the current user has liked this post */
|
|
3216
|
+
isLiked?: boolean;
|
|
3217
|
+
/** Number of likes */
|
|
3218
|
+
likeCount?: number;
|
|
3219
|
+
/** Number of comments */
|
|
3220
|
+
commentCount?: number;
|
|
3221
|
+
/** Array of comments */
|
|
3222
|
+
comments?: CommentData[];
|
|
3223
|
+
/** Auto-focus comment input when modal opens */
|
|
3224
|
+
focusComment?: boolean;
|
|
3225
|
+
}
|
|
3226
|
+
/**
|
|
3227
|
+
* Comment data interface
|
|
3228
|
+
*
|
|
3229
|
+
* Represents a single comment on a post.
|
|
3230
|
+
*
|
|
3231
|
+
* @example
|
|
3232
|
+
* ```typescript
|
|
3233
|
+
* const comment: CommentData = {
|
|
3234
|
+
* authorName: 'Jane Smith',
|
|
3235
|
+
* authorRole: 'Tenant',
|
|
3236
|
+
* timestamp: '1h ago',
|
|
3237
|
+
* avatarInitials: 'JS',
|
|
3238
|
+
* content: 'Great post!',
|
|
3239
|
+
* isLiked: false,
|
|
3240
|
+
* likeCount: 5,
|
|
3241
|
+
* isOwnComment: false
|
|
3242
|
+
* };
|
|
3243
|
+
* ```
|
|
3244
|
+
*/
|
|
3245
|
+
interface CommentData {
|
|
3246
|
+
/** Unique comment identifier */
|
|
3247
|
+
id?: string;
|
|
3248
|
+
/** Comment author name */
|
|
3249
|
+
authorName: string;
|
|
3250
|
+
/** Author role */
|
|
3251
|
+
authorRole: string;
|
|
3252
|
+
/** Comment timestamp */
|
|
3253
|
+
timestamp: string;
|
|
2892
3254
|
/** Author avatar initials */
|
|
2893
3255
|
avatarInitials: string;
|
|
2894
3256
|
/** Comment text content */
|
|
@@ -2929,13 +3291,14 @@ interface CommentData {
|
|
|
2929
3291
|
* }
|
|
2930
3292
|
* ```
|
|
2931
3293
|
*/
|
|
2932
|
-
declare class DsMobilePostDetailModalComponent implements
|
|
2933
|
-
private modalController;
|
|
3294
|
+
declare class DsMobilePostDetailModalComponent implements OnInit, AfterViewInit {
|
|
2934
3295
|
private lightbox;
|
|
2935
3296
|
private bottomSheet;
|
|
2936
3297
|
postData: PostDetailData;
|
|
2937
3298
|
currentUserName: string;
|
|
2938
3299
|
currentUserInitialsInput: string;
|
|
3300
|
+
loading: boolean;
|
|
3301
|
+
error: string | undefined;
|
|
2939
3302
|
onSubmitComment?: (payload: {
|
|
2940
3303
|
postId: string;
|
|
2941
3304
|
text: string;
|
|
@@ -2951,16 +3314,6 @@ declare class DsMobilePostDetailModalComponent implements AfterViewInit, OnDestr
|
|
|
2951
3314
|
onDeleteComment?: (payload: {
|
|
2952
3315
|
commentId: string;
|
|
2953
3316
|
}) => void;
|
|
2954
|
-
/**
|
|
2955
|
-
* Loading state - when true, shows loading indicator
|
|
2956
|
-
* Set this to true while fetching post data from your API
|
|
2957
|
-
*/
|
|
2958
|
-
loading: boolean;
|
|
2959
|
-
/**
|
|
2960
|
-
* Error state - when set, shows error message
|
|
2961
|
-
* Set this to an error message string if API call fails
|
|
2962
|
-
*/
|
|
2963
|
-
error?: string;
|
|
2964
3317
|
commentInput?: ElementRef<HTMLTextAreaElement>;
|
|
2965
3318
|
post: _angular_core.WritableSignal<PostDetailData>;
|
|
2966
3319
|
commentText: _angular_core.WritableSignal<string>;
|
|
@@ -2987,19 +3340,9 @@ declare class DsMobilePostDetailModalComponent implements AfterViewInit, OnDestr
|
|
|
2987
3340
|
initials: string;
|
|
2988
3341
|
role: string;
|
|
2989
3342
|
}[]>;
|
|
2990
|
-
constructor(
|
|
3343
|
+
constructor(lightbox: DsMobileLightboxService, bottomSheet: DsMobileBottomSheetService);
|
|
2991
3344
|
ngOnInit(): void;
|
|
2992
3345
|
ngAfterViewInit(): void;
|
|
2993
|
-
ngOnDestroy(): void;
|
|
2994
|
-
/**
|
|
2995
|
-
* Set up keyboard event listeners to adjust composer position
|
|
2996
|
-
* The CSS uses --keyboard-height variable to translate the composer up
|
|
2997
|
-
*/
|
|
2998
|
-
private setupKeyboardListeners;
|
|
2999
|
-
/**
|
|
3000
|
-
* Clean up keyboard event listeners
|
|
3001
|
-
*/
|
|
3002
|
-
private cleanupKeyboardListeners;
|
|
3003
3346
|
/**
|
|
3004
3347
|
* Show the keyboard when user interacts with input
|
|
3005
3348
|
*/
|
|
@@ -3041,10 +3384,6 @@ declare class DsMobilePostDetailModalComponent implements AfterViewInit, OnDestr
|
|
|
3041
3384
|
active: boolean;
|
|
3042
3385
|
count: number;
|
|
3043
3386
|
}): void;
|
|
3044
|
-
/**
|
|
3045
|
-
* Close the modal
|
|
3046
|
-
*/
|
|
3047
|
-
close(): void;
|
|
3048
3387
|
/**
|
|
3049
3388
|
* Submit a comment
|
|
3050
3389
|
*/
|
|
@@ -3058,7 +3397,83 @@ declare class DsMobilePostDetailModalComponent implements AfterViewInit, OnDestr
|
|
|
3058
3397
|
*/
|
|
3059
3398
|
handleCommentLongPress(authorName: string, content: string, isOwnComment: boolean): Promise<void>;
|
|
3060
3399
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<DsMobilePostDetailModalComponent, never>;
|
|
3061
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<DsMobilePostDetailModalComponent, "ds-mobile-post-detail-modal", never, { "postData": { "alias": "postData"; "required": false; }; "currentUserName": { "alias": "currentUserName"; "required": false; }; "currentUserInitialsInput": { "alias": "currentUserInitialsInput"; "required": false; }; "
|
|
3400
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<DsMobilePostDetailModalComponent, "ds-mobile-post-detail-modal", never, { "postData": { "alias": "postData"; "required": false; }; "currentUserName": { "alias": "currentUserName"; "required": false; }; "currentUserInitialsInput": { "alias": "currentUserInitialsInput"; "required": false; }; "loading": { "alias": "loading"; "required": false; }; "error": { "alias": "error"; "required": false; }; "onSubmitComment": { "alias": "onSubmitComment"; "required": false; }; "onToggleCommentLike": { "alias": "onToggleCommentLike"; "required": false; }; "onEditComment": { "alias": "onEditComment"; "required": false; }; "onDeleteComment": { "alias": "onDeleteComment"; "required": false; }; }, {}, never, never, true, never>;
|
|
3401
|
+
}
|
|
3402
|
+
|
|
3403
|
+
/**
|
|
3404
|
+
* BaseModalService
|
|
3405
|
+
*
|
|
3406
|
+
* Abstract base class for all modal services in the application.
|
|
3407
|
+
* Enforces consistent modal configuration and presentation across all modals.
|
|
3408
|
+
*
|
|
3409
|
+
* **Features:**
|
|
3410
|
+
* - Standardized modal presentation (stacked effect with gap at top)
|
|
3411
|
+
* - Consistent backdrop and dismissal behavior
|
|
3412
|
+
* - Automatic safe area handling
|
|
3413
|
+
* - Native iOS-style animations
|
|
3414
|
+
*
|
|
3415
|
+
* **Why use this:**
|
|
3416
|
+
* - Ensures all modals have the same look and feel
|
|
3417
|
+
* - Prevents inconsistencies in modal configuration
|
|
3418
|
+
* - Single source of truth for modal settings
|
|
3419
|
+
* - Makes it impossible to forget critical configuration
|
|
3420
|
+
*
|
|
3421
|
+
* @example
|
|
3422
|
+
* ```typescript
|
|
3423
|
+
* @Injectable({ providedIn: 'root' })
|
|
3424
|
+
* export class MyModalService extends BaseModalService {
|
|
3425
|
+
* async open(data: MyData) {
|
|
3426
|
+
* const modal = await this.createModal(
|
|
3427
|
+
* MyModalComponent,
|
|
3428
|
+
* { data }
|
|
3429
|
+
* );
|
|
3430
|
+
* await modal.present();
|
|
3431
|
+
* }
|
|
3432
|
+
* }
|
|
3433
|
+
* ```
|
|
3434
|
+
*/
|
|
3435
|
+
declare abstract class BaseModalService {
|
|
3436
|
+
protected modalController: ModalController;
|
|
3437
|
+
constructor(modalController: ModalController);
|
|
3438
|
+
/**
|
|
3439
|
+
* Create a modal with standardized configuration
|
|
3440
|
+
*
|
|
3441
|
+
* This method enforces consistent modal behavior across the app:
|
|
3442
|
+
* - Uses 'ds-modal-base' CSS class for consistent styling
|
|
3443
|
+
* - iOS mode for native feel
|
|
3444
|
+
* - presentingElement for stacked modal effect
|
|
3445
|
+
* - Standard backdrop and dismissal settings
|
|
3446
|
+
*
|
|
3447
|
+
* @param component The component to display in the modal
|
|
3448
|
+
* @param componentProps Props to pass to the component
|
|
3449
|
+
* @param customOptions Optional overrides for specific modal needs
|
|
3450
|
+
* @returns Promise resolving to the created modal
|
|
3451
|
+
*
|
|
3452
|
+
* @example
|
|
3453
|
+
* ```typescript
|
|
3454
|
+
* const modal = await this.createModal(
|
|
3455
|
+
* PostDetailComponent,
|
|
3456
|
+
* { postId: '123', loading: false }
|
|
3457
|
+
* );
|
|
3458
|
+
* await modal.present();
|
|
3459
|
+
* ```
|
|
3460
|
+
*/
|
|
3461
|
+
protected createModal<T>(component: Type<T>, componentProps?: Record<string, any>, customOptions?: Partial<ModalOptions$1>): Promise<HTMLIonModalElement>;
|
|
3462
|
+
/**
|
|
3463
|
+
* Close the currently open modal
|
|
3464
|
+
*
|
|
3465
|
+
* @param data Optional data to pass back when dismissing
|
|
3466
|
+
* @returns Promise that resolves when the modal is dismissed
|
|
3467
|
+
*/
|
|
3468
|
+
close(data?: any): Promise<boolean>;
|
|
3469
|
+
/**
|
|
3470
|
+
* Get the top-most modal if one exists
|
|
3471
|
+
*
|
|
3472
|
+
* @returns Promise that resolves to the modal element or undefined
|
|
3473
|
+
*/
|
|
3474
|
+
getTop(): Promise<HTMLIonModalElement | undefined>;
|
|
3475
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<BaseModalService, never>;
|
|
3476
|
+
static ɵprov: _angular_core.ɵɵInjectableDeclaration<BaseModalService>;
|
|
3062
3477
|
}
|
|
3063
3478
|
|
|
3064
3479
|
/**
|
|
@@ -3104,8 +3519,7 @@ declare class DsMobilePostDetailModalComponent implements AfterViewInit, OnDestr
|
|
|
3104
3519
|
* }
|
|
3105
3520
|
* ```
|
|
3106
3521
|
*/
|
|
3107
|
-
declare class DsMobilePostDetailModalService {
|
|
3108
|
-
private modalController;
|
|
3522
|
+
declare class DsMobilePostDetailModalService extends BaseModalService {
|
|
3109
3523
|
constructor(modalController: ModalController);
|
|
3110
3524
|
/**
|
|
3111
3525
|
* Open the post detail modal
|
|
@@ -3135,19 +3549,6 @@ declare class DsMobilePostDetailModalService {
|
|
|
3135
3549
|
currentUserName?: string;
|
|
3136
3550
|
currentUserInitials?: string;
|
|
3137
3551
|
}): Promise<void>;
|
|
3138
|
-
/**
|
|
3139
|
-
* Close the currently open post detail modal
|
|
3140
|
-
*
|
|
3141
|
-
* @param data Optional data to pass back when dismissing
|
|
3142
|
-
* @returns Promise that resolves when the modal is dismissed
|
|
3143
|
-
*/
|
|
3144
|
-
close(data?: any): Promise<boolean>;
|
|
3145
|
-
/**
|
|
3146
|
-
* Get the top-most modal if one exists
|
|
3147
|
-
*
|
|
3148
|
-
* @returns Promise that resolves to the modal element or undefined
|
|
3149
|
-
*/
|
|
3150
|
-
getTop(): Promise<HTMLIonModalElement | undefined>;
|
|
3151
3552
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<DsMobilePostDetailModalService, never>;
|
|
3152
3553
|
static ɵprov: _angular_core.ɵɵInjectableDeclaration<DsMobilePostDetailModalService>;
|
|
3153
3554
|
}
|
|
@@ -3161,12 +3562,21 @@ interface ChatMessage {
|
|
|
3161
3562
|
senderId: string;
|
|
3162
3563
|
senderName: string;
|
|
3163
3564
|
senderRole?: string;
|
|
3164
|
-
timestamp:
|
|
3565
|
+
timestamp: Date;
|
|
3165
3566
|
avatarInitials?: string;
|
|
3166
3567
|
avatarType?: 'initials' | 'photo' | 'icon';
|
|
3167
3568
|
avatarSrc?: string;
|
|
3168
3569
|
isOwnMessage: boolean;
|
|
3169
3570
|
attachments?: ChatAttachment[];
|
|
3571
|
+
fileAttachments?: AttachmentData[];
|
|
3572
|
+
}
|
|
3573
|
+
/**
|
|
3574
|
+
* Message group interface for grouped timestamp display
|
|
3575
|
+
*/
|
|
3576
|
+
interface MessageGroup {
|
|
3577
|
+
timestamp: Date;
|
|
3578
|
+
displayTimestamp: string;
|
|
3579
|
+
messages: ChatMessage[];
|
|
3170
3580
|
}
|
|
3171
3581
|
/**
|
|
3172
3582
|
* Chat participant interface
|
|
@@ -3184,27 +3594,58 @@ interface ChatParticipant {
|
|
|
3184
3594
|
*
|
|
3185
3595
|
* Represents the data needed to display a chat conversation.
|
|
3186
3596
|
*
|
|
3187
|
-
|
|
3597
|
+
* @example
|
|
3188
3598
|
* ```typescript
|
|
3189
3599
|
* const chatData: ChatModalData = {
|
|
3190
3600
|
* participant: {
|
|
3191
|
-
* id: '123',
|
|
3601
|
+
* id: 'u-123',
|
|
3192
3602
|
* name: 'Ricki Meihlen',
|
|
3193
3603
|
* role: 'Inquiry assignee',
|
|
3194
|
-
* avatarInitials: 'RM'
|
|
3604
|
+
* avatarInitials: 'RM',
|
|
3605
|
+
* avatarType: 'initials'
|
|
3195
3606
|
* },
|
|
3607
|
+
* currentUserId: 'u-456',
|
|
3608
|
+
* currentUserInitials: 'SD',
|
|
3609
|
+
* currentUserAvatarType: 'initials',
|
|
3610
|
+
* autoFocus: true,
|
|
3196
3611
|
* messages: [
|
|
3197
3612
|
* {
|
|
3198
|
-
* id: '1',
|
|
3199
|
-
* content: 'We have received your case
|
|
3200
|
-
* senderId: '123',
|
|
3613
|
+
* id: 'm-1',
|
|
3614
|
+
* content: 'We have received your case. Please see the attached photo.',
|
|
3615
|
+
* senderId: 'u-123',
|
|
3201
3616
|
* senderName: 'Ricki Meihlen',
|
|
3617
|
+
* senderRole: 'Case worker',
|
|
3202
3618
|
* timestamp: '12:34',
|
|
3203
3619
|
* isOwnMessage: false,
|
|
3204
|
-
* avatarInitials: 'RM'
|
|
3620
|
+
* avatarInitials: 'RM',
|
|
3621
|
+
* avatarType: 'initials',
|
|
3622
|
+
* attachments: [
|
|
3623
|
+
* {
|
|
3624
|
+
* id: 'a-1',
|
|
3625
|
+
* type: 'image',
|
|
3626
|
+
* url: 'https://example.com/photo.jpg',
|
|
3627
|
+
* name: 'photo.jpg',
|
|
3628
|
+
* thumbnail: 'https://example.com/photo_thumb.jpg'
|
|
3629
|
+
* },
|
|
3630
|
+
* {
|
|
3631
|
+
* id: 'a-2',
|
|
3632
|
+
* type: 'pdf',
|
|
3633
|
+
* url: 'https://example.com/report.pdf',
|
|
3634
|
+
* name: 'report.pdf'
|
|
3635
|
+
* }
|
|
3636
|
+
* ]
|
|
3637
|
+
* },
|
|
3638
|
+
* {
|
|
3639
|
+
* id: 'm-2',
|
|
3640
|
+
* content: 'Thanks — I will take a look.',
|
|
3641
|
+
* senderId: 'u-456',
|
|
3642
|
+
* senderName: 'You',
|
|
3643
|
+
* timestamp: '12:36',
|
|
3644
|
+
* isOwnMessage: true,
|
|
3645
|
+
* avatarInitials: 'SD',
|
|
3646
|
+
* avatarType: 'initials'
|
|
3205
3647
|
* }
|
|
3206
|
-
* ]
|
|
3207
|
-
* currentUserId: '456'
|
|
3648
|
+
* ]
|
|
3208
3649
|
* };
|
|
3209
3650
|
* ```
|
|
3210
3651
|
*/
|
|
@@ -3253,9 +3694,8 @@ interface ChatModalData {
|
|
|
3253
3694
|
* }
|
|
3254
3695
|
* ```
|
|
3255
3696
|
*/
|
|
3256
|
-
declare class DsMobileChatModalComponent implements OnInit, AfterViewInit
|
|
3257
|
-
private
|
|
3258
|
-
private lightbox;
|
|
3697
|
+
declare class DsMobileChatModalComponent implements OnInit, AfterViewInit {
|
|
3698
|
+
private lightboxService;
|
|
3259
3699
|
chatData: ChatModalData;
|
|
3260
3700
|
/**
|
|
3261
3701
|
* Loading state - when true, shows loading indicator
|
|
@@ -3271,18 +3711,25 @@ declare class DsMobileChatModalComponent implements OnInit, AfterViewInit, OnDes
|
|
|
3271
3711
|
currentUserAvatarType: _angular_core.WritableSignal<"initials" | "photo" | "icon">;
|
|
3272
3712
|
currentUserAvatarSrc: _angular_core.WritableSignal<string>;
|
|
3273
3713
|
autoFocus: _angular_core.WritableSignal<boolean>;
|
|
3274
|
-
|
|
3714
|
+
/**
|
|
3715
|
+
* Selected message ID for showing timestamp
|
|
3716
|
+
*/
|
|
3717
|
+
selectedMessageId: _angular_core.WritableSignal<string | null>;
|
|
3718
|
+
/**
|
|
3719
|
+
* Timeout for auto-hiding timestamp
|
|
3720
|
+
*/
|
|
3721
|
+
private timestampTimeout?;
|
|
3722
|
+
/**
|
|
3723
|
+
* Computed signal for grouped messages with timestamp headers
|
|
3724
|
+
*/
|
|
3725
|
+
messageGroups: _angular_core.Signal<MessageGroup[]>;
|
|
3726
|
+
constructor(lightboxService: DsMobileLightboxService);
|
|
3275
3727
|
ngOnInit(): void;
|
|
3276
3728
|
ngAfterViewInit(): void;
|
|
3277
|
-
ngOnDestroy(): void;
|
|
3278
3729
|
/**
|
|
3279
3730
|
* Scroll to bottom of messages
|
|
3280
3731
|
*/
|
|
3281
3732
|
private scrollToBottom;
|
|
3282
|
-
/**
|
|
3283
|
-
* Close the modal
|
|
3284
|
-
*/
|
|
3285
|
-
close(): void;
|
|
3286
3733
|
/**
|
|
3287
3734
|
* Handle message sent from composer
|
|
3288
3735
|
*/
|
|
@@ -3291,15 +3738,54 @@ declare class DsMobileChatModalComponent implements OnInit, AfterViewInit, OnDes
|
|
|
3291
3738
|
isReply?: boolean;
|
|
3292
3739
|
replyTo?: string;
|
|
3293
3740
|
isEdit?: boolean;
|
|
3741
|
+
attachments?: AttachmentData[];
|
|
3294
3742
|
}): void;
|
|
3295
3743
|
/**
|
|
3296
3744
|
* Handle attachment click
|
|
3297
3745
|
*/
|
|
3298
3746
|
handleAttachmentClick(attachment: ChatAttachment): void;
|
|
3747
|
+
/**
|
|
3748
|
+
* Handle composer attachment button click
|
|
3749
|
+
*/
|
|
3750
|
+
handleComposerAttachmentClick(): void;
|
|
3751
|
+
/**
|
|
3752
|
+
* Get file variant for card-inline-file component
|
|
3753
|
+
*/
|
|
3754
|
+
getFileVariant(type: string): 'pdf' | 'doc';
|
|
3755
|
+
/**
|
|
3756
|
+
* Handle file attachment click
|
|
3757
|
+
*/
|
|
3758
|
+
handleFileAttachmentClick(fileAttachment: AttachmentData): void;
|
|
3759
|
+
/**
|
|
3760
|
+
* Handle image attachment click - opens lightbox
|
|
3761
|
+
*/
|
|
3762
|
+
handleImageClick(attachment: AttachmentData, message: ChatMessage): Promise<void>;
|
|
3299
3763
|
/**
|
|
3300
3764
|
* Handle message long press
|
|
3301
3765
|
*/
|
|
3302
3766
|
handleMessageLongPress(message: ChatMessage): void;
|
|
3767
|
+
/**
|
|
3768
|
+
* Handle message click to show/hide timestamp
|
|
3769
|
+
*/
|
|
3770
|
+
handleMessageClick(messageId: string): void;
|
|
3771
|
+
/**
|
|
3772
|
+
* Format message timestamp for display (EU 24-hour format, Danish)
|
|
3773
|
+
*/
|
|
3774
|
+
formatMessageTimestamp(date: Date): string;
|
|
3775
|
+
/**
|
|
3776
|
+
* Group messages by time threshold
|
|
3777
|
+
* Messages within the threshold and on the same day are grouped together
|
|
3778
|
+
*/
|
|
3779
|
+
private groupMessagesByTime;
|
|
3780
|
+
/**
|
|
3781
|
+
* Determine if a new message group should be started
|
|
3782
|
+
*/
|
|
3783
|
+
private shouldStartNewGroup;
|
|
3784
|
+
/**
|
|
3785
|
+
* Format group timestamp header with smart date display
|
|
3786
|
+
* Uses 24-hour EU time format with Danish locale
|
|
3787
|
+
*/
|
|
3788
|
+
private formatGroupTimestamp;
|
|
3303
3789
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<DsMobileChatModalComponent, never>;
|
|
3304
3790
|
static ɵcmp: _angular_core.ɵɵComponentDeclaration<DsMobileChatModalComponent, "ds-mobile-chat-modal", never, { "chatData": { "alias": "chatData"; "required": false; }; "loading": { "alias": "loading"; "required": false; }; "error": { "alias": "error"; "required": false; }; }, {}, never, never, true, never>;
|
|
3305
3791
|
}
|
|
@@ -3359,8 +3845,7 @@ declare class DsMobileChatModalComponent implements OnInit, AfterViewInit, OnDes
|
|
|
3359
3845
|
* }
|
|
3360
3846
|
* ```
|
|
3361
3847
|
*/
|
|
3362
|
-
declare class DsMobileChatModalService {
|
|
3363
|
-
private modalController;
|
|
3848
|
+
declare class DsMobileChatModalService extends BaseModalService {
|
|
3364
3849
|
constructor(modalController: ModalController);
|
|
3365
3850
|
/**
|
|
3366
3851
|
* Open the chat modal
|
|
@@ -3373,21 +3858,190 @@ declare class DsMobileChatModalService {
|
|
|
3373
3858
|
loading?: boolean;
|
|
3374
3859
|
error?: string;
|
|
3375
3860
|
}): Promise<void>;
|
|
3861
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<DsMobileChatModalService, never>;
|
|
3862
|
+
static ɵprov: _angular_core.ɵɵInjectableDeclaration<DsMobileChatModalService>;
|
|
3863
|
+
}
|
|
3864
|
+
|
|
3865
|
+
/**
|
|
3866
|
+
* Photo interface for inquiry (deprecated - use AttachmentData)
|
|
3867
|
+
* @deprecated Use AttachmentData from attachment-preview component instead
|
|
3868
|
+
*/
|
|
3869
|
+
interface InquiryPhoto {
|
|
3870
|
+
id: string;
|
|
3871
|
+
src: string;
|
|
3872
|
+
alt?: string;
|
|
3873
|
+
}
|
|
3874
|
+
/**
|
|
3875
|
+
* New inquiry form data
|
|
3876
|
+
*/
|
|
3877
|
+
interface NewInquiryData {
|
|
3878
|
+
title: string;
|
|
3879
|
+
description: string;
|
|
3880
|
+
attachments: AttachmentData[];
|
|
3881
|
+
category?: string;
|
|
3882
|
+
}
|
|
3883
|
+
/**
|
|
3884
|
+
* DsMobileNewInquiryModalComponent
|
|
3885
|
+
*
|
|
3886
|
+
* Modal component for creating new inquiries.
|
|
3887
|
+
* Uses ds-mobile-modal-base for consistent layout and behavior.
|
|
3888
|
+
*
|
|
3889
|
+
* Features:
|
|
3890
|
+
* - Title and description fields
|
|
3891
|
+
* - Photo upload with preview
|
|
3892
|
+
* - Submit button at bottom
|
|
3893
|
+
* - Form validation
|
|
3894
|
+
* - Camera/photo picker integration
|
|
3895
|
+
*
|
|
3896
|
+
* This component is typically not used directly - use DsMobileNewInquiryModalService instead.
|
|
3897
|
+
*
|
|
3898
|
+
* @example
|
|
3899
|
+
* ```typescript
|
|
3900
|
+
* // Don't instantiate directly - use the service:
|
|
3901
|
+
* constructor(private inquiryModal: DsMobileNewInquiryModalService) {}
|
|
3902
|
+
*
|
|
3903
|
+
* createInquiry() {
|
|
3904
|
+
* this.inquiryModal.open({
|
|
3905
|
+
* onSubmit: (data) => console.log('Inquiry created:', data)
|
|
3906
|
+
* });
|
|
3907
|
+
* }
|
|
3908
|
+
* ```
|
|
3909
|
+
*/
|
|
3910
|
+
declare class DsMobileNewInquiryModalComponent implements OnInit, AfterViewInit {
|
|
3911
|
+
titleInputRef?: ElementRef<HTMLElement>;
|
|
3912
|
+
titleInput?: DsTextareaComponent;
|
|
3913
|
+
fileInput?: ElementRef<HTMLInputElement>;
|
|
3376
3914
|
/**
|
|
3377
|
-
*
|
|
3378
|
-
*
|
|
3379
|
-
* @param data Optional data to pass back when dismissing
|
|
3380
|
-
* @returns Promise that resolves when the modal is dismissed
|
|
3915
|
+
* Loading state for the modal
|
|
3381
3916
|
*/
|
|
3382
|
-
|
|
3917
|
+
loading: boolean;
|
|
3383
3918
|
/**
|
|
3384
|
-
*
|
|
3919
|
+
* Error message to display
|
|
3920
|
+
*/
|
|
3921
|
+
error?: string;
|
|
3922
|
+
/**
|
|
3923
|
+
* Callback function when form is submitted
|
|
3924
|
+
*/
|
|
3925
|
+
onSubmit?: (data: NewInquiryData) => void | Promise<void>;
|
|
3926
|
+
/**
|
|
3927
|
+
* Form title field
|
|
3928
|
+
*/
|
|
3929
|
+
title: string;
|
|
3930
|
+
/**
|
|
3931
|
+
* Form description field
|
|
3932
|
+
*/
|
|
3933
|
+
description: string;
|
|
3934
|
+
/**
|
|
3935
|
+
* Attachments array (replaces photos)
|
|
3936
|
+
*/
|
|
3937
|
+
attachments: _angular_core.WritableSignal<AttachmentData[]>;
|
|
3938
|
+
/**
|
|
3939
|
+
* Form validation state
|
|
3940
|
+
*/
|
|
3941
|
+
isFormValid: _angular_core.WritableSignal<boolean>;
|
|
3942
|
+
/**
|
|
3943
|
+
* Submitting state
|
|
3944
|
+
*/
|
|
3945
|
+
isSubmitting: _angular_core.WritableSignal<boolean>;
|
|
3946
|
+
ngOnInit(): void;
|
|
3947
|
+
ngAfterViewInit(): void;
|
|
3948
|
+
/**
|
|
3949
|
+
* Auto-resize the title textarea based on content
|
|
3950
|
+
*/
|
|
3951
|
+
private autoResizeTitleTextarea;
|
|
3952
|
+
/**
|
|
3953
|
+
* Handle title change with auto-resize
|
|
3954
|
+
*/
|
|
3955
|
+
handleTitleChange(value: string): void;
|
|
3956
|
+
/**
|
|
3957
|
+
* Validate form fields
|
|
3958
|
+
*/
|
|
3959
|
+
validateForm(): void;
|
|
3960
|
+
/**
|
|
3961
|
+
* Add a new photo from camera/library
|
|
3962
|
+
*/
|
|
3963
|
+
addPhoto(): Promise<void>;
|
|
3964
|
+
/**
|
|
3965
|
+
* Remove an attachment
|
|
3966
|
+
*/
|
|
3967
|
+
removeAttachment(attachmentId: string): void;
|
|
3968
|
+
/**
|
|
3969
|
+
* Handle attachment button click
|
|
3970
|
+
*/
|
|
3971
|
+
handleAddAttachment(): void;
|
|
3972
|
+
/**
|
|
3973
|
+
* Detect file type from file name or mime type
|
|
3974
|
+
*/
|
|
3975
|
+
private detectFileType;
|
|
3976
|
+
/**
|
|
3977
|
+
* Format file size for display
|
|
3978
|
+
*/
|
|
3979
|
+
private formatFileSize;
|
|
3980
|
+
/**
|
|
3981
|
+
* Handle file selection from file input
|
|
3982
|
+
*/
|
|
3983
|
+
handleFileSelect(event: Event): void;
|
|
3984
|
+
/**
|
|
3985
|
+
* Handle form submission
|
|
3986
|
+
*/
|
|
3987
|
+
handleSubmit(): Promise<void>;
|
|
3988
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<DsMobileNewInquiryModalComponent, never>;
|
|
3989
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<DsMobileNewInquiryModalComponent, "ds-mobile-new-inquiry-modal", never, { "loading": { "alias": "loading"; "required": false; }; "error": { "alias": "error"; "required": false; }; "onSubmit": { "alias": "onSubmit"; "required": false; }; }, {}, never, never, true, never>;
|
|
3990
|
+
}
|
|
3991
|
+
|
|
3992
|
+
/**
|
|
3993
|
+
* Options for opening the new inquiry modal
|
|
3994
|
+
*/
|
|
3995
|
+
interface NewInquiryModalOptions {
|
|
3996
|
+
/** Callback function when inquiry is submitted */
|
|
3997
|
+
onSubmit?: (data: NewInquiryData) => void | Promise<void>;
|
|
3998
|
+
/** Initial loading state */
|
|
3999
|
+
loading?: boolean;
|
|
4000
|
+
/** Initial error message */
|
|
4001
|
+
error?: string;
|
|
4002
|
+
}
|
|
4003
|
+
/**
|
|
4004
|
+
* DsMobileNewInquiryModalService
|
|
4005
|
+
*
|
|
4006
|
+
* Service for displaying the new inquiry creation modal.
|
|
4007
|
+
* Built on Ionic's modal system with native gestures and animations.
|
|
4008
|
+
*
|
|
4009
|
+
* Features:
|
|
4010
|
+
* - Full-screen modal with form
|
|
4011
|
+
* - Title and description inputs
|
|
4012
|
+
* - Photo upload with camera/gallery
|
|
4013
|
+
* - Form validation
|
|
4014
|
+
* - Submit handling
|
|
4015
|
+
* - Loading and error states
|
|
4016
|
+
*
|
|
4017
|
+
* @example
|
|
4018
|
+
* ```typescript
|
|
4019
|
+
* constructor(private inquiryModal: DsMobileNewInquiryModalService) {}
|
|
4020
|
+
*
|
|
4021
|
+
* async createNewInquiry() {
|
|
4022
|
+
* await this.inquiryModal.open({
|
|
4023
|
+
* onSubmit: async (data) => {
|
|
4024
|
+
* console.log('Creating inquiry:', data);
|
|
4025
|
+
* // Call your API to create the inquiry
|
|
4026
|
+
* await this.apiService.createInquiry(data);
|
|
4027
|
+
* // Close the modal
|
|
4028
|
+
* await this.inquiryModal.close();
|
|
4029
|
+
* }
|
|
4030
|
+
* });
|
|
4031
|
+
* }
|
|
4032
|
+
* ```
|
|
4033
|
+
*/
|
|
4034
|
+
declare class DsMobileNewInquiryModalService extends BaseModalService {
|
|
4035
|
+
constructor(modalController: ModalController);
|
|
4036
|
+
/**
|
|
4037
|
+
* Open the new inquiry modal
|
|
3385
4038
|
*
|
|
3386
|
-
* @
|
|
4039
|
+
* @param options Modal options including onSubmit callback
|
|
4040
|
+
* @returns Promise that resolves when the modal is presented
|
|
3387
4041
|
*/
|
|
3388
|
-
|
|
3389
|
-
static ɵfac: _angular_core.ɵɵFactoryDeclaration<
|
|
3390
|
-
static ɵprov: _angular_core.ɵɵInjectableDeclaration<
|
|
4042
|
+
open(options?: NewInquiryModalOptions): Promise<void>;
|
|
4043
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<DsMobileNewInquiryModalService, never>;
|
|
4044
|
+
static ɵprov: _angular_core.ɵɵInjectableDeclaration<DsMobileNewInquiryModalService>;
|
|
3391
4045
|
}
|
|
3392
4046
|
|
|
3393
4047
|
/**
|
|
@@ -3513,8 +4167,7 @@ interface ContactItem {
|
|
|
3513
4167
|
*
|
|
3514
4168
|
* This component is typically not used directly - use DsMobileHandbookDetailModalService instead.
|
|
3515
4169
|
*/
|
|
3516
|
-
declare class DsMobileHandbookDetailModalComponent {
|
|
3517
|
-
private modalController;
|
|
4170
|
+
declare class DsMobileHandbookDetailModalComponent implements OnInit {
|
|
3518
4171
|
handbookData: HandbookDetailData;
|
|
3519
4172
|
/**
|
|
3520
4173
|
* Loading state - when true, shows loading indicator
|
|
@@ -3525,7 +4178,6 @@ declare class DsMobileHandbookDetailModalComponent {
|
|
|
3525
4178
|
*/
|
|
3526
4179
|
error?: string;
|
|
3527
4180
|
handbook: _angular_core.WritableSignal<HandbookDetailData>;
|
|
3528
|
-
constructor(modalController: ModalController);
|
|
3529
4181
|
ngOnInit(): void;
|
|
3530
4182
|
/**
|
|
3531
4183
|
* Split handbook items to enforce content structure rules:
|
|
@@ -3540,10 +4192,6 @@ declare class DsMobileHandbookDetailModalComponent {
|
|
|
3540
4192
|
* Get all display items with enforced content structure rules applied
|
|
3541
4193
|
*/
|
|
3542
4194
|
getDisplayItems(): HandbookItem[];
|
|
3543
|
-
/**
|
|
3544
|
-
* Close the modal
|
|
3545
|
-
*/
|
|
3546
|
-
close(): void;
|
|
3547
4195
|
/**
|
|
3548
4196
|
* Handle contact click
|
|
3549
4197
|
*/
|
|
@@ -3594,8 +4242,7 @@ declare class DsMobileHandbookDetailModalComponent {
|
|
|
3594
4242
|
* }
|
|
3595
4243
|
* ```
|
|
3596
4244
|
*/
|
|
3597
|
-
declare class DsMobileHandbookDetailModalService {
|
|
3598
|
-
private modalController;
|
|
4245
|
+
declare class DsMobileHandbookDetailModalService extends BaseModalService {
|
|
3599
4246
|
constructor(modalController: ModalController);
|
|
3600
4247
|
/**
|
|
3601
4248
|
* Open the handbook detail modal
|
|
@@ -3608,19 +4255,6 @@ declare class DsMobileHandbookDetailModalService {
|
|
|
3608
4255
|
loading?: boolean;
|
|
3609
4256
|
error?: string;
|
|
3610
4257
|
}): Promise<void>;
|
|
3611
|
-
/**
|
|
3612
|
-
* Close the currently open handbook detail modal
|
|
3613
|
-
*
|
|
3614
|
-
* @param data Optional data to pass back when dismissing
|
|
3615
|
-
* @returns Promise that resolves when the modal is dismissed
|
|
3616
|
-
*/
|
|
3617
|
-
close(data?: any): Promise<boolean>;
|
|
3618
|
-
/**
|
|
3619
|
-
* Get the top-most modal if one exists
|
|
3620
|
-
*
|
|
3621
|
-
* @returns Promise that resolves to the modal element or undefined
|
|
3622
|
-
*/
|
|
3623
|
-
getTop(): Promise<HTMLIonModalElement | undefined>;
|
|
3624
4258
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<DsMobileHandbookDetailModalService, never>;
|
|
3625
4259
|
static ɵprov: _angular_core.ɵɵInjectableDeclaration<DsMobileHandbookDetailModalService>;
|
|
3626
4260
|
}
|
|
@@ -3815,7 +4449,7 @@ declare class DsTextInputComponent implements ControlValueAccessor {
|
|
|
3815
4449
|
hasError: _angular_core.InputSignal<boolean>;
|
|
3816
4450
|
errorMessage: _angular_core.InputSignal<string>;
|
|
3817
4451
|
autocomplete: _angular_core.InputSignal<string>;
|
|
3818
|
-
inputmode: _angular_core.InputSignal<"search" | "text" | "
|
|
4452
|
+
inputmode: _angular_core.InputSignal<"search" | "text" | "url" | "numeric" | "email" | "tel" | undefined>;
|
|
3819
4453
|
autoClearError: _angular_core.InputSignal<boolean>;
|
|
3820
4454
|
validator: _angular_core.InputSignal<((value: string) => boolean) | null>;
|
|
3821
4455
|
valueChange: _angular_core.OutputEmitterRef<string>;
|
|
@@ -3842,6 +4476,68 @@ declare class DsTextInputComponent implements ControlValueAccessor {
|
|
|
3842
4476
|
static ɵcmp: _angular_core.ɵɵComponentDeclaration<DsTextInputComponent, "ds-text-input", never, { "type": { "alias": "type"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "readonly": { "alias": "readonly"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "hasError": { "alias": "hasError"; "required": false; "isSignal": true; }; "errorMessage": { "alias": "errorMessage"; "required": false; "isSignal": true; }; "autocomplete": { "alias": "autocomplete"; "required": false; "isSignal": true; }; "inputmode": { "alias": "inputmode"; "required": false; "isSignal": true; }; "autoClearError": { "alias": "autoClearError"; "required": false; "isSignal": true; }; "validator": { "alias": "validator"; "required": false; "isSignal": true; }; }, { "valueChange": "valueChange"; "blur": "blur"; "focus": "focus"; "errorCleared": "errorCleared"; }, never, never, true, never>;
|
|
3843
4477
|
}
|
|
3844
4478
|
|
|
4479
|
+
/**
|
|
4480
|
+
* DsMobileFabComponent
|
|
4481
|
+
*
|
|
4482
|
+
* Floating Action Button component for mobile interfaces.
|
|
4483
|
+
* A prominent circular button that floats above the content.
|
|
4484
|
+
*
|
|
4485
|
+
* Features:
|
|
4486
|
+
* - Configurable positioning (bottom-right, bottom-left, bottom-center)
|
|
4487
|
+
* - Uses design system theming variables
|
|
4488
|
+
* - Handles iOS safe areas
|
|
4489
|
+
* - Accessible with ARIA labels
|
|
4490
|
+
* - Smooth entrance animation
|
|
4491
|
+
*
|
|
4492
|
+
* @example
|
|
4493
|
+
* ```html
|
|
4494
|
+
* <ds-mobile-fab
|
|
4495
|
+
* icon="remixAddLine"
|
|
4496
|
+
* [position]="'bottom-right'"
|
|
4497
|
+
* (fabClick)="handleAddClick()"
|
|
4498
|
+
* ariaLabel="Add new inquiry">
|
|
4499
|
+
* </ds-mobile-fab>
|
|
4500
|
+
* ```
|
|
4501
|
+
*/
|
|
4502
|
+
declare class DsMobileFabComponent {
|
|
4503
|
+
/**
|
|
4504
|
+
* Icon name from the design system icon library
|
|
4505
|
+
* @default 'remixAddLine'
|
|
4506
|
+
*/
|
|
4507
|
+
icon: _angular_core.InputSignal<string>;
|
|
4508
|
+
/**
|
|
4509
|
+
* Position of the FAB on the screen
|
|
4510
|
+
* @default 'bottom-right'
|
|
4511
|
+
*/
|
|
4512
|
+
position: _angular_core.InputSignal<"bottom-right" | "bottom-left" | "bottom-center">;
|
|
4513
|
+
/**
|
|
4514
|
+
* Size of the FAB button
|
|
4515
|
+
* Note: FAB is always 56px circular, but this affects the icon size
|
|
4516
|
+
* @default 'md'
|
|
4517
|
+
*/
|
|
4518
|
+
size: _angular_core.InputSignal<"sm" | "md" | "lg">;
|
|
4519
|
+
/**
|
|
4520
|
+
* ARIA label for accessibility
|
|
4521
|
+
* @required - Always provide a descriptive label
|
|
4522
|
+
*/
|
|
4523
|
+
ariaLabel: _angular_core.InputSignal<string>;
|
|
4524
|
+
/**
|
|
4525
|
+
* Whether the FAB is disabled
|
|
4526
|
+
* @default false
|
|
4527
|
+
*/
|
|
4528
|
+
disabled: _angular_core.InputSignal<boolean>;
|
|
4529
|
+
/**
|
|
4530
|
+
* Emitted when the FAB is clicked
|
|
4531
|
+
*/
|
|
4532
|
+
fabClick: _angular_core.OutputEmitterRef<void>;
|
|
4533
|
+
/**
|
|
4534
|
+
* Handle button click
|
|
4535
|
+
*/
|
|
4536
|
+
handleClick(): void;
|
|
4537
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<DsMobileFabComponent, never>;
|
|
4538
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<DsMobileFabComponent, "ds-mobile-fab", never, { "icon": { "alias": "icon"; "required": false; "isSignal": true; }; "position": { "alias": "position"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": true; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; }, { "fabClick": "fabClick"; }, never, never, true, never>;
|
|
4539
|
+
}
|
|
4540
|
+
|
|
3845
4541
|
interface WhitelabelConfig {
|
|
3846
4542
|
logoUrl: string;
|
|
3847
4543
|
logoMarkUrl: string;
|
|
@@ -4004,6 +4700,105 @@ declare class UserService {
|
|
|
4004
4700
|
static ɵprov: _angular_core.ɵɵInjectableDeclaration<UserService>;
|
|
4005
4701
|
}
|
|
4006
4702
|
|
|
4703
|
+
/**
|
|
4704
|
+
* Post and Comment Models
|
|
4705
|
+
* Unified data structures for community posts
|
|
4706
|
+
*/
|
|
4707
|
+
interface Comment {
|
|
4708
|
+
authorName: string;
|
|
4709
|
+
authorRole: string;
|
|
4710
|
+
timestamp: string;
|
|
4711
|
+
avatarInitials: string;
|
|
4712
|
+
avatarSrc?: string;
|
|
4713
|
+
avatarType?: 'photo' | 'initials' | 'icon';
|
|
4714
|
+
content: string;
|
|
4715
|
+
likeCount: number;
|
|
4716
|
+
isLiked?: boolean;
|
|
4717
|
+
isOwnComment: boolean;
|
|
4718
|
+
}
|
|
4719
|
+
interface Post {
|
|
4720
|
+
id: string;
|
|
4721
|
+
authorName: string;
|
|
4722
|
+
authorRole: string;
|
|
4723
|
+
timestamp: string;
|
|
4724
|
+
avatarType: 'photo' | 'initials' | 'icon';
|
|
4725
|
+
avatarSrc?: string;
|
|
4726
|
+
avatarInitials?: string;
|
|
4727
|
+
avatarIconName?: string;
|
|
4728
|
+
content: string;
|
|
4729
|
+
imageSrc?: string;
|
|
4730
|
+
imageAlt?: string;
|
|
4731
|
+
isLiked: boolean;
|
|
4732
|
+
likeCount: number;
|
|
4733
|
+
commentCount: number;
|
|
4734
|
+
comments?: Comment[];
|
|
4735
|
+
isPinned?: boolean;
|
|
4736
|
+
showBadge?: boolean;
|
|
4737
|
+
hasInlinePhotos?: boolean;
|
|
4738
|
+
inlinePhotos?: string[];
|
|
4739
|
+
inlinePhotoCount?: number;
|
|
4740
|
+
}
|
|
4741
|
+
|
|
4742
|
+
/**
|
|
4743
|
+
* PostsService
|
|
4744
|
+
*
|
|
4745
|
+
* Centralized service for managing community posts.
|
|
4746
|
+
* Provides a single source of truth for post data, including comments.
|
|
4747
|
+
*
|
|
4748
|
+
* Features:
|
|
4749
|
+
* - CRUD operations for posts
|
|
4750
|
+
* - Infinite scroll pagination
|
|
4751
|
+
* - Post search/filter (future)
|
|
4752
|
+
* - Comment management (future)
|
|
4753
|
+
*/
|
|
4754
|
+
declare class PostsService {
|
|
4755
|
+
private postsState;
|
|
4756
|
+
posts: _angular_core.Signal<Post[]>;
|
|
4757
|
+
private currentPage;
|
|
4758
|
+
private hasMore;
|
|
4759
|
+
constructor();
|
|
4760
|
+
/**
|
|
4761
|
+
* Get a post by ID
|
|
4762
|
+
*/
|
|
4763
|
+
getPostById(id: string): Post | undefined;
|
|
4764
|
+
/**
|
|
4765
|
+
* Add a new post (e.g., from post creator)
|
|
4766
|
+
* Adds to the beginning of the list
|
|
4767
|
+
*/
|
|
4768
|
+
addPost(post: Post): void;
|
|
4769
|
+
/**
|
|
4770
|
+
* Update an existing post
|
|
4771
|
+
*/
|
|
4772
|
+
updatePost(id: string, updates: Partial<Post>): void;
|
|
4773
|
+
/**
|
|
4774
|
+
* Delete a post by ID
|
|
4775
|
+
*/
|
|
4776
|
+
deletePost(id: string): void;
|
|
4777
|
+
/**
|
|
4778
|
+
* Load more posts for infinite scroll
|
|
4779
|
+
* Returns true if more posts were loaded, false if no more posts
|
|
4780
|
+
*/
|
|
4781
|
+
loadMorePosts(): Promise<boolean>;
|
|
4782
|
+
/**
|
|
4783
|
+
* Check if there are more posts to load
|
|
4784
|
+
*/
|
|
4785
|
+
hasMorePosts(): boolean;
|
|
4786
|
+
/**
|
|
4787
|
+
* Reset pagination (e.g., on pull-to-refresh)
|
|
4788
|
+
*/
|
|
4789
|
+
resetPagination(): void;
|
|
4790
|
+
/**
|
|
4791
|
+
* Get initial posts (shown on page load)
|
|
4792
|
+
*/
|
|
4793
|
+
private getInitialPosts;
|
|
4794
|
+
/**
|
|
4795
|
+
* Get additional posts for infinite scroll
|
|
4796
|
+
*/
|
|
4797
|
+
private getAdditionalPosts;
|
|
4798
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<PostsService, never>;
|
|
4799
|
+
static ɵprov: _angular_core.ɵɵInjectableDeclaration<PostsService>;
|
|
4800
|
+
}
|
|
4801
|
+
|
|
4007
4802
|
declare class MobileCommunityPageComponent {
|
|
4008
4803
|
private router;
|
|
4009
4804
|
private route;
|
|
@@ -4011,23 +4806,22 @@ declare class MobileCommunityPageComponent {
|
|
|
4011
4806
|
private lightbox;
|
|
4012
4807
|
private postModal;
|
|
4013
4808
|
userService: UserService;
|
|
4014
|
-
|
|
4015
|
-
|
|
4809
|
+
private postsService;
|
|
4810
|
+
allPosts: _angular_core.Signal<Post[]>;
|
|
4016
4811
|
hasAnyPosts: _angular_core.Signal<boolean>;
|
|
4017
|
-
|
|
4812
|
+
hasMorePosts: _angular_core.Signal<boolean>;
|
|
4813
|
+
constructor(router: Router, route: ActivatedRoute, bottomSheet: DsMobileBottomSheetService, lightbox: DsMobileLightboxService, postModal: DsMobilePostDetailModalService, userService: UserService, postsService: PostsService);
|
|
4814
|
+
/**
|
|
4815
|
+
* Handle infinite scroll event
|
|
4816
|
+
* Loads more posts when user scrolls to bottom
|
|
4817
|
+
*/
|
|
4818
|
+
onInfiniteScroll(event: any): Promise<void>;
|
|
4018
4819
|
handleRefresh(event: any): void;
|
|
4019
4820
|
/**
|
|
4020
4821
|
* Open post detail modal
|
|
4021
|
-
*
|
|
4022
|
-
* - Maintains scroll position
|
|
4023
|
-
* - Native iOS-style modal feel
|
|
4024
|
-
* - Proper close button that works
|
|
4822
|
+
* Gets post data from service and opens modal
|
|
4025
4823
|
*/
|
|
4026
4824
|
openPost(postId: string, focusComment?: boolean): Promise<void>;
|
|
4027
|
-
/**
|
|
4028
|
-
* Open user-created post detail modal
|
|
4029
|
-
*/
|
|
4030
|
-
openUserPost(index: number, focusComment?: boolean): Promise<void>;
|
|
4031
4825
|
openPostCreator(): Promise<void>;
|
|
4032
4826
|
/**
|
|
4033
4827
|
* Open an image in the lightbox viewer
|
|
@@ -4038,7 +4832,7 @@ declare class MobileCommunityPageComponent {
|
|
|
4038
4832
|
/**
|
|
4039
4833
|
* Handle long press on a post to show action sheet
|
|
4040
4834
|
*/
|
|
4041
|
-
handlePostLongPress(
|
|
4835
|
+
handlePostLongPress(postId: string, isOwnPost: boolean): Promise<void>;
|
|
4042
4836
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<MobileCommunityPageComponent, never>;
|
|
4043
4837
|
static ɵcmp: _angular_core.ɵɵComponentDeclaration<MobileCommunityPageComponent, "app-mobile-community-page", never, {}, {}, never, never, true, never>;
|
|
4044
4838
|
}
|
|
@@ -4076,7 +4870,8 @@ interface Inquiry {
|
|
|
4076
4870
|
declare class MobileInquiriesPageComponent {
|
|
4077
4871
|
userService: UserService;
|
|
4078
4872
|
private navCtrl;
|
|
4079
|
-
|
|
4873
|
+
private newInquiryModal;
|
|
4874
|
+
constructor(userService: UserService, navCtrl: NavController, newInquiryModal: DsMobileNewInquiryModalService);
|
|
4080
4875
|
filterStatus: _angular_core.WritableSignal<"open" | "closed" | "all">;
|
|
4081
4876
|
tabItems: InlineTabItem[];
|
|
4082
4877
|
inquiries: _angular_core.WritableSignal<Inquiry[]>;
|
|
@@ -4087,22 +4882,11 @@ declare class MobileInquiriesPageComponent {
|
|
|
4087
4882
|
getInquiryIcon(category: string): string;
|
|
4088
4883
|
openInquiryDetail(inquiryId: string): void;
|
|
4089
4884
|
showInquiryActions(inquiryId: string): void;
|
|
4885
|
+
createNewInquiry(): Promise<void>;
|
|
4090
4886
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<MobileInquiriesPageComponent, never>;
|
|
4091
4887
|
static ɵcmp: _angular_core.ɵɵComponentDeclaration<MobileInquiriesPageComponent, "app-mobile-inquiries-page", never, {}, {}, never, never, true, never>;
|
|
4092
4888
|
}
|
|
4093
4889
|
|
|
4094
|
-
interface ActivityItem {
|
|
4095
|
-
id: string;
|
|
4096
|
-
type: 'assignment' | 'status_change' | 'creation';
|
|
4097
|
-
actor?: string;
|
|
4098
|
-
actorInitials?: string;
|
|
4099
|
-
title: string;
|
|
4100
|
-
description?: string;
|
|
4101
|
-
timestamp: string;
|
|
4102
|
-
date: string;
|
|
4103
|
-
iconName: string;
|
|
4104
|
-
iconBgColor?: string;
|
|
4105
|
-
}
|
|
4106
4890
|
interface MessageThread {
|
|
4107
4891
|
id: string;
|
|
4108
4892
|
senderName: string;
|
|
@@ -4113,28 +4897,28 @@ interface MessageThread {
|
|
|
4113
4897
|
timestamp: string;
|
|
4114
4898
|
unread: boolean;
|
|
4115
4899
|
}
|
|
4116
|
-
declare class MobileInquiryDetailPageComponent
|
|
4900
|
+
declare class MobileInquiryDetailPageComponent {
|
|
4117
4901
|
userService: UserService;
|
|
4118
|
-
private navCtrl;
|
|
4119
|
-
private elementRef;
|
|
4120
4902
|
private lightbox;
|
|
4121
4903
|
private chatModal;
|
|
4122
|
-
ionContent?: IonContent;
|
|
4123
|
-
private platform;
|
|
4124
|
-
isNativePlatform: _angular_core.Signal<boolean>;
|
|
4125
4904
|
inquiryTitle: string;
|
|
4126
4905
|
activeTab: _angular_core.WritableSignal<string>;
|
|
4127
4906
|
tabItems: InlineTabItem[];
|
|
4128
|
-
activities: ActivityItem[];
|
|
4129
4907
|
messageThreads: MessageThread[];
|
|
4130
4908
|
unreadMessagesCount: _angular_core.Signal<number>;
|
|
4131
4909
|
photos: LightboxImage[];
|
|
4132
|
-
constructor(userService: UserService,
|
|
4133
|
-
ngAfterViewInit(): void;
|
|
4910
|
+
constructor(userService: UserService, lightbox: DsMobileLightboxService, chatModal: DsMobileChatModalService);
|
|
4134
4911
|
setActiveTab(tabId: string): void;
|
|
4135
4912
|
goBack(): void;
|
|
4136
|
-
handleScroll(event: any): void;
|
|
4137
4913
|
handleRefresh(event: any): void;
|
|
4914
|
+
/**
|
|
4915
|
+
* Check if there are unread messages
|
|
4916
|
+
*/
|
|
4917
|
+
hasUnreadMessages(): boolean;
|
|
4918
|
+
/**
|
|
4919
|
+
* Navigate to messages tab when banner is clicked
|
|
4920
|
+
*/
|
|
4921
|
+
navigateToMessagesTab(): void;
|
|
4138
4922
|
openMessage(messageId: string): Promise<void>;
|
|
4139
4923
|
openPhotoLightbox(index: number): Promise<void>;
|
|
4140
4924
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<MobileInquiryDetailPageComponent, never>;
|
|
@@ -4222,6 +5006,23 @@ declare class MobilePostDetailPageComponent {
|
|
|
4222
5006
|
static ɵcmp: _angular_core.ɵɵComponentDeclaration<MobilePostDetailPageComponent, "app-mobile-post-detail-page", never, {}, {}, never, never, true, never>;
|
|
4223
5007
|
}
|
|
4224
5008
|
|
|
5009
|
+
/**
|
|
5010
|
+
* SignInPageComponent
|
|
5011
|
+
*
|
|
5012
|
+
* Sign-in page with email authentication.
|
|
5013
|
+
* Features logomark, decorative city background, and form validation.
|
|
5014
|
+
*/
|
|
5015
|
+
declare class SignInPageComponent {
|
|
5016
|
+
email: string;
|
|
5017
|
+
emailError: _angular_core.WritableSignal<boolean>;
|
|
5018
|
+
isSubmitting: _angular_core.WritableSignal<boolean>;
|
|
5019
|
+
emailSent: _angular_core.WritableSignal<boolean>;
|
|
5020
|
+
handleSubmit(): void;
|
|
5021
|
+
handleBackToLogin(): void;
|
|
5022
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<SignInPageComponent, never>;
|
|
5023
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<SignInPageComponent, "app-sign-in", never, {}, {}, never, never, true, never>;
|
|
5024
|
+
}
|
|
5025
|
+
|
|
4225
5026
|
/**
|
|
4226
5027
|
* Whitelabel Demo Page
|
|
4227
5028
|
*
|
|
@@ -4247,23 +5048,26 @@ declare class WhitelabelDemoPage implements OnInit {
|
|
|
4247
5048
|
}
|
|
4248
5049
|
|
|
4249
5050
|
/**
|
|
4250
|
-
* Custom page transition - iOS-style push/pop
|
|
5051
|
+
* Custom page transition - iOS-style push/pop with dark overlay
|
|
4251
5052
|
*
|
|
4252
5053
|
* FORWARD (navigating TO detail):
|
|
4253
5054
|
* - Entering page (detail): slides in from RIGHT, z-index 10 (on top)
|
|
4254
5055
|
* - Leaving page (list): slides LEFT slightly, z-index 9 (underneath)
|
|
5056
|
+
* - Dark overlay: fades in on leaving page (opacity 0 to 0.70)
|
|
4255
5057
|
*
|
|
4256
5058
|
* REVERSE (swipe back FROM detail):
|
|
4257
5059
|
* - Entering page (list): slides in from LEFT, z-index 9 (underneath)
|
|
4258
5060
|
* - Leaving page (detail): slides out to RIGHT, z-index 10 (on top)
|
|
5061
|
+
* - Dark overlay: fades out on entering page (main page underneath, opacity 0.70 to 0)
|
|
4259
5062
|
*/
|
|
4260
5063
|
declare const customPageTransition: (_: HTMLElement, opts: any) => Animation;
|
|
4261
5064
|
/**
|
|
4262
5065
|
* Custom back transition - iOS style where page slides out to reveal page underneath
|
|
4263
5066
|
* The entering page (inquiries) slides in from the LEFT underneath
|
|
4264
5067
|
* The leaving page (detail) slides out to the RIGHT on top
|
|
5068
|
+
* Dark overlay: fades out on entering page (main page underneath, opacity 0.70 to 0)
|
|
4265
5069
|
*/
|
|
4266
5070
|
declare const customBackTransition: (_: HTMLElement, opts: any) => Animation;
|
|
4267
5071
|
|
|
4268
|
-
export { ActionCommentComponent, ActionLikeComponent, ContentRowComponent, DsAvatarWithBadgeComponent, DsMobileActionsBottomSheetComponent, DsMobileBottomSheetService, DsMobileChatModalComponent, DsMobileChatModalService, DsMobileActionsBottomSheetComponent as DsMobileCommentActionsBottomSheetComponent, DsMobileCommentComponent, DsMobileContactListItemComponent, DsMobileContentComponent, DsMobileContentSectionComponent, DsMobileHandbookDetailModalComponent, DsMobileHandbookDetailModalService, DsMobileHandbookFolderComponent, DsMobileHandbookFolderMiniComponent, DsMobileHeaderContentComponent, DsMobileHeaderContentTileComponent, DsMobileInlinePhotoComponent, DsMobileInlineTabsComponent, DsMobileInteractiveListItemInquiryComponent, DsMobileInteractiveListItemMessageComponent, DsMobileInteractiveListItemPostComponent, DsMobileLightboxImageComponent as DsMobileLightboxComponent, DsMobileLightboxFooterComponent, DsMobileLightboxHeaderComponent, DsMobileLightboxImageComponent, DsMobileLightboxPdfComponent, DsMobileLightboxService, DsMobileListItemComponent, DsMobileListItemStaticComponent, DsMobileLongPressDirective, DsMobileMessageBubbleComponent, DsMobileMessageComposerComponent, DsMobileModalService, DsMobilePageDetailsComponent, DsMobilePageMainComponent, DsMobileActionsBottomSheetComponent as DsMobilePostActionsBottomSheetComponent, DsMobilePostComposerComponent, DsMobilePostCreateBottomSheetComponent, DsMobilePostDetailModalComponent, DsMobilePostDetailModalService, DsMobileTabBarComponent, DsMobileTabsComponent, DsTextInputComponent, MobileCommunityPageComponent, MobileHandbookPageComponent, MobileHomePageComponent, MobileInquiriesPageComponent, MobileInquiryDetailPageComponent, MobilePageBase, MobilePostDetailPageComponent, MobileTabsExampleComponent, PostActionsComponent, PostAttachmentsComponent, PostContentComponent, PostCreatePageComponent, PostMediaComponent, PostPdfAttachmentComponent, PostTextComponent, SectionHeaderComponent, TileContentComponent, TileIconComponent, TileLabelComponent, TileValueComponent, UserService, WhitelabelDemoPage, WhitelabelService, customBackTransition, customPageTransition };
|
|
4269
|
-
export type { ActionGroup, ActionItem, ActionResult, AttachmentItem, AvatarSize, AvatarType, BadgePosition, BottomSheetOptions, ChatAttachment, ChatMessage, ChatModalData, ChatParticipant, ActionResult as CommentActionResult, CommentData, ContactItem, ContentWidth, HandbookDetailData, HandbookItem, InlineTabItem, LightboxAuthor, LightboxImage, LightboxImageOptions, LightboxMediaFile, LightboxMediaType, LightboxOptions, LightboxPdf, LightboxPdfOptions, ModalOptions, ActionResult as PostActionResult, PostDetailData, TabConfig, WhitelabelConfig };
|
|
5072
|
+
export { ActionCommentComponent, ActionLikeComponent, ContentRowComponent, DsAvatarWithBadgeComponent, DsMobileActionsBottomSheetComponent, DsMobileAttachmentPreviewComponent, DsMobileBottomSheetService, DsMobileChatModalComponent, DsMobileChatModalService, DsMobileActionsBottomSheetComponent as DsMobileCommentActionsBottomSheetComponent, DsMobileCommentComponent, DsMobileContactListItemComponent, DsMobileContentComponent, DsMobileContentSectionComponent, DsMobileFabComponent, DsMobileHandbookDetailModalComponent, DsMobileHandbookDetailModalService, DsMobileHandbookFolderComponent, DsMobileHandbookFolderMiniComponent, DsMobileHeaderContentComponent, DsMobileHeaderContentTileComponent, DsMobileInlinePhotoComponent, DsMobileInlineTabsComponent, DsMobileInteractiveListItemInquiryComponent, DsMobileInteractiveListItemMessageComponent, DsMobileInteractiveListItemPostComponent, DsMobileLightboxImageComponent as DsMobileLightboxComponent, DsMobileLightboxFooterComponent, DsMobileLightboxHeaderComponent, DsMobileLightboxImageComponent, DsMobileLightboxPdfComponent, DsMobileLightboxService, DsMobileListItemComponent, DsMobileListItemStaticComponent, DsMobileLongPressDirective, DsMobileMessageBubbleComponent, DsMobileMessageComposerComponent, DsMobileModalBaseComponent, DsMobileModalService, DsMobileNewInquiryModalComponent, DsMobileNewInquiryModalService, DsMobilePageDetailsComponent, DsMobilePageMainComponent, DsMobileActionsBottomSheetComponent as DsMobilePostActionsBottomSheetComponent, DsMobilePostComposerComponent, DsMobilePostCreateBottomSheetComponent, DsMobilePostDetailModalComponent, DsMobilePostDetailModalService, DsMobileTabBarComponent, DsMobileTabsComponent, DsTextInputComponent, MobileCommunityPageComponent, MobileHandbookPageComponent, MobileHomePageComponent, MobileInquiriesPageComponent, MobileInquiryDetailPageComponent, MobileModalBase, MobilePageBase, MobilePostDetailPageComponent, MobileTabsExampleComponent, PostActionsComponent, PostAttachmentsComponent, PostContentComponent, PostCreatePageComponent, PostMediaComponent, PostPdfAttachmentComponent, PostTextComponent, SectionHeaderComponent, SignInPageComponent, TileContentComponent, TileIconComponent, TileLabelComponent, TileValueComponent, UserService, WhitelabelDemoPage, WhitelabelService, customBackTransition, customPageTransition };
|
|
5073
|
+
export type { ActionGroup, ActionItem, ActionResult, AttachmentData, AttachmentFileType, AttachmentItem, AvatarSize, AvatarType, BadgePosition, BottomSheetOptions, ChatAttachment, ChatMessage, ChatModalData, ChatParticipant, Comment, ActionResult as CommentActionResult, CommentData, ContactItem, ContentWidth, HandbookDetailData, HandbookItem, InlineTabItem, InquiryPhoto, LightboxAuthor, LightboxImage, LightboxImageOptions, LightboxMediaFile, LightboxMediaType, LightboxOptions, LightboxPdf, LightboxPdfOptions, ModalOptions, NewInquiryData, NewInquiryModalOptions, Post, ActionResult as PostActionResult, PostDetailData, TabConfig, WhitelabelConfig };
|