@servicemind.tis/tis-image-and-file-upload-and-view 1.2.23 → 1.2.25
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/servicemind.tis-tis-image-and-file-upload-and-view.mjs +154 -96
- package/fesm2022/servicemind.tis-tis-image-and-file-upload-and-view.mjs.map +1 -1
- package/lib/interfaces/socket-adapter.interface.d.ts +8 -1
- package/lib/services/tis-remote-upload.service.d.ts +12 -3
- package/lib/tis-image-and-file-upload-and-view.module.d.ts +10 -9
- package/lib/tis-qr-code-dialog/tis-qr-code-dialog.component.d.ts +15 -9
- package/package.json +3 -2
|
@@ -23,6 +23,8 @@ import { HttpHeaders, HttpClientModule } from '@angular/common/http';
|
|
|
23
23
|
import * as i1$3 from '@angular/material/snack-bar';
|
|
24
24
|
import { MatSnackBarModule } from '@angular/material/snack-bar';
|
|
25
25
|
import { takeUntil, take, timeout } from 'rxjs/operators';
|
|
26
|
+
import * as i4$1 from 'angularx-qrcode';
|
|
27
|
+
import { QRCodeComponent } from 'angularx-qrcode';
|
|
26
28
|
import * as i10 from '@angular/cdk/drag-drop';
|
|
27
29
|
import { moveItemInArray, DragDropModule } from '@angular/cdk/drag-drop';
|
|
28
30
|
import * as i6 from '@angular/forms';
|
|
@@ -545,7 +547,9 @@ class TisRemoteUploadService {
|
|
|
545
547
|
// Step 1: Get link token from backend
|
|
546
548
|
const endpoint = this.config?.apiEndpoints?.generateMobileLinkToken
|
|
547
549
|
|| `${this.apiUrl}/ease-of-access/mobile-upload-link-token`;
|
|
548
|
-
const
|
|
550
|
+
const apiResponse = await this.callHttpApi(endpoint, { deviceId: this.deviceId, userId: this.userId });
|
|
551
|
+
// Unwrap the data from API response
|
|
552
|
+
const response = apiResponse.data || apiResponse;
|
|
549
553
|
const expirySeconds = this.config?.qrCode?.expirySeconds || DEFAULT_QR_EXPIRY;
|
|
550
554
|
const expiresAt = response.expiresAt || Date.now() + expirySeconds * 1000;
|
|
551
555
|
// Step 2: Build QR URL
|
|
@@ -592,22 +596,27 @@ class TisRemoteUploadService {
|
|
|
592
596
|
// Mobile Communication
|
|
593
597
|
// ===========================================================================
|
|
594
598
|
/**
|
|
595
|
-
* Send message to mobile device
|
|
599
|
+
* Send message to mobile device via channel
|
|
596
600
|
*/
|
|
597
601
|
sendToMobile(type, data) {
|
|
598
602
|
if (!this.socketAdapter?.sendViaSocket) {
|
|
599
603
|
console.warn(`[${TisRemoteUploadService.COMPONENT}] sendViaSocket not available`);
|
|
600
604
|
return;
|
|
601
605
|
}
|
|
602
|
-
|
|
603
|
-
action:
|
|
606
|
+
const message = {
|
|
607
|
+
action: 'send-to-channel',
|
|
604
608
|
data: {
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
+
channel: this.channelName,
|
|
610
|
+
payload: {
|
|
611
|
+
type,
|
|
612
|
+
...data,
|
|
613
|
+
desktopDeviceId: this.deviceId,
|
|
614
|
+
timestamp: Date.now()
|
|
615
|
+
}
|
|
609
616
|
}
|
|
610
|
-
}
|
|
617
|
+
};
|
|
618
|
+
console.log(`[${TisRemoteUploadService.COMPONENT}] Sending to mobile:`, message);
|
|
619
|
+
this.socketAdapter.sendViaSocket(message);
|
|
611
620
|
}
|
|
612
621
|
/**
|
|
613
622
|
* Accept mobile connection (send SUCCESS response)
|
|
@@ -639,18 +648,61 @@ class TisRemoteUploadService {
|
|
|
639
648
|
this.sendToMobile('connectionState', { state: 'SUCCESS' });
|
|
640
649
|
}
|
|
641
650
|
/**
|
|
642
|
-
* Disconnect from mobile device
|
|
651
|
+
* Disconnect from mobile device - call API and clear local state
|
|
643
652
|
*/
|
|
644
|
-
disconnect() {
|
|
653
|
+
async disconnect() {
|
|
645
654
|
console.log(`[${TisRemoteUploadService.COMPONENT}] Disconnecting from mobile...`);
|
|
646
|
-
|
|
647
|
-
|
|
655
|
+
const mobileDeviceId = this.mobileConnection$.value?.mobileDeviceId;
|
|
656
|
+
// Call disconnect API via socket
|
|
657
|
+
if (this.socketAdapter?.callApiViaSocket && mobileDeviceId) {
|
|
658
|
+
try {
|
|
659
|
+
const callApi = this.socketAdapter.callApiViaSocket.bind(this.socketAdapter);
|
|
660
|
+
const response = await new Promise((resolve, reject) => {
|
|
661
|
+
const timeout = setTimeout(() => reject(new Error('Disconnect API timeout')), 10000);
|
|
662
|
+
callApi('tis-image-mobile-uploader/disconnect-mobile-link', {
|
|
663
|
+
desktopDeviceId: this.deviceId,
|
|
664
|
+
mobileDeviceId: mobileDeviceId,
|
|
665
|
+
initiatedBy: 'desktop'
|
|
666
|
+
}).pipe(take(1)).subscribe({
|
|
667
|
+
next: (res) => {
|
|
668
|
+
clearTimeout(timeout);
|
|
669
|
+
resolve(res);
|
|
670
|
+
},
|
|
671
|
+
error: (err) => {
|
|
672
|
+
clearTimeout(timeout);
|
|
673
|
+
reject(err);
|
|
674
|
+
}
|
|
675
|
+
});
|
|
676
|
+
});
|
|
677
|
+
console.log(`[${TisRemoteUploadService.COMPONENT}] Disconnect API response:`, response);
|
|
678
|
+
}
|
|
679
|
+
catch (error) {
|
|
680
|
+
console.warn(`[${TisRemoteUploadService.COMPONENT}] Disconnect API call failed:`, error);
|
|
681
|
+
// Continue with local cleanup anyway
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
// Notify mobile via channel (backup notification)
|
|
685
|
+
this.sendToMobile('mobile-link-disconnected', {
|
|
686
|
+
desktopDeviceId: this.deviceId,
|
|
687
|
+
initiatedBy: 'desktop'
|
|
688
|
+
});
|
|
648
689
|
// Clear state
|
|
649
690
|
this.mobileConnection$.next(null);
|
|
650
691
|
this.connectionStatus$.next('disconnected');
|
|
651
692
|
this.pairingSession$.next(null);
|
|
652
693
|
this.clearMobileConnection();
|
|
653
694
|
}
|
|
695
|
+
/**
|
|
696
|
+
* Handle disconnect initiated from remote (mobile) side
|
|
697
|
+
*/
|
|
698
|
+
handleRemoteDisconnect(data) {
|
|
699
|
+
console.log(`[${TisRemoteUploadService.COMPONENT}] Mobile disconnected:`, data);
|
|
700
|
+
// Clear state without calling API (mobile already initiated)
|
|
701
|
+
this.mobileConnection$.next(null);
|
|
702
|
+
this.connectionStatus$.next('disconnected');
|
|
703
|
+
this.pairingSession$.next(null);
|
|
704
|
+
this.clearMobileConnection();
|
|
705
|
+
}
|
|
654
706
|
// ===========================================================================
|
|
655
707
|
// Channel Subscription & Message Handling
|
|
656
708
|
// ===========================================================================
|
|
@@ -680,18 +732,23 @@ class TisRemoteUploadService {
|
|
|
680
732
|
*/
|
|
681
733
|
handleChannelMessage(message) {
|
|
682
734
|
console.log(`[${TisRemoteUploadService.COMPONENT}] Received:`, message);
|
|
683
|
-
// Extract message type and data
|
|
684
|
-
const
|
|
685
|
-
const
|
|
735
|
+
// Extract message type and data - handle nested payload structure
|
|
736
|
+
const payload = message.payload || message.data || message;
|
|
737
|
+
const type = payload.type || message.type;
|
|
738
|
+
const data = payload;
|
|
686
739
|
switch (type) {
|
|
687
740
|
case 'connectionState':
|
|
688
741
|
this.handleConnectionState(data);
|
|
689
742
|
break;
|
|
743
|
+
case 'mobile-link-established':
|
|
744
|
+
this.handleMobileLinkEstablished(data);
|
|
745
|
+
break;
|
|
690
746
|
case 'image-uploaded':
|
|
691
747
|
case 'upload_complete':
|
|
692
748
|
this.handleUploadComplete(message);
|
|
693
749
|
break;
|
|
694
750
|
case 'disconnect':
|
|
751
|
+
case 'mobile-link-disconnected':
|
|
695
752
|
this.handleMobileDisconnect(data);
|
|
696
753
|
break;
|
|
697
754
|
default:
|
|
@@ -704,6 +761,50 @@ class TisRemoteUploadService {
|
|
|
704
761
|
}
|
|
705
762
|
}
|
|
706
763
|
}
|
|
764
|
+
/**
|
|
765
|
+
* Handle mobile-link-established message
|
|
766
|
+
* This is sent when mobile successfully connects via the backend
|
|
767
|
+
*/
|
|
768
|
+
handleMobileLinkEstablished(data) {
|
|
769
|
+
const mobileDeviceId = data.mobileDeviceId;
|
|
770
|
+
const mobileConnectionId = data.mobileConnectionId;
|
|
771
|
+
const userId = data.userId;
|
|
772
|
+
console.log(`[${TisRemoteUploadService.COMPONENT}] Mobile link established:`, {
|
|
773
|
+
mobileDeviceId,
|
|
774
|
+
mobileConnectionId,
|
|
775
|
+
userId
|
|
776
|
+
});
|
|
777
|
+
if (mobileDeviceId) {
|
|
778
|
+
// Save mobile connection
|
|
779
|
+
const connectionInfo = {
|
|
780
|
+
mobileDeviceId,
|
|
781
|
+
connectedAt: Date.now(),
|
|
782
|
+
lastActivity: Date.now()
|
|
783
|
+
};
|
|
784
|
+
this.mobileConnection$.next(connectionInfo);
|
|
785
|
+
this.saveMobileConnection(connectionInfo);
|
|
786
|
+
// Update status to connected
|
|
787
|
+
this.connectionStatus$.next('connected');
|
|
788
|
+
// Update session
|
|
789
|
+
const session = this.pairingSession$.value;
|
|
790
|
+
if (session) {
|
|
791
|
+
const updatedSession = {
|
|
792
|
+
...session,
|
|
793
|
+
mobileDeviceId,
|
|
794
|
+
status: 'connected',
|
|
795
|
+
lastActivity: Date.now()
|
|
796
|
+
};
|
|
797
|
+
this.pairingSession$.next(updatedSession);
|
|
798
|
+
}
|
|
799
|
+
// Send SUCCESS acknowledgment to mobile
|
|
800
|
+
this.sendToMobile('connectionState', {
|
|
801
|
+
state: 'SUCCESS',
|
|
802
|
+
desktopDeviceId: this.deviceId,
|
|
803
|
+
mobileConnectionId
|
|
804
|
+
});
|
|
805
|
+
console.log(`[${TisRemoteUploadService.COMPONENT}] Connection established with mobile device:`, mobileDeviceId);
|
|
806
|
+
}
|
|
807
|
+
}
|
|
707
808
|
/**
|
|
708
809
|
* Handle connection state messages from mobile
|
|
709
810
|
*/
|
|
@@ -845,7 +946,6 @@ class TisQrCodeDialogComponent {
|
|
|
845
946
|
dialogRef;
|
|
846
947
|
data;
|
|
847
948
|
remoteUploadService;
|
|
848
|
-
qrCanvas;
|
|
849
949
|
qrData = '';
|
|
850
950
|
expiresAt = 0;
|
|
851
951
|
remainingTime = '';
|
|
@@ -889,6 +989,10 @@ class TisQrCodeDialogComponent {
|
|
|
889
989
|
this.isConnected = true;
|
|
890
990
|
this.connectionStatus = 'connected';
|
|
891
991
|
this.isLoading = false;
|
|
992
|
+
// Send field info to mobile since already connected
|
|
993
|
+
if (this.data.fieldInfo) {
|
|
994
|
+
this.sendFieldInfoToMobile();
|
|
995
|
+
}
|
|
892
996
|
}
|
|
893
997
|
else {
|
|
894
998
|
// No existing connection, generate QR code
|
|
@@ -905,8 +1009,6 @@ class TisQrCodeDialogComponent {
|
|
|
905
1009
|
this.expiresAt = result.expiresAt;
|
|
906
1010
|
this.isLoading = false;
|
|
907
1011
|
this.startCountdown();
|
|
908
|
-
// Generate QR code after view is ready
|
|
909
|
-
setTimeout(() => this.renderQrCode(), 100);
|
|
910
1012
|
}
|
|
911
1013
|
catch (error) {
|
|
912
1014
|
this.isLoading = false;
|
|
@@ -919,7 +1021,12 @@ class TisQrCodeDialogComponent {
|
|
|
919
1021
|
.pipe(takeUntil(this.destroy$))
|
|
920
1022
|
.subscribe(status => {
|
|
921
1023
|
this.connectionStatus = status;
|
|
1024
|
+
const wasConnected = this.isConnected;
|
|
922
1025
|
this.isConnected = status === 'connected';
|
|
1026
|
+
// Send field info when first connected
|
|
1027
|
+
if (!wasConnected && this.isConnected && this.data.fieldInfo) {
|
|
1028
|
+
this.sendFieldInfoToMobile();
|
|
1029
|
+
}
|
|
923
1030
|
});
|
|
924
1031
|
// Mobile connection changes
|
|
925
1032
|
this.remoteUploadService.getMobileConnection()
|
|
@@ -943,6 +1050,15 @@ class TisQrCodeDialogComponent {
|
|
|
943
1050
|
console.error('[TisQrCodeDialog] Error:', error);
|
|
944
1051
|
});
|
|
945
1052
|
}
|
|
1053
|
+
/**
|
|
1054
|
+
* Send field configuration to mobile device
|
|
1055
|
+
*/
|
|
1056
|
+
sendFieldInfoToMobile() {
|
|
1057
|
+
if (!this.data.fieldInfo)
|
|
1058
|
+
return;
|
|
1059
|
+
console.log('[TisQrCodeDialog] Sending field info to mobile:', this.data.fieldInfo);
|
|
1060
|
+
this.remoteUploadService.sendToMobile('field-info', this.data.fieldInfo);
|
|
1061
|
+
}
|
|
946
1062
|
startCountdown() {
|
|
947
1063
|
if (this.countdownSubscription) {
|
|
948
1064
|
this.countdownSubscription.unsubscribe();
|
|
@@ -964,74 +1080,6 @@ class TisQrCodeDialogComponent {
|
|
|
964
1080
|
}
|
|
965
1081
|
});
|
|
966
1082
|
}
|
|
967
|
-
renderQrCode() {
|
|
968
|
-
if (!this.qrCanvas || !this.qrData)
|
|
969
|
-
return;
|
|
970
|
-
const canvas = this.qrCanvas.nativeElement;
|
|
971
|
-
const ctx = canvas.getContext('2d');
|
|
972
|
-
if (!ctx)
|
|
973
|
-
return;
|
|
974
|
-
const size = this.data.qrSize || 200;
|
|
975
|
-
canvas.width = size;
|
|
976
|
-
canvas.height = size;
|
|
977
|
-
this.generateQrCodeOnCanvas(ctx, this.qrData, size);
|
|
978
|
-
}
|
|
979
|
-
/**
|
|
980
|
-
* Simple QR code generator using canvas
|
|
981
|
-
* In production, you'd use a library like qrcode or qrcode-generator
|
|
982
|
-
*/
|
|
983
|
-
generateQrCodeOnCanvas(ctx, data, size) {
|
|
984
|
-
const moduleCount = 25;
|
|
985
|
-
const moduleSize = size / moduleCount;
|
|
986
|
-
ctx.fillStyle = '#ffffff';
|
|
987
|
-
ctx.fillRect(0, 0, size, size);
|
|
988
|
-
const pattern = this.generatePattern(data, moduleCount);
|
|
989
|
-
ctx.fillStyle = '#000000';
|
|
990
|
-
for (let row = 0; row < moduleCount; row++) {
|
|
991
|
-
for (let col = 0; col < moduleCount; col++) {
|
|
992
|
-
if (pattern[row][col]) {
|
|
993
|
-
ctx.fillRect(col * moduleSize, row * moduleSize, moduleSize, moduleSize);
|
|
994
|
-
}
|
|
995
|
-
}
|
|
996
|
-
}
|
|
997
|
-
this.drawFinderPattern(ctx, 0, 0, moduleSize);
|
|
998
|
-
this.drawFinderPattern(ctx, (moduleCount - 7) * moduleSize, 0, moduleSize);
|
|
999
|
-
this.drawFinderPattern(ctx, 0, (moduleCount - 7) * moduleSize, moduleSize);
|
|
1000
|
-
}
|
|
1001
|
-
generatePattern(data, size) {
|
|
1002
|
-
const pattern = [];
|
|
1003
|
-
let hash = 0;
|
|
1004
|
-
for (let i = 0; i < data.length; i++) {
|
|
1005
|
-
hash = ((hash << 5) - hash) + data.charCodeAt(i);
|
|
1006
|
-
hash = hash & hash;
|
|
1007
|
-
}
|
|
1008
|
-
const seed = Math.abs(hash);
|
|
1009
|
-
let current = seed;
|
|
1010
|
-
for (let row = 0; row < size; row++) {
|
|
1011
|
-
pattern[row] = [];
|
|
1012
|
-
for (let col = 0; col < size; col++) {
|
|
1013
|
-
if ((row < 8 && col < 8) ||
|
|
1014
|
-
(row < 8 && col >= size - 8) ||
|
|
1015
|
-
(row >= size - 8 && col < 8)) {
|
|
1016
|
-
pattern[row][col] = false;
|
|
1017
|
-
}
|
|
1018
|
-
else {
|
|
1019
|
-
current = (current * 1103515245 + 12345) & 0x7fffffff;
|
|
1020
|
-
pattern[row][col] = (current % 2) === 0;
|
|
1021
|
-
}
|
|
1022
|
-
}
|
|
1023
|
-
}
|
|
1024
|
-
return pattern;
|
|
1025
|
-
}
|
|
1026
|
-
drawFinderPattern(ctx, x, y, moduleSize) {
|
|
1027
|
-
const s = moduleSize;
|
|
1028
|
-
ctx.fillStyle = '#000000';
|
|
1029
|
-
ctx.fillRect(x, y, 7 * s, 7 * s);
|
|
1030
|
-
ctx.fillStyle = '#ffffff';
|
|
1031
|
-
ctx.fillRect(x + s, y + s, 5 * s, 5 * s);
|
|
1032
|
-
ctx.fillStyle = '#000000';
|
|
1033
|
-
ctx.fillRect(x + 2 * s, y + 2 * s, 3 * s, 3 * s);
|
|
1034
|
-
}
|
|
1035
1083
|
// ---------------------------------------------------------------------------
|
|
1036
1084
|
// Public Methods
|
|
1037
1085
|
// ---------------------------------------------------------------------------
|
|
@@ -1079,18 +1127,15 @@ class TisQrCodeDialogComponent {
|
|
|
1079
1127
|
});
|
|
1080
1128
|
}
|
|
1081
1129
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: TisQrCodeDialogComponent, deps: [{ token: i1$2.MatDialogRef }, { token: MAT_DIALOG_DATA }, { token: TisRemoteUploadService }], target: i0.ɵɵFactoryTarget.Component });
|
|
1082
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.6", type: TisQrCodeDialogComponent, isStandalone: false, selector: "tis-qr-code-dialog", viewQueries: [{ propertyName: "qrCanvas", first: true, predicate: ["qrCanvas"], descendants: true }], ngImport: i0, template: "<div class=\"qr-dialog-container\">\n <!-- Header -->\n <div class=\"qr-dialog-header\">\n <h2 class=\"qr-dialog-title\">{{ data.title || 'Upload from Mobile' }}</h2>\n <p class=\"qr-dialog-subtitle\">{{ data.subtitle || 'Scan this QR code with your mobile device to upload images' }}</p>\n <button mat-icon-button class=\"close-btn\" (click)=\"close()\">\n <mat-icon>close</mat-icon>\n </button>\n </div>\n\n <!-- Content -->\n <div class=\"qr-dialog-content\">\n <!-- Loading State -->\n <div *ngIf=\"isLoading\" class=\"loading-container\">\n <mat-spinner diameter=\"48\"></mat-spinner>\n <p>Generating QR Code...</p>\n </div>\n\n <!-- Error State -->\n <div *ngIf=\"errorMessage && !isLoading\" class=\"error-container\">\n <mat-icon class=\"error-icon\">error_outline</mat-icon>\n <p class=\"error-message\">{{ errorMessage }}</p>\n <button mat-raised-button color=\"primary\" (click)=\"refreshQrCode()\">\n Try Again\n </button>\n </div>\n\n <!-- Main Content -->\n <div *ngIf=\"!isLoading && !errorMessage\" class=\"qr-content\">\n \n <!-- Device Info Card -->\n <div class=\"device-info-card\">\n <div class=\"device-row\">\n <mat-icon class=\"device-icon desktop\">computer</mat-icon>\n <div class=\"device-details\">\n <span class=\"device-label\">This Device</span>\n <span class=\"device-id\">{{ formatDeviceId(desktopDeviceId) }}</span>\n </div>\n </div>\n \n <div class=\"connection-line\" *ngIf=\"mobileDeviceId\">\n <mat-icon>sync_alt</mat-icon>\n </div>\n \n <div class=\"device-row\" *ngIf=\"mobileDeviceId\">\n <mat-icon class=\"device-icon mobile\">smartphone</mat-icon>\n <div class=\"device-details\">\n <span class=\"device-label\">Connected Mobile</span>\n <span class=\"device-id\">{{ formatDeviceId(mobileDeviceId) }}</span>\n </div>\n </div>\n </div>\n\n <!-- Connected State -->\n <div *ngIf=\"isConnected\" class=\"connected-state\">\n <div class=\"connected-indicator\">\n <mat-icon class=\"success-icon\">check_circle</mat-icon>\n <span>Mobile Connected!</span>\n </div>\n <p class=\"connected-message\">\n You can now upload images from your mobile device. \n Select a file/image upload field and the uploaded files will appear automatically.\n </p>\n \n <!-- Uploaded Files -->\n <div class=\"uploaded-files\" *ngIf=\"uploadedFiles.length > 0\">\n <h4>Uploaded Files ({{ uploadedFiles.length }})</h4>\n <div class=\"file-list\">\n <div class=\"file-item\" *ngFor=\"let upload of uploadedFiles\">\n <mat-icon>check_circle</mat-icon>\n <span>{{ upload.file.fileName }}</span>\n </div>\n </div>\n </div>\n </div>\n\n <!-- QR Code (only show when not connected) -->\n <div *ngIf=\"!isConnected\" class=\"qr-section\">\n <!-- Connection Status -->\n <div class=\"connection-status\" [ngClass]=\"connectionStatus\">\n <div class=\"status-indicator\"></div>\n <span *ngIf=\"connectionStatus === 'disconnected'\">Waiting for mobile...</span>\n <span *ngIf=\"connectionStatus === 'pending'\">Waiting for connection...</span>\n </div>\n\n <!-- QR Code -->\n <div class=\"qr-code-wrapper\" [class.expired]=\"isExpired\">\n <canvas #qrCanvas class=\"qr-canvas\"></canvas>\n \n <!-- Expired Overlay -->\n <div *ngIf=\"isExpired\" class=\"expired-overlay\">\n <mat-icon>refresh</mat-icon>\n <p>QR Code Expired</p>\n <button mat-raised-button color=\"primary\" (click)=\"refreshQrCode()\">\n Generate New Code\n </button>\n </div>\n </div>\n\n <!-- Countdown Timer -->\n <div class=\"countdown\" *ngIf=\"data.showCountdown !== false && !isExpired\">\n <mat-icon>timer</mat-icon>\n <span>Expires in {{ remainingTime }}</span>\n </div>\n </div>\n\n </div>\n </div>\n\n <!-- Footer -->\n <div class=\"qr-dialog-footer\">\n <button mat-button *ngIf=\"isConnected\" color=\"warn\" (click)=\"disconnect()\">\n <mat-icon>link_off</mat-icon>\n Disconnect\n </button>\n <button mat-button *ngIf=\"!isConnected && !isLoading\" (click)=\"connectToMobile()\">\n <mat-icon>qr_code</mat-icon>\n Connect & Upload via Mobile\n </button>\n <button mat-raised-button color=\"primary\" (click)=\"close()\">\n {{ uploadedFiles.length > 0 ? 'Done' : 'Close' }}\n </button>\n </div>\n</div>\n", styles: [".qr-dialog-container{display:flex;flex-direction:column;min-width:360px;max-width:440px;background:#fff;border-radius:16px;overflow:hidden}.qr-dialog-header{position:relative;padding:24px 24px 16px;text-align:center;border-bottom:1px solid #f0f0f0}.qr-dialog-title{margin:0 0 8px;font-size:20px;font-weight:600;color:#1a1a1a}.qr-dialog-subtitle{margin:0;font-size:14px;color:#666;line-height:1.4}.close-btn{position:absolute;top:12px;right:12px;color:#999}.qr-dialog-content{padding:24px;display:flex;flex-direction:column;align-items:center;min-height:300px}.loading-container{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:16px;height:250px;color:#666}.error-container{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:16px;height:250px;text-align:center}.error-icon{font-size:48px;width:48px;height:48px;color:#f44336}.error-message{color:#666;margin:0}.qr-content{display:flex;flex-direction:column;align-items:center;gap:20px;width:100%}.device-info-section{width:100%;display:flex;align-items:center;justify-content:center;gap:12px;padding:16px;background:linear-gradient(135deg,#f8f9fa,#e9ecef);border-radius:12px;margin-bottom:8px}.device-card{display:flex;flex-direction:column;align-items:center;gap:6px;padding:12px 16px;background:#fff;border-radius:10px;min-width:120px;box-shadow:0 2px 8px #0000000f;transition:all .3s ease}.device-card.this-device{border:2px solid #2196f3}.device-card.connected-device{border:2px dashed #9e9e9e}.device-card.connected-device.active{border:2px solid #4caf50}.device-label{display:flex;align-items:center;gap:4px;font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.5px}.device-card.this-device .device-label{color:#2196f3}.device-card.connected-device .device-label{color:#9e9e9e}.device-card.connected-device.active .device-label{color:#4caf50}.device-label mat-icon{font-size:14px;width:14px;height:14px}.device-id{font-family:SF Mono,Monaco,Courier New,monospace;font-size:13px;font-weight:600;color:#333;letter-spacing:.5px}.device-id.waiting{color:#9e9e9e;font-style:italic;font-weight:400}.connection-line{display:flex;flex-direction:column;align-items:center;gap:4px;padding:0 8px}.connection-line .line{width:40px;height:2px;background:#e0e0e0;border-radius:1px;position:relative;overflow:hidden}.connection-line.waiting .line:after{content:\"\";position:absolute;top:0;left:-100%;width:50%;height:100%;background:linear-gradient(90deg,transparent,#2196f3,transparent);animation:shimmer 1.5s infinite}.connection-line.connected .line{background:#4caf50}.connection-line mat-icon{font-size:16px;width:16px;height:16px;color:#9e9e9e}.connection-line.waiting mat-icon{color:#ff9800;animation:blink 1s infinite}.connection-line.connected mat-icon{color:#4caf50}@keyframes shimmer{0%{left:-100%}to{left:200%}}@keyframes blink{0%,to{opacity:1}50%{opacity:.3}}.connection-status{display:flex;align-items:center;gap:8px;padding:8px 16px;border-radius:20px;font-size:13px;font-weight:500}.connection-status .status-indicator{width:8px;height:8px;border-radius:50%;animation:pulse 2s infinite}.connection-status.disconnected{background:#f5f5f5;color:#666}.connection-status.disconnected .status-indicator{background:#999}.connection-status.pending{background:#fff3e0;color:#e65100}.connection-status.pending .status-indicator{background:#ff9800}.connection-status.connected{background:#e8f5e9;color:#2e7d32}.connection-status.connected .status-indicator{background:#4caf50;animation:none}@keyframes pulse{0%,to{opacity:1;transform:scale(1)}50%{opacity:.5;transform:scale(1.2)}}.qr-code-wrapper{position:relative;padding:16px;background:#f8f9fa;border-radius:12px;border:2px solid #e0e0e0;transition:all .3s ease}.qr-code-wrapper.expired{opacity:.5}.qr-code-wrapper.connected{border-color:#4caf50;background:#f1f8f4}.qr-canvas{display:block;width:200px;height:200px}.expired-overlay,.connected-overlay{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;background:#fffffff2;border-radius:10px}.expired-overlay mat-icon{font-size:40px;width:40px;height:40px;color:#999}.expired-overlay p{margin:0;color:#666;font-weight:500}.connected-overlay .success-icon{font-size:56px;width:56px;height:56px;color:#4caf50}.connected-overlay p{margin:0;color:#2e7d32;font-size:16px;font-weight:600}.pairing-code-section{text-align:center}.pairing-label{margin:0 0 8px;font-size:13px;color:#666}.pairing-code{display:inline-flex;align-items:center;gap:8px;padding:10px 16px;background:#f5f5f5;border-radius:8px;cursor:pointer;transition:background .2s ease}.pairing-code:hover{background:#eee}.pairing-code .code{font-family:SF Mono,Monaco,Courier New,monospace;font-size:18px;font-weight:600;letter-spacing:2px;color:#1a1a1a}.pairing-code .copy-icon{font-size:18px;width:18px;height:18px;color:#666}.countdown{display:flex;align-items:center;gap:6px;font-size:13px;color:#666}.countdown mat-icon{font-size:18px;width:18px;height:18px}.uploaded-files{width:100%;margin-top:8px;padding-top:16px;border-top:1px solid #f0f0f0}.uploaded-files h4{margin:0 0 12px;font-size:14px;font-weight:600;color:#333}.file-list{display:flex;flex-direction:column;gap:8px;max-height:120px;overflow-y:auto}.file-item{display:flex;align-items:center;gap:8px;padding:8px 12px;background:#f1f8f4;border-radius:8px;font-size:13px;color:#333}.file-item mat-icon{font-size:18px;width:18px;height:18px;color:#4caf50}.file-item span{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.qr-dialog-footer{display:flex;justify-content:flex-end;gap:12px;padding:16px 24px;border-top:1px solid #f0f0f0;background:#fafafa}@media (max-width: 400px){.qr-dialog-container{min-width:100%;border-radius:0}.qr-canvas{width:180px;height:180px}.device-info-section{flex-direction:column;gap:8px}.connection-line{transform:rotate(90deg)}.device-card{min-width:100%}}\n"], dependencies: [{ kind: "directive", type: i2$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i3$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: i2.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "component", type: i4.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "component", type: i4.MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }] });
|
|
1130
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.6", type: TisQrCodeDialogComponent, isStandalone: false, selector: "tis-qr-code-dialog", ngImport: i0, template: "<div class=\"qr-dialog-container\">\n <!-- Header -->\n <div class=\"qr-dialog-header\">\n <h2 class=\"qr-dialog-title\">{{ data.title || 'Upload from Mobile' }}</h2>\n <p class=\"qr-dialog-subtitle\">{{ data.subtitle || 'Scan this QR code with your mobile device to upload images' }}</p>\n <button mat-icon-button class=\"close-btn\" (click)=\"close()\">\n <mat-icon>close</mat-icon>\n </button>\n </div>\n\n <!-- Content -->\n <div class=\"qr-dialog-content\">\n <!-- Loading State -->\n <div *ngIf=\"isLoading\" class=\"loading-container\">\n <mat-spinner diameter=\"48\"></mat-spinner>\n <p>Generating QR Code...</p>\n </div>\n\n <!-- Error State -->\n <div *ngIf=\"errorMessage && !isLoading\" class=\"error-container\">\n <mat-icon class=\"error-icon\">error_outline</mat-icon>\n <p class=\"error-message\">{{ errorMessage }}</p>\n <button mat-raised-button color=\"primary\" (click)=\"refreshQrCode()\">\n Try Again\n </button>\n </div>\n\n <!-- Main Content -->\n <div *ngIf=\"!isLoading && !errorMessage\" class=\"qr-content\">\n \n <!-- Device Info Card -->\n <div class=\"device-info-card\">\n <div class=\"device-row\">\n <mat-icon class=\"device-icon desktop\">computer</mat-icon>\n <div class=\"device-details\">\n <span class=\"device-label\">THIS DEVICE</span>\n <span class=\"device-id\" [title]=\"desktopDeviceId\">{{ formatDeviceId(desktopDeviceId) }}</span>\n </div>\n </div>\n \n <div class=\"connection-line\" *ngIf=\"mobileDeviceId\">\n <mat-icon>sync_alt</mat-icon>\n </div>\n \n <div class=\"device-row\" *ngIf=\"mobileDeviceId\">\n <mat-icon class=\"device-icon mobile\">smartphone</mat-icon>\n <div class=\"device-details\">\n <span class=\"device-label\">CONNECTED MOBILE</span>\n <span class=\"device-id\" [title]=\"mobileDeviceId\">{{ formatDeviceId(mobileDeviceId) }}</span>\n </div>\n </div>\n </div>\n\n <!-- Connected State -->\n <div *ngIf=\"isConnected\" class=\"connected-state\">\n <div class=\"connected-indicator\">\n <mat-icon class=\"success-icon\">check_circle</mat-icon>\n <span>Mobile Connected!</span>\n </div>\n <p class=\"connected-message\">\n You can now upload images from your mobile device. \n Select a file/image upload field and the uploaded files will appear automatically.\n </p>\n \n <!-- Uploaded Files -->\n <div class=\"uploaded-files\" *ngIf=\"uploadedFiles.length > 0\">\n <h4>Uploaded Files ({{ uploadedFiles.length }})</h4>\n <div class=\"file-list\">\n <div class=\"file-item\" *ngFor=\"let upload of uploadedFiles\">\n <mat-icon>check_circle</mat-icon>\n <span>{{ upload.file.fileName }}</span>\n </div>\n </div>\n </div>\n </div>\n\n <!-- QR Code (only show when not connected) -->\n <div *ngIf=\"!isConnected\" class=\"qr-section\">\n <!-- Connection Status -->\n <div class=\"connection-status\" [ngClass]=\"connectionStatus\">\n <div class=\"status-indicator\"></div>\n <span *ngIf=\"connectionStatus === 'disconnected'\">Waiting for mobile...</span>\n <span *ngIf=\"connectionStatus === 'pending'\">Waiting for connection...</span>\n </div>\n\n <!-- QR Code -->\n <div class=\"qr-code-wrapper\" [class.expired]=\"isExpired\">\n <qrcode \n *ngIf=\"qrData\"\n [qrdata]=\"qrData\" \n [width]=\"data.qrSize || 200\" \n [errorCorrectionLevel]=\"'M'\"\n [elementType]=\"'canvas'\"\n [cssClass]=\"'qr-canvas'\"\n ></qrcode>\n \n <!-- Expired Overlay -->\n <div *ngIf=\"isExpired\" class=\"expired-overlay\">\n <mat-icon>refresh</mat-icon>\n <p>QR Code Expired</p>\n <button mat-raised-button color=\"primary\" (click)=\"refreshQrCode()\">\n Generate New Code\n </button>\n </div>\n </div>\n\n <!-- Countdown Timer -->\n <div class=\"countdown\" *ngIf=\"data.showCountdown !== false && !isExpired\">\n <mat-icon>timer</mat-icon>\n <span>Expires in {{ remainingTime }}</span>\n </div>\n </div>\n\n </div>\n </div>\n\n <!-- Footer -->\n <div class=\"qr-dialog-footer\">\n <button mat-button *ngIf=\"isConnected\" color=\"warn\" (click)=\"disconnect()\">\n <mat-icon>link_off</mat-icon>\n Disconnect\n </button>\n <button mat-button *ngIf=\"!isConnected && !isLoading\" (click)=\"connectToMobile()\">\n <mat-icon>qr_code</mat-icon>\n Connect & Upload via Mobile\n </button>\n <button mat-raised-button color=\"primary\" (click)=\"close()\">\n {{ uploadedFiles.length > 0 ? 'Done' : 'Close' }}\n </button>\n </div>\n</div>\n", styles: [".qr-dialog-container{display:flex;flex-direction:column;min-width:360px;max-width:440px;background:#fff;border-radius:16px;overflow:hidden}.qr-dialog-header{position:relative;padding:24px 24px 16px;text-align:center;border-bottom:1px solid #f0f0f0}.qr-dialog-title{margin:0 0 8px;font-size:20px;font-weight:600;color:#1a1a1a}.qr-dialog-subtitle{margin:0;font-size:14px;color:#666;line-height:1.4}.close-btn{position:absolute;top:12px;right:12px;color:#999}.qr-dialog-content{padding:24px;display:flex;flex-direction:column;align-items:center;min-height:300px}.loading-container{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:16px;height:250px;color:#666}.error-container{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:16px;height:250px;text-align:center}.error-icon{font-size:48px;width:48px;height:48px;color:#f44336}.error-message{color:#666;margin:0}.qr-content{display:flex;flex-direction:column;align-items:center;gap:20px;width:100%}.device-info-section{width:100%;display:flex;align-items:center;justify-content:center;gap:12px;padding:16px;background:linear-gradient(135deg,#f8f9fa,#e9ecef);border-radius:12px;margin-bottom:8px}.device-card{display:flex;flex-direction:column;align-items:center;gap:6px;padding:12px 16px;background:#fff;border-radius:10px;min-width:120px;box-shadow:0 2px 8px #0000000f;transition:all .3s ease}.device-card.this-device{border:2px solid #2196f3}.device-card.connected-device{border:2px dashed #9e9e9e}.device-card.connected-device.active{border:2px solid #4caf50}.device-label{display:flex;align-items:center;gap:4px;font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.5px}.device-card.this-device .device-label{color:#2196f3}.device-card.connected-device .device-label{color:#9e9e9e}.device-card.connected-device.active .device-label{color:#4caf50}.device-label mat-icon{font-size:14px;width:14px;height:14px}.device-id{font-family:SF Mono,Monaco,Courier New,monospace;font-size:13px;font-weight:600;color:#333;letter-spacing:.5px}.device-id.waiting{color:#9e9e9e;font-style:italic;font-weight:400}.connection-line{display:flex;flex-direction:column;align-items:center;gap:4px;padding:0 8px}.connection-line .line{width:40px;height:2px;background:#e0e0e0;border-radius:1px;position:relative;overflow:hidden}.connection-line.waiting .line:after{content:\"\";position:absolute;top:0;left:-100%;width:50%;height:100%;background:linear-gradient(90deg,transparent,#2196f3,transparent);animation:shimmer 1.5s infinite}.connection-line.connected .line{background:#4caf50}.connection-line mat-icon{font-size:16px;width:16px;height:16px;color:#9e9e9e}.connection-line.waiting mat-icon{color:#ff9800;animation:blink 1s infinite}.connection-line.connected mat-icon{color:#4caf50}@keyframes shimmer{0%{left:-100%}to{left:200%}}@keyframes blink{0%,to{opacity:1}50%{opacity:.3}}.connection-status{display:flex;align-items:center;gap:8px;padding:8px 16px;border-radius:20px;font-size:13px;font-weight:500}.connection-status .status-indicator{width:8px;height:8px;border-radius:50%;animation:pulse 2s infinite}.connection-status.disconnected{background:#f5f5f5;color:#666}.connection-status.disconnected .status-indicator{background:#999}.connection-status.pending{background:#fff3e0;color:#e65100}.connection-status.pending .status-indicator{background:#ff9800}.connection-status.connected{background:#e8f5e9;color:#2e7d32}.connection-status.connected .status-indicator{background:#4caf50;animation:none}@keyframes pulse{0%,to{opacity:1;transform:scale(1)}50%{opacity:.5;transform:scale(1.2)}}.qr-code-wrapper{position:relative;padding:16px;background:#f8f9fa;border-radius:12px;border:2px solid #e0e0e0;transition:all .3s ease}.qr-code-wrapper.expired{opacity:.5}.qr-code-wrapper.connected{border-color:#4caf50;background:#f1f8f4}.qr-canvas{display:block;width:200px;height:200px}.expired-overlay,.connected-overlay{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;background:#fffffff2;border-radius:10px}.expired-overlay mat-icon{font-size:40px;width:40px;height:40px;color:#999}.expired-overlay p{margin:0;color:#666;font-weight:500}.connected-overlay .success-icon{font-size:56px;width:56px;height:56px;color:#4caf50}.connected-overlay p{margin:0;color:#2e7d32;font-size:16px;font-weight:600}.pairing-code-section{text-align:center}.pairing-label{margin:0 0 8px;font-size:13px;color:#666}.pairing-code{display:inline-flex;align-items:center;gap:8px;padding:10px 16px;background:#f5f5f5;border-radius:8px;cursor:pointer;transition:background .2s ease}.pairing-code:hover{background:#eee}.pairing-code .code{font-family:SF Mono,Monaco,Courier New,monospace;font-size:18px;font-weight:600;letter-spacing:2px;color:#1a1a1a}.pairing-code .copy-icon{font-size:18px;width:18px;height:18px;color:#666}.countdown{display:flex;align-items:center;gap:6px;font-size:13px;color:#666}.countdown mat-icon{font-size:18px;width:18px;height:18px}.uploaded-files{width:100%;margin-top:8px;padding-top:16px;border-top:1px solid #f0f0f0}.uploaded-files h4{margin:0 0 12px;font-size:14px;font-weight:600;color:#333}.file-list{display:flex;flex-direction:column;gap:8px;max-height:120px;overflow-y:auto}.file-item{display:flex;align-items:center;gap:8px;padding:8px 12px;background:#f1f8f4;border-radius:8px;font-size:13px;color:#333}.file-item mat-icon{font-size:18px;width:18px;height:18px;color:#4caf50}.file-item span{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.qr-dialog-footer{display:flex;justify-content:flex-end;gap:12px;padding:16px 24px;border-top:1px solid #f0f0f0;background:#fafafa}.device-info-card{width:100%;display:flex;flex-direction:row;align-items:center;justify-content:center;gap:12px;padding:12px 16px;background:linear-gradient(135deg,#f8f9fa,#e9ecef);border-radius:12px;margin-bottom:8px}.device-info-card .device-row{display:flex;align-items:center;gap:10px;flex:0 0 auto}.device-info-card .device-icon{font-size:24px;width:24px;height:24px}.device-info-card .device-icon.desktop{color:#1976d2}.device-info-card .device-icon.mobile{color:#7b1fa2}.device-info-card .device-details{display:flex;flex-direction:column;gap:2px}.device-info-card .device-label{font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.5px;color:#666}.device-info-card .device-id{font-family:SF Mono,Monaco,Courier New,monospace;font-size:12px;font-weight:500;color:#333;cursor:default}.device-info-card .connection-line{display:flex;align-items:center;padding:0 4px}.device-info-card .connection-line mat-icon{font-size:18px;width:18px;height:18px;color:#4caf50}@media (max-width: 400px){.qr-dialog-container{min-width:100%;border-radius:0}.qr-canvas{width:180px;height:180px}.device-info-section,.device-info-card{flex-direction:column;gap:8px}.device-info-card .connection-line,.connection-line{transform:rotate(90deg)}.device-card{min-width:100%}}\n"], dependencies: [{ kind: "directive", type: i2$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i4$1.QRCodeComponent, selector: "qrcode", inputs: ["allowEmptyString", "colorDark", "colorLight", "cssClass", "elementType", "errorCorrectionLevel", "imageSrc", "imageHeight", "imageWidth", "margin", "qrdata", "scale", "version", "width", "alt", "ariaLabel", "title"], outputs: ["qrCodeURL"] }, { kind: "component", type: i3$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: i2.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "component", type: i4.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "component", type: i4.MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }] });
|
|
1083
1131
|
}
|
|
1084
1132
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: TisQrCodeDialogComponent, decorators: [{
|
|
1085
1133
|
type: Component,
|
|
1086
|
-
args: [{ selector: 'tis-qr-code-dialog', standalone: false, template: "<div class=\"qr-dialog-container\">\n <!-- Header -->\n <div class=\"qr-dialog-header\">\n <h2 class=\"qr-dialog-title\">{{ data.title || 'Upload from Mobile' }}</h2>\n <p class=\"qr-dialog-subtitle\">{{ data.subtitle || 'Scan this QR code with your mobile device to upload images' }}</p>\n <button mat-icon-button class=\"close-btn\" (click)=\"close()\">\n <mat-icon>close</mat-icon>\n </button>\n </div>\n\n <!-- Content -->\n <div class=\"qr-dialog-content\">\n <!-- Loading State -->\n <div *ngIf=\"isLoading\" class=\"loading-container\">\n <mat-spinner diameter=\"48\"></mat-spinner>\n <p>Generating QR Code...</p>\n </div>\n\n <!-- Error State -->\n <div *ngIf=\"errorMessage && !isLoading\" class=\"error-container\">\n <mat-icon class=\"error-icon\">error_outline</mat-icon>\n <p class=\"error-message\">{{ errorMessage }}</p>\n <button mat-raised-button color=\"primary\" (click)=\"refreshQrCode()\">\n Try Again\n </button>\n </div>\n\n <!-- Main Content -->\n <div *ngIf=\"!isLoading && !errorMessage\" class=\"qr-content\">\n \n <!-- Device Info Card -->\n <div class=\"device-info-card\">\n <div class=\"device-row\">\n <mat-icon class=\"device-icon desktop\">computer</mat-icon>\n <div class=\"device-details\">\n <span class=\"device-label\">This Device</span>\n <span class=\"device-id\">{{ formatDeviceId(desktopDeviceId) }}</span>\n </div>\n </div>\n \n <div class=\"connection-line\" *ngIf=\"mobileDeviceId\">\n <mat-icon>sync_alt</mat-icon>\n </div>\n \n <div class=\"device-row\" *ngIf=\"mobileDeviceId\">\n <mat-icon class=\"device-icon mobile\">smartphone</mat-icon>\n <div class=\"device-details\">\n <span class=\"device-label\">Connected Mobile</span>\n <span class=\"device-id\">{{ formatDeviceId(mobileDeviceId) }}</span>\n </div>\n </div>\n </div>\n\n <!-- Connected State -->\n <div *ngIf=\"isConnected\" class=\"connected-state\">\n <div class=\"connected-indicator\">\n <mat-icon class=\"success-icon\">check_circle</mat-icon>\n <span>Mobile Connected!</span>\n </div>\n <p class=\"connected-message\">\n You can now upload images from your mobile device. \n Select a file/image upload field and the uploaded files will appear automatically.\n </p>\n \n <!-- Uploaded Files -->\n <div class=\"uploaded-files\" *ngIf=\"uploadedFiles.length > 0\">\n <h4>Uploaded Files ({{ uploadedFiles.length }})</h4>\n <div class=\"file-list\">\n <div class=\"file-item\" *ngFor=\"let upload of uploadedFiles\">\n <mat-icon>check_circle</mat-icon>\n <span>{{ upload.file.fileName }}</span>\n </div>\n </div>\n </div>\n </div>\n\n <!-- QR Code (only show when not connected) -->\n <div *ngIf=\"!isConnected\" class=\"qr-section\">\n <!-- Connection Status -->\n <div class=\"connection-status\" [ngClass]=\"connectionStatus\">\n <div class=\"status-indicator\"></div>\n <span *ngIf=\"connectionStatus === 'disconnected'\">Waiting for mobile...</span>\n <span *ngIf=\"connectionStatus === 'pending'\">Waiting for connection...</span>\n </div>\n\n <!-- QR Code -->\n <div class=\"qr-code-wrapper\" [class.expired]=\"isExpired\">\n <canvas #qrCanvas class=\"qr-canvas\"></canvas>\n \n <!-- Expired Overlay -->\n <div *ngIf=\"isExpired\" class=\"expired-overlay\">\n <mat-icon>refresh</mat-icon>\n <p>QR Code Expired</p>\n <button mat-raised-button color=\"primary\" (click)=\"refreshQrCode()\">\n Generate New Code\n </button>\n </div>\n </div>\n\n <!-- Countdown Timer -->\n <div class=\"countdown\" *ngIf=\"data.showCountdown !== false && !isExpired\">\n <mat-icon>timer</mat-icon>\n <span>Expires in {{ remainingTime }}</span>\n </div>\n </div>\n\n </div>\n </div>\n\n <!-- Footer -->\n <div class=\"qr-dialog-footer\">\n <button mat-button *ngIf=\"isConnected\" color=\"warn\" (click)=\"disconnect()\">\n <mat-icon>link_off</mat-icon>\n Disconnect\n </button>\n <button mat-button *ngIf=\"!isConnected && !isLoading\" (click)=\"connectToMobile()\">\n <mat-icon>qr_code</mat-icon>\n Connect & Upload via Mobile\n </button>\n <button mat-raised-button color=\"primary\" (click)=\"close()\">\n {{ uploadedFiles.length > 0 ? 'Done' : 'Close' }}\n </button>\n </div>\n</div>\n", styles: [".qr-dialog-container{display:flex;flex-direction:column;min-width:360px;max-width:440px;background:#fff;border-radius:16px;overflow:hidden}.qr-dialog-header{position:relative;padding:24px 24px 16px;text-align:center;border-bottom:1px solid #f0f0f0}.qr-dialog-title{margin:0 0 8px;font-size:20px;font-weight:600;color:#1a1a1a}.qr-dialog-subtitle{margin:0;font-size:14px;color:#666;line-height:1.4}.close-btn{position:absolute;top:12px;right:12px;color:#999}.qr-dialog-content{padding:24px;display:flex;flex-direction:column;align-items:center;min-height:300px}.loading-container{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:16px;height:250px;color:#666}.error-container{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:16px;height:250px;text-align:center}.error-icon{font-size:48px;width:48px;height:48px;color:#f44336}.error-message{color:#666;margin:0}.qr-content{display:flex;flex-direction:column;align-items:center;gap:20px;width:100%}.device-info-section{width:100%;display:flex;align-items:center;justify-content:center;gap:12px;padding:16px;background:linear-gradient(135deg,#f8f9fa,#e9ecef);border-radius:12px;margin-bottom:8px}.device-card{display:flex;flex-direction:column;align-items:center;gap:6px;padding:12px 16px;background:#fff;border-radius:10px;min-width:120px;box-shadow:0 2px 8px #0000000f;transition:all .3s ease}.device-card.this-device{border:2px solid #2196f3}.device-card.connected-device{border:2px dashed #9e9e9e}.device-card.connected-device.active{border:2px solid #4caf50}.device-label{display:flex;align-items:center;gap:4px;font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.5px}.device-card.this-device .device-label{color:#2196f3}.device-card.connected-device .device-label{color:#9e9e9e}.device-card.connected-device.active .device-label{color:#4caf50}.device-label mat-icon{font-size:14px;width:14px;height:14px}.device-id{font-family:SF Mono,Monaco,Courier New,monospace;font-size:13px;font-weight:600;color:#333;letter-spacing:.5px}.device-id.waiting{color:#9e9e9e;font-style:italic;font-weight:400}.connection-line{display:flex;flex-direction:column;align-items:center;gap:4px;padding:0 8px}.connection-line .line{width:40px;height:2px;background:#e0e0e0;border-radius:1px;position:relative;overflow:hidden}.connection-line.waiting .line:after{content:\"\";position:absolute;top:0;left:-100%;width:50%;height:100%;background:linear-gradient(90deg,transparent,#2196f3,transparent);animation:shimmer 1.5s infinite}.connection-line.connected .line{background:#4caf50}.connection-line mat-icon{font-size:16px;width:16px;height:16px;color:#9e9e9e}.connection-line.waiting mat-icon{color:#ff9800;animation:blink 1s infinite}.connection-line.connected mat-icon{color:#4caf50}@keyframes shimmer{0%{left:-100%}to{left:200%}}@keyframes blink{0%,to{opacity:1}50%{opacity:.3}}.connection-status{display:flex;align-items:center;gap:8px;padding:8px 16px;border-radius:20px;font-size:13px;font-weight:500}.connection-status .status-indicator{width:8px;height:8px;border-radius:50%;animation:pulse 2s infinite}.connection-status.disconnected{background:#f5f5f5;color:#666}.connection-status.disconnected .status-indicator{background:#999}.connection-status.pending{background:#fff3e0;color:#e65100}.connection-status.pending .status-indicator{background:#ff9800}.connection-status.connected{background:#e8f5e9;color:#2e7d32}.connection-status.connected .status-indicator{background:#4caf50;animation:none}@keyframes pulse{0%,to{opacity:1;transform:scale(1)}50%{opacity:.5;transform:scale(1.2)}}.qr-code-wrapper{position:relative;padding:16px;background:#f8f9fa;border-radius:12px;border:2px solid #e0e0e0;transition:all .3s ease}.qr-code-wrapper.expired{opacity:.5}.qr-code-wrapper.connected{border-color:#4caf50;background:#f1f8f4}.qr-canvas{display:block;width:200px;height:200px}.expired-overlay,.connected-overlay{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;background:#fffffff2;border-radius:10px}.expired-overlay mat-icon{font-size:40px;width:40px;height:40px;color:#999}.expired-overlay p{margin:0;color:#666;font-weight:500}.connected-overlay .success-icon{font-size:56px;width:56px;height:56px;color:#4caf50}.connected-overlay p{margin:0;color:#2e7d32;font-size:16px;font-weight:600}.pairing-code-section{text-align:center}.pairing-label{margin:0 0 8px;font-size:13px;color:#666}.pairing-code{display:inline-flex;align-items:center;gap:8px;padding:10px 16px;background:#f5f5f5;border-radius:8px;cursor:pointer;transition:background .2s ease}.pairing-code:hover{background:#eee}.pairing-code .code{font-family:SF Mono,Monaco,Courier New,monospace;font-size:18px;font-weight:600;letter-spacing:2px;color:#1a1a1a}.pairing-code .copy-icon{font-size:18px;width:18px;height:18px;color:#666}.countdown{display:flex;align-items:center;gap:6px;font-size:13px;color:#666}.countdown mat-icon{font-size:18px;width:18px;height:18px}.uploaded-files{width:100%;margin-top:8px;padding-top:16px;border-top:1px solid #f0f0f0}.uploaded-files h4{margin:0 0 12px;font-size:14px;font-weight:600;color:#333}.file-list{display:flex;flex-direction:column;gap:8px;max-height:120px;overflow-y:auto}.file-item{display:flex;align-items:center;gap:8px;padding:8px 12px;background:#f1f8f4;border-radius:8px;font-size:13px;color:#333}.file-item mat-icon{font-size:18px;width:18px;height:18px;color:#4caf50}.file-item span{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.qr-dialog-footer{display:flex;justify-content:flex-end;gap:12px;padding:16px 24px;border-top:1px solid #f0f0f0;background:#fafafa}@media (max-width: 400px){.qr-dialog-container{min-width:100%;border-radius:0}.qr-canvas{width:180px;height:180px}.device-info-section{flex-direction:column;gap:8px}.connection-line{transform:rotate(90deg)}.device-card{min-width:100%}}\n"] }]
|
|
1134
|
+
args: [{ selector: 'tis-qr-code-dialog', standalone: false, template: "<div class=\"qr-dialog-container\">\n <!-- Header -->\n <div class=\"qr-dialog-header\">\n <h2 class=\"qr-dialog-title\">{{ data.title || 'Upload from Mobile' }}</h2>\n <p class=\"qr-dialog-subtitle\">{{ data.subtitle || 'Scan this QR code with your mobile device to upload images' }}</p>\n <button mat-icon-button class=\"close-btn\" (click)=\"close()\">\n <mat-icon>close</mat-icon>\n </button>\n </div>\n\n <!-- Content -->\n <div class=\"qr-dialog-content\">\n <!-- Loading State -->\n <div *ngIf=\"isLoading\" class=\"loading-container\">\n <mat-spinner diameter=\"48\"></mat-spinner>\n <p>Generating QR Code...</p>\n </div>\n\n <!-- Error State -->\n <div *ngIf=\"errorMessage && !isLoading\" class=\"error-container\">\n <mat-icon class=\"error-icon\">error_outline</mat-icon>\n <p class=\"error-message\">{{ errorMessage }}</p>\n <button mat-raised-button color=\"primary\" (click)=\"refreshQrCode()\">\n Try Again\n </button>\n </div>\n\n <!-- Main Content -->\n <div *ngIf=\"!isLoading && !errorMessage\" class=\"qr-content\">\n \n <!-- Device Info Card -->\n <div class=\"device-info-card\">\n <div class=\"device-row\">\n <mat-icon class=\"device-icon desktop\">computer</mat-icon>\n <div class=\"device-details\">\n <span class=\"device-label\">THIS DEVICE</span>\n <span class=\"device-id\" [title]=\"desktopDeviceId\">{{ formatDeviceId(desktopDeviceId) }}</span>\n </div>\n </div>\n \n <div class=\"connection-line\" *ngIf=\"mobileDeviceId\">\n <mat-icon>sync_alt</mat-icon>\n </div>\n \n <div class=\"device-row\" *ngIf=\"mobileDeviceId\">\n <mat-icon class=\"device-icon mobile\">smartphone</mat-icon>\n <div class=\"device-details\">\n <span class=\"device-label\">CONNECTED MOBILE</span>\n <span class=\"device-id\" [title]=\"mobileDeviceId\">{{ formatDeviceId(mobileDeviceId) }}</span>\n </div>\n </div>\n </div>\n\n <!-- Connected State -->\n <div *ngIf=\"isConnected\" class=\"connected-state\">\n <div class=\"connected-indicator\">\n <mat-icon class=\"success-icon\">check_circle</mat-icon>\n <span>Mobile Connected!</span>\n </div>\n <p class=\"connected-message\">\n You can now upload images from your mobile device. \n Select a file/image upload field and the uploaded files will appear automatically.\n </p>\n \n <!-- Uploaded Files -->\n <div class=\"uploaded-files\" *ngIf=\"uploadedFiles.length > 0\">\n <h4>Uploaded Files ({{ uploadedFiles.length }})</h4>\n <div class=\"file-list\">\n <div class=\"file-item\" *ngFor=\"let upload of uploadedFiles\">\n <mat-icon>check_circle</mat-icon>\n <span>{{ upload.file.fileName }}</span>\n </div>\n </div>\n </div>\n </div>\n\n <!-- QR Code (only show when not connected) -->\n <div *ngIf=\"!isConnected\" class=\"qr-section\">\n <!-- Connection Status -->\n <div class=\"connection-status\" [ngClass]=\"connectionStatus\">\n <div class=\"status-indicator\"></div>\n <span *ngIf=\"connectionStatus === 'disconnected'\">Waiting for mobile...</span>\n <span *ngIf=\"connectionStatus === 'pending'\">Waiting for connection...</span>\n </div>\n\n <!-- QR Code -->\n <div class=\"qr-code-wrapper\" [class.expired]=\"isExpired\">\n <qrcode \n *ngIf=\"qrData\"\n [qrdata]=\"qrData\" \n [width]=\"data.qrSize || 200\" \n [errorCorrectionLevel]=\"'M'\"\n [elementType]=\"'canvas'\"\n [cssClass]=\"'qr-canvas'\"\n ></qrcode>\n \n <!-- Expired Overlay -->\n <div *ngIf=\"isExpired\" class=\"expired-overlay\">\n <mat-icon>refresh</mat-icon>\n <p>QR Code Expired</p>\n <button mat-raised-button color=\"primary\" (click)=\"refreshQrCode()\">\n Generate New Code\n </button>\n </div>\n </div>\n\n <!-- Countdown Timer -->\n <div class=\"countdown\" *ngIf=\"data.showCountdown !== false && !isExpired\">\n <mat-icon>timer</mat-icon>\n <span>Expires in {{ remainingTime }}</span>\n </div>\n </div>\n\n </div>\n </div>\n\n <!-- Footer -->\n <div class=\"qr-dialog-footer\">\n <button mat-button *ngIf=\"isConnected\" color=\"warn\" (click)=\"disconnect()\">\n <mat-icon>link_off</mat-icon>\n Disconnect\n </button>\n <button mat-button *ngIf=\"!isConnected && !isLoading\" (click)=\"connectToMobile()\">\n <mat-icon>qr_code</mat-icon>\n Connect & Upload via Mobile\n </button>\n <button mat-raised-button color=\"primary\" (click)=\"close()\">\n {{ uploadedFiles.length > 0 ? 'Done' : 'Close' }}\n </button>\n </div>\n</div>\n", styles: [".qr-dialog-container{display:flex;flex-direction:column;min-width:360px;max-width:440px;background:#fff;border-radius:16px;overflow:hidden}.qr-dialog-header{position:relative;padding:24px 24px 16px;text-align:center;border-bottom:1px solid #f0f0f0}.qr-dialog-title{margin:0 0 8px;font-size:20px;font-weight:600;color:#1a1a1a}.qr-dialog-subtitle{margin:0;font-size:14px;color:#666;line-height:1.4}.close-btn{position:absolute;top:12px;right:12px;color:#999}.qr-dialog-content{padding:24px;display:flex;flex-direction:column;align-items:center;min-height:300px}.loading-container{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:16px;height:250px;color:#666}.error-container{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:16px;height:250px;text-align:center}.error-icon{font-size:48px;width:48px;height:48px;color:#f44336}.error-message{color:#666;margin:0}.qr-content{display:flex;flex-direction:column;align-items:center;gap:20px;width:100%}.device-info-section{width:100%;display:flex;align-items:center;justify-content:center;gap:12px;padding:16px;background:linear-gradient(135deg,#f8f9fa,#e9ecef);border-radius:12px;margin-bottom:8px}.device-card{display:flex;flex-direction:column;align-items:center;gap:6px;padding:12px 16px;background:#fff;border-radius:10px;min-width:120px;box-shadow:0 2px 8px #0000000f;transition:all .3s ease}.device-card.this-device{border:2px solid #2196f3}.device-card.connected-device{border:2px dashed #9e9e9e}.device-card.connected-device.active{border:2px solid #4caf50}.device-label{display:flex;align-items:center;gap:4px;font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.5px}.device-card.this-device .device-label{color:#2196f3}.device-card.connected-device .device-label{color:#9e9e9e}.device-card.connected-device.active .device-label{color:#4caf50}.device-label mat-icon{font-size:14px;width:14px;height:14px}.device-id{font-family:SF Mono,Monaco,Courier New,monospace;font-size:13px;font-weight:600;color:#333;letter-spacing:.5px}.device-id.waiting{color:#9e9e9e;font-style:italic;font-weight:400}.connection-line{display:flex;flex-direction:column;align-items:center;gap:4px;padding:0 8px}.connection-line .line{width:40px;height:2px;background:#e0e0e0;border-radius:1px;position:relative;overflow:hidden}.connection-line.waiting .line:after{content:\"\";position:absolute;top:0;left:-100%;width:50%;height:100%;background:linear-gradient(90deg,transparent,#2196f3,transparent);animation:shimmer 1.5s infinite}.connection-line.connected .line{background:#4caf50}.connection-line mat-icon{font-size:16px;width:16px;height:16px;color:#9e9e9e}.connection-line.waiting mat-icon{color:#ff9800;animation:blink 1s infinite}.connection-line.connected mat-icon{color:#4caf50}@keyframes shimmer{0%{left:-100%}to{left:200%}}@keyframes blink{0%,to{opacity:1}50%{opacity:.3}}.connection-status{display:flex;align-items:center;gap:8px;padding:8px 16px;border-radius:20px;font-size:13px;font-weight:500}.connection-status .status-indicator{width:8px;height:8px;border-radius:50%;animation:pulse 2s infinite}.connection-status.disconnected{background:#f5f5f5;color:#666}.connection-status.disconnected .status-indicator{background:#999}.connection-status.pending{background:#fff3e0;color:#e65100}.connection-status.pending .status-indicator{background:#ff9800}.connection-status.connected{background:#e8f5e9;color:#2e7d32}.connection-status.connected .status-indicator{background:#4caf50;animation:none}@keyframes pulse{0%,to{opacity:1;transform:scale(1)}50%{opacity:.5;transform:scale(1.2)}}.qr-code-wrapper{position:relative;padding:16px;background:#f8f9fa;border-radius:12px;border:2px solid #e0e0e0;transition:all .3s ease}.qr-code-wrapper.expired{opacity:.5}.qr-code-wrapper.connected{border-color:#4caf50;background:#f1f8f4}.qr-canvas{display:block;width:200px;height:200px}.expired-overlay,.connected-overlay{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;background:#fffffff2;border-radius:10px}.expired-overlay mat-icon{font-size:40px;width:40px;height:40px;color:#999}.expired-overlay p{margin:0;color:#666;font-weight:500}.connected-overlay .success-icon{font-size:56px;width:56px;height:56px;color:#4caf50}.connected-overlay p{margin:0;color:#2e7d32;font-size:16px;font-weight:600}.pairing-code-section{text-align:center}.pairing-label{margin:0 0 8px;font-size:13px;color:#666}.pairing-code{display:inline-flex;align-items:center;gap:8px;padding:10px 16px;background:#f5f5f5;border-radius:8px;cursor:pointer;transition:background .2s ease}.pairing-code:hover{background:#eee}.pairing-code .code{font-family:SF Mono,Monaco,Courier New,monospace;font-size:18px;font-weight:600;letter-spacing:2px;color:#1a1a1a}.pairing-code .copy-icon{font-size:18px;width:18px;height:18px;color:#666}.countdown{display:flex;align-items:center;gap:6px;font-size:13px;color:#666}.countdown mat-icon{font-size:18px;width:18px;height:18px}.uploaded-files{width:100%;margin-top:8px;padding-top:16px;border-top:1px solid #f0f0f0}.uploaded-files h4{margin:0 0 12px;font-size:14px;font-weight:600;color:#333}.file-list{display:flex;flex-direction:column;gap:8px;max-height:120px;overflow-y:auto}.file-item{display:flex;align-items:center;gap:8px;padding:8px 12px;background:#f1f8f4;border-radius:8px;font-size:13px;color:#333}.file-item mat-icon{font-size:18px;width:18px;height:18px;color:#4caf50}.file-item span{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.qr-dialog-footer{display:flex;justify-content:flex-end;gap:12px;padding:16px 24px;border-top:1px solid #f0f0f0;background:#fafafa}.device-info-card{width:100%;display:flex;flex-direction:row;align-items:center;justify-content:center;gap:12px;padding:12px 16px;background:linear-gradient(135deg,#f8f9fa,#e9ecef);border-radius:12px;margin-bottom:8px}.device-info-card .device-row{display:flex;align-items:center;gap:10px;flex:0 0 auto}.device-info-card .device-icon{font-size:24px;width:24px;height:24px}.device-info-card .device-icon.desktop{color:#1976d2}.device-info-card .device-icon.mobile{color:#7b1fa2}.device-info-card .device-details{display:flex;flex-direction:column;gap:2px}.device-info-card .device-label{font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.5px;color:#666}.device-info-card .device-id{font-family:SF Mono,Monaco,Courier New,monospace;font-size:12px;font-weight:500;color:#333;cursor:default}.device-info-card .connection-line{display:flex;align-items:center;padding:0 4px}.device-info-card .connection-line mat-icon{font-size:18px;width:18px;height:18px;color:#4caf50}@media (max-width: 400px){.qr-dialog-container{min-width:100%;border-radius:0}.qr-canvas{width:180px;height:180px}.device-info-section,.device-info-card{flex-direction:column;gap:8px}.device-info-card .connection-line,.connection-line{transform:rotate(90deg)}.device-card{min-width:100%}}\n"] }]
|
|
1087
1135
|
}], ctorParameters: () => [{ type: i1$2.MatDialogRef }, { type: undefined, decorators: [{
|
|
1088
1136
|
type: Inject,
|
|
1089
1137
|
args: [MAT_DIALOG_DATA]
|
|
1090
|
-
}] }, { type: TisRemoteUploadService }]
|
|
1091
|
-
type: ViewChild,
|
|
1092
|
-
args: ['qrCanvas', { static: false }]
|
|
1093
|
-
}] } });
|
|
1138
|
+
}] }, { type: TisRemoteUploadService }] });
|
|
1094
1139
|
|
|
1095
1140
|
const generateRandomString = (length) => {
|
|
1096
1141
|
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
|
@@ -2685,7 +2730,17 @@ class TisImageAndFileUploadAndViewComponent {
|
|
|
2685
2730
|
subtitle: `Scan this QR code to upload ${this.type === 'image' ? 'images' : 'files'} from your mobile device`,
|
|
2686
2731
|
qrSize: 200,
|
|
2687
2732
|
showCountdown: true,
|
|
2688
|
-
autoCloseOnUpload: false
|
|
2733
|
+
autoCloseOnUpload: false,
|
|
2734
|
+
fieldInfo: {
|
|
2735
|
+
label: this.label || `${this.type === 'image' ? 'Images' : 'Files'}`,
|
|
2736
|
+
accept: this.accept || (this.type === 'image' ? 'image/*' : '*'),
|
|
2737
|
+
type: this.type,
|
|
2738
|
+
entityType: this.entityType,
|
|
2739
|
+
entityId: this.entityId,
|
|
2740
|
+
isMultiple: this.config.isMultiple,
|
|
2741
|
+
limit: this.config.limit,
|
|
2742
|
+
isCompressed: this.config.isCompressed
|
|
2743
|
+
}
|
|
2689
2744
|
};
|
|
2690
2745
|
const dialogRef = this.dialog.open(TisQrCodeDialogComponent, {
|
|
2691
2746
|
width: this.isMobile ? '100%' : '420px',
|
|
@@ -2811,7 +2866,8 @@ class TisImageAndFileUploadAndViewModule {
|
|
|
2811
2866
|
HttpClientModule,
|
|
2812
2867
|
NgxExtendedPdfViewerModule,
|
|
2813
2868
|
FormsModule,
|
|
2814
|
-
ReactiveFormsModule,
|
|
2869
|
+
ReactiveFormsModule,
|
|
2870
|
+
QRCodeComponent, MatTooltipModule,
|
|
2815
2871
|
MatIconModule,
|
|
2816
2872
|
MatSnackBarModule,
|
|
2817
2873
|
MatProgressSpinnerModule,
|
|
@@ -2823,7 +2879,8 @@ class TisImageAndFileUploadAndViewModule {
|
|
|
2823
2879
|
HttpClientModule,
|
|
2824
2880
|
NgxExtendedPdfViewerModule,
|
|
2825
2881
|
FormsModule,
|
|
2826
|
-
ReactiveFormsModule,
|
|
2882
|
+
ReactiveFormsModule,
|
|
2883
|
+
QRCodeComponent, uiImports, DragDropModule] });
|
|
2827
2884
|
}
|
|
2828
2885
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: TisImageAndFileUploadAndViewModule, decorators: [{
|
|
2829
2886
|
type: NgModule,
|
|
@@ -2845,6 +2902,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImpor
|
|
|
2845
2902
|
NgxExtendedPdfViewerModule,
|
|
2846
2903
|
FormsModule,
|
|
2847
2904
|
ReactiveFormsModule,
|
|
2905
|
+
QRCodeComponent,
|
|
2848
2906
|
...uiImports,
|
|
2849
2907
|
DragDropModule
|
|
2850
2908
|
],
|