@propbinder/mobile-design 0.2.3 → 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 +5536 -3010
- package/fesm2022/propbinder-mobile-design.mjs.map +1 -1
- package/index.d.ts +1084 -279
- 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
|
/**
|
|
@@ -1311,7 +1497,7 @@ declare class DsMobileListItemComponent {
|
|
|
1311
1497
|
* - 'center' - Align to center
|
|
1312
1498
|
* - 'bottom' - Align to bottom
|
|
1313
1499
|
*/
|
|
1314
|
-
align: _angular_core.InputSignal<"
|
|
1500
|
+
align: _angular_core.InputSignal<"center" | "top" | "bottom">;
|
|
1315
1501
|
/**
|
|
1316
1502
|
* Whether the list item is interactive (clickable and long-pressable)
|
|
1317
1503
|
* When true, adds interactive background, cursor pointer, and touch handlers
|
|
@@ -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,8 +3694,8 @@ interface ChatModalData {
|
|
|
3253
3694
|
* }
|
|
3254
3695
|
* ```
|
|
3255
3696
|
*/
|
|
3256
|
-
declare class DsMobileChatModalComponent implements OnInit, AfterViewInit
|
|
3257
|
-
private
|
|
3697
|
+
declare class DsMobileChatModalComponent implements OnInit, AfterViewInit {
|
|
3698
|
+
private lightboxService;
|
|
3258
3699
|
chatData: ChatModalData;
|
|
3259
3700
|
/**
|
|
3260
3701
|
* Loading state - when true, shows loading indicator
|
|
@@ -3270,18 +3711,25 @@ declare class DsMobileChatModalComponent implements OnInit, AfterViewInit, OnDes
|
|
|
3270
3711
|
currentUserAvatarType: _angular_core.WritableSignal<"initials" | "photo" | "icon">;
|
|
3271
3712
|
currentUserAvatarSrc: _angular_core.WritableSignal<string>;
|
|
3272
3713
|
autoFocus: _angular_core.WritableSignal<boolean>;
|
|
3273
|
-
|
|
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);
|
|
3274
3727
|
ngOnInit(): void;
|
|
3275
3728
|
ngAfterViewInit(): void;
|
|
3276
|
-
ngOnDestroy(): void;
|
|
3277
3729
|
/**
|
|
3278
3730
|
* Scroll to bottom of messages
|
|
3279
3731
|
*/
|
|
3280
3732
|
private scrollToBottom;
|
|
3281
|
-
/**
|
|
3282
|
-
* Close the modal
|
|
3283
|
-
*/
|
|
3284
|
-
close(): void;
|
|
3285
3733
|
/**
|
|
3286
3734
|
* Handle message sent from composer
|
|
3287
3735
|
*/
|
|
@@ -3290,15 +3738,54 @@ declare class DsMobileChatModalComponent implements OnInit, AfterViewInit, OnDes
|
|
|
3290
3738
|
isReply?: boolean;
|
|
3291
3739
|
replyTo?: string;
|
|
3292
3740
|
isEdit?: boolean;
|
|
3741
|
+
attachments?: AttachmentData[];
|
|
3293
3742
|
}): void;
|
|
3294
3743
|
/**
|
|
3295
3744
|
* Handle attachment click
|
|
3296
3745
|
*/
|
|
3297
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>;
|
|
3298
3763
|
/**
|
|
3299
3764
|
* Handle message long press
|
|
3300
3765
|
*/
|
|
3301
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;
|
|
3302
3789
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<DsMobileChatModalComponent, never>;
|
|
3303
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>;
|
|
3304
3791
|
}
|
|
@@ -3358,8 +3845,7 @@ declare class DsMobileChatModalComponent implements OnInit, AfterViewInit, OnDes
|
|
|
3358
3845
|
* }
|
|
3359
3846
|
* ```
|
|
3360
3847
|
*/
|
|
3361
|
-
declare class DsMobileChatModalService {
|
|
3362
|
-
private modalController;
|
|
3848
|
+
declare class DsMobileChatModalService extends BaseModalService {
|
|
3363
3849
|
constructor(modalController: ModalController);
|
|
3364
3850
|
/**
|
|
3365
3851
|
* Open the chat modal
|
|
@@ -3372,21 +3858,190 @@ declare class DsMobileChatModalService {
|
|
|
3372
3858
|
loading?: boolean;
|
|
3373
3859
|
error?: string;
|
|
3374
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>;
|
|
3375
3914
|
/**
|
|
3376
|
-
*
|
|
3377
|
-
*
|
|
3378
|
-
* @param data Optional data to pass back when dismissing
|
|
3379
|
-
* @returns Promise that resolves when the modal is dismissed
|
|
3915
|
+
* Loading state for the modal
|
|
3380
3916
|
*/
|
|
3381
|
-
|
|
3917
|
+
loading: boolean;
|
|
3382
3918
|
/**
|
|
3383
|
-
*
|
|
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
|
|
3384
4038
|
*
|
|
3385
|
-
* @
|
|
4039
|
+
* @param options Modal options including onSubmit callback
|
|
4040
|
+
* @returns Promise that resolves when the modal is presented
|
|
3386
4041
|
*/
|
|
3387
|
-
|
|
3388
|
-
static ɵfac: _angular_core.ɵɵFactoryDeclaration<
|
|
3389
|
-
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>;
|
|
3390
4045
|
}
|
|
3391
4046
|
|
|
3392
4047
|
/**
|
|
@@ -3512,8 +4167,7 @@ interface ContactItem {
|
|
|
3512
4167
|
*
|
|
3513
4168
|
* This component is typically not used directly - use DsMobileHandbookDetailModalService instead.
|
|
3514
4169
|
*/
|
|
3515
|
-
declare class DsMobileHandbookDetailModalComponent {
|
|
3516
|
-
private modalController;
|
|
4170
|
+
declare class DsMobileHandbookDetailModalComponent implements OnInit {
|
|
3517
4171
|
handbookData: HandbookDetailData;
|
|
3518
4172
|
/**
|
|
3519
4173
|
* Loading state - when true, shows loading indicator
|
|
@@ -3524,7 +4178,6 @@ declare class DsMobileHandbookDetailModalComponent {
|
|
|
3524
4178
|
*/
|
|
3525
4179
|
error?: string;
|
|
3526
4180
|
handbook: _angular_core.WritableSignal<HandbookDetailData>;
|
|
3527
|
-
constructor(modalController: ModalController);
|
|
3528
4181
|
ngOnInit(): void;
|
|
3529
4182
|
/**
|
|
3530
4183
|
* Split handbook items to enforce content structure rules:
|
|
@@ -3539,10 +4192,6 @@ declare class DsMobileHandbookDetailModalComponent {
|
|
|
3539
4192
|
* Get all display items with enforced content structure rules applied
|
|
3540
4193
|
*/
|
|
3541
4194
|
getDisplayItems(): HandbookItem[];
|
|
3542
|
-
/**
|
|
3543
|
-
* Close the modal
|
|
3544
|
-
*/
|
|
3545
|
-
close(): void;
|
|
3546
4195
|
/**
|
|
3547
4196
|
* Handle contact click
|
|
3548
4197
|
*/
|
|
@@ -3593,8 +4242,7 @@ declare class DsMobileHandbookDetailModalComponent {
|
|
|
3593
4242
|
* }
|
|
3594
4243
|
* ```
|
|
3595
4244
|
*/
|
|
3596
|
-
declare class DsMobileHandbookDetailModalService {
|
|
3597
|
-
private modalController;
|
|
4245
|
+
declare class DsMobileHandbookDetailModalService extends BaseModalService {
|
|
3598
4246
|
constructor(modalController: ModalController);
|
|
3599
4247
|
/**
|
|
3600
4248
|
* Open the handbook detail modal
|
|
@@ -3607,19 +4255,6 @@ declare class DsMobileHandbookDetailModalService {
|
|
|
3607
4255
|
loading?: boolean;
|
|
3608
4256
|
error?: string;
|
|
3609
4257
|
}): Promise<void>;
|
|
3610
|
-
/**
|
|
3611
|
-
* Close the currently open handbook detail modal
|
|
3612
|
-
*
|
|
3613
|
-
* @param data Optional data to pass back when dismissing
|
|
3614
|
-
* @returns Promise that resolves when the modal is dismissed
|
|
3615
|
-
*/
|
|
3616
|
-
close(data?: any): Promise<boolean>;
|
|
3617
|
-
/**
|
|
3618
|
-
* Get the top-most modal if one exists
|
|
3619
|
-
*
|
|
3620
|
-
* @returns Promise that resolves to the modal element or undefined
|
|
3621
|
-
*/
|
|
3622
|
-
getTop(): Promise<HTMLIonModalElement | undefined>;
|
|
3623
4258
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<DsMobileHandbookDetailModalService, never>;
|
|
3624
4259
|
static ɵprov: _angular_core.ɵɵInjectableDeclaration<DsMobileHandbookDetailModalService>;
|
|
3625
4260
|
}
|
|
@@ -3841,6 +4476,68 @@ declare class DsTextInputComponent implements ControlValueAccessor {
|
|
|
3841
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>;
|
|
3842
4477
|
}
|
|
3843
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
|
+
|
|
3844
4541
|
interface WhitelabelConfig {
|
|
3845
4542
|
logoUrl: string;
|
|
3846
4543
|
logoMarkUrl: string;
|
|
@@ -4003,6 +4700,105 @@ declare class UserService {
|
|
|
4003
4700
|
static ɵprov: _angular_core.ɵɵInjectableDeclaration<UserService>;
|
|
4004
4701
|
}
|
|
4005
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
|
+
|
|
4006
4802
|
declare class MobileCommunityPageComponent {
|
|
4007
4803
|
private router;
|
|
4008
4804
|
private route;
|
|
@@ -4010,23 +4806,22 @@ declare class MobileCommunityPageComponent {
|
|
|
4010
4806
|
private lightbox;
|
|
4011
4807
|
private postModal;
|
|
4012
4808
|
userService: UserService;
|
|
4013
|
-
|
|
4014
|
-
|
|
4809
|
+
private postsService;
|
|
4810
|
+
allPosts: _angular_core.Signal<Post[]>;
|
|
4015
4811
|
hasAnyPosts: _angular_core.Signal<boolean>;
|
|
4016
|
-
|
|
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>;
|
|
4017
4819
|
handleRefresh(event: any): void;
|
|
4018
4820
|
/**
|
|
4019
4821
|
* Open post detail modal
|
|
4020
|
-
*
|
|
4021
|
-
* - Maintains scroll position
|
|
4022
|
-
* - Native iOS-style modal feel
|
|
4023
|
-
* - Proper close button that works
|
|
4822
|
+
* Gets post data from service and opens modal
|
|
4024
4823
|
*/
|
|
4025
4824
|
openPost(postId: string, focusComment?: boolean): Promise<void>;
|
|
4026
|
-
/**
|
|
4027
|
-
* Open user-created post detail modal
|
|
4028
|
-
*/
|
|
4029
|
-
openUserPost(index: number, focusComment?: boolean): Promise<void>;
|
|
4030
4825
|
openPostCreator(): Promise<void>;
|
|
4031
4826
|
/**
|
|
4032
4827
|
* Open an image in the lightbox viewer
|
|
@@ -4037,7 +4832,7 @@ declare class MobileCommunityPageComponent {
|
|
|
4037
4832
|
/**
|
|
4038
4833
|
* Handle long press on a post to show action sheet
|
|
4039
4834
|
*/
|
|
4040
|
-
handlePostLongPress(
|
|
4835
|
+
handlePostLongPress(postId: string, isOwnPost: boolean): Promise<void>;
|
|
4041
4836
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<MobileCommunityPageComponent, never>;
|
|
4042
4837
|
static ɵcmp: _angular_core.ɵɵComponentDeclaration<MobileCommunityPageComponent, "app-mobile-community-page", never, {}, {}, never, never, true, never>;
|
|
4043
4838
|
}
|
|
@@ -4075,7 +4870,8 @@ interface Inquiry {
|
|
|
4075
4870
|
declare class MobileInquiriesPageComponent {
|
|
4076
4871
|
userService: UserService;
|
|
4077
4872
|
private navCtrl;
|
|
4078
|
-
|
|
4873
|
+
private newInquiryModal;
|
|
4874
|
+
constructor(userService: UserService, navCtrl: NavController, newInquiryModal: DsMobileNewInquiryModalService);
|
|
4079
4875
|
filterStatus: _angular_core.WritableSignal<"open" | "closed" | "all">;
|
|
4080
4876
|
tabItems: InlineTabItem[];
|
|
4081
4877
|
inquiries: _angular_core.WritableSignal<Inquiry[]>;
|
|
@@ -4086,22 +4882,11 @@ declare class MobileInquiriesPageComponent {
|
|
|
4086
4882
|
getInquiryIcon(category: string): string;
|
|
4087
4883
|
openInquiryDetail(inquiryId: string): void;
|
|
4088
4884
|
showInquiryActions(inquiryId: string): void;
|
|
4885
|
+
createNewInquiry(): Promise<void>;
|
|
4089
4886
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<MobileInquiriesPageComponent, never>;
|
|
4090
4887
|
static ɵcmp: _angular_core.ɵɵComponentDeclaration<MobileInquiriesPageComponent, "app-mobile-inquiries-page", never, {}, {}, never, never, true, never>;
|
|
4091
4888
|
}
|
|
4092
4889
|
|
|
4093
|
-
interface ActivityItem {
|
|
4094
|
-
id: string;
|
|
4095
|
-
type: 'assignment' | 'status_change' | 'creation';
|
|
4096
|
-
actor?: string;
|
|
4097
|
-
actorInitials?: string;
|
|
4098
|
-
title: string;
|
|
4099
|
-
description?: string;
|
|
4100
|
-
timestamp: string;
|
|
4101
|
-
date: string;
|
|
4102
|
-
iconName: string;
|
|
4103
|
-
iconBgColor?: string;
|
|
4104
|
-
}
|
|
4105
4890
|
interface MessageThread {
|
|
4106
4891
|
id: string;
|
|
4107
4892
|
senderName: string;
|
|
@@ -4112,28 +4897,28 @@ interface MessageThread {
|
|
|
4112
4897
|
timestamp: string;
|
|
4113
4898
|
unread: boolean;
|
|
4114
4899
|
}
|
|
4115
|
-
declare class MobileInquiryDetailPageComponent
|
|
4900
|
+
declare class MobileInquiryDetailPageComponent {
|
|
4116
4901
|
userService: UserService;
|
|
4117
|
-
private navCtrl;
|
|
4118
|
-
private elementRef;
|
|
4119
4902
|
private lightbox;
|
|
4120
4903
|
private chatModal;
|
|
4121
|
-
ionContent?: IonContent;
|
|
4122
|
-
private platform;
|
|
4123
|
-
isNativePlatform: _angular_core.Signal<boolean>;
|
|
4124
4904
|
inquiryTitle: string;
|
|
4125
4905
|
activeTab: _angular_core.WritableSignal<string>;
|
|
4126
4906
|
tabItems: InlineTabItem[];
|
|
4127
|
-
activities: ActivityItem[];
|
|
4128
4907
|
messageThreads: MessageThread[];
|
|
4129
4908
|
unreadMessagesCount: _angular_core.Signal<number>;
|
|
4130
4909
|
photos: LightboxImage[];
|
|
4131
|
-
constructor(userService: UserService,
|
|
4132
|
-
ngAfterViewInit(): void;
|
|
4910
|
+
constructor(userService: UserService, lightbox: DsMobileLightboxService, chatModal: DsMobileChatModalService);
|
|
4133
4911
|
setActiveTab(tabId: string): void;
|
|
4134
4912
|
goBack(): void;
|
|
4135
|
-
handleScroll(event: any): void;
|
|
4136
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;
|
|
4137
4922
|
openMessage(messageId: string): Promise<void>;
|
|
4138
4923
|
openPhotoLightbox(index: number): Promise<void>;
|
|
4139
4924
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<MobileInquiryDetailPageComponent, never>;
|
|
@@ -4221,6 +5006,23 @@ declare class MobilePostDetailPageComponent {
|
|
|
4221
5006
|
static ɵcmp: _angular_core.ɵɵComponentDeclaration<MobilePostDetailPageComponent, "app-mobile-post-detail-page", never, {}, {}, never, never, true, never>;
|
|
4222
5007
|
}
|
|
4223
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
|
+
|
|
4224
5026
|
/**
|
|
4225
5027
|
* Whitelabel Demo Page
|
|
4226
5028
|
*
|
|
@@ -4246,23 +5048,26 @@ declare class WhitelabelDemoPage implements OnInit {
|
|
|
4246
5048
|
}
|
|
4247
5049
|
|
|
4248
5050
|
/**
|
|
4249
|
-
* Custom page transition - iOS-style push/pop
|
|
5051
|
+
* Custom page transition - iOS-style push/pop with dark overlay
|
|
4250
5052
|
*
|
|
4251
5053
|
* FORWARD (navigating TO detail):
|
|
4252
5054
|
* - Entering page (detail): slides in from RIGHT, z-index 10 (on top)
|
|
4253
5055
|
* - Leaving page (list): slides LEFT slightly, z-index 9 (underneath)
|
|
5056
|
+
* - Dark overlay: fades in on leaving page (opacity 0 to 0.70)
|
|
4254
5057
|
*
|
|
4255
5058
|
* REVERSE (swipe back FROM detail):
|
|
4256
5059
|
* - Entering page (list): slides in from LEFT, z-index 9 (underneath)
|
|
4257
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)
|
|
4258
5062
|
*/
|
|
4259
5063
|
declare const customPageTransition: (_: HTMLElement, opts: any) => Animation;
|
|
4260
5064
|
/**
|
|
4261
5065
|
* Custom back transition - iOS style where page slides out to reveal page underneath
|
|
4262
5066
|
* The entering page (inquiries) slides in from the LEFT underneath
|
|
4263
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)
|
|
4264
5069
|
*/
|
|
4265
5070
|
declare const customBackTransition: (_: HTMLElement, opts: any) => Animation;
|
|
4266
5071
|
|
|
4267
|
-
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 };
|
|
4268
|
-
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 };
|