diff --git a/src/app/app-provider-admin/provider-admin/activities/services/employee-parking-place-mapping.service.ts b/src/app/app-provider-admin/provider-admin/activities/services/employee-parking-place-mapping.service.ts
index 2dbdebb8..183ca9fe 100644
--- a/src/app/app-provider-admin/provider-admin/activities/services/employee-parking-place-mapping.service.ts
+++ b/src/app/app-provider-admin/provider-admin/activities/services/employee-parking-place-mapping.service.ts
@@ -124,4 +124,8 @@ export class EmployeeParkingPlaceMappingService {
observe: 'response',
});
}
+
+ activateOrDeActivateSignature(data: any) {
+ return this.http.post(environment.signatureStatus, data);
+ }
}
diff --git a/src/app/app-provider-admin/provider-admin/configurations/configurations.module.ts b/src/app/app-provider-admin/provider-admin/configurations/configurations.module.ts
index a7119996..78b36204 100644
--- a/src/app/app-provider-admin/provider-admin/configurations/configurations.module.ts
+++ b/src/app/app-provider-admin/provider-admin/configurations/configurations.module.ts
@@ -47,6 +47,9 @@ import { WrapupTimeConfigurationService } from 'src/app/core/services/ProviderAd
import { CoreModule } from 'src/app/core/core.module';
import { EmailConfigurationComponent } from './email-configuration/email-configuration.component';
import { EmailConfigurationService } from 'src/app/core/services/ProviderAdminServices/email-configuration-services.service';
+import { MatPaginatorModule } from '@angular/material/paginator';
+import { MatSortModule } from '@angular/material/sort';
+import { MatInputModule } from '@angular/material/input';
@NgModule({
declarations: [
@@ -83,6 +86,9 @@ import { EmailConfigurationService } from 'src/app/core/services/ProviderAdminSe
MatIconModule,
MatNativeDateModule,
CoreModule,
+ MatPaginatorModule,
+ MatSortModule,
+ MatInputModule,
],
providers: [
SnomedMasterService,
diff --git a/src/app/app-provider-admin/provider-admin/configurations/sms-template/sms-template.component.html b/src/app/app-provider-admin/provider-admin/configurations/sms-template/sms-template.component.html
index 1c384d10..cdcfa1a0 100644
--- a/src/app/app-provider-admin/provider-admin/configurations/sms-template/sms-template.component.html
+++ b/src/app/app-provider-admin/provider-admin/configurations/sms-template/sms-template.component.html
@@ -186,12 +186,12 @@
Create SMS Template
required
[readonly]="isReadonly"
minlength="20"
- maxlength="200"
+ maxlength="300"
#sms
name="smsTemplate"
>
{{ sms.value.length ? sms.value.length : 0 }}/200{{ sms.value.length ? sms.value.length : 0 }}/300
diff --git a/src/app/app-provider-admin/provider-admin/configurations/sms-template/sms-template.component.ts b/src/app/app-provider-admin/provider-admin/configurations/sms-template/sms-template.component.ts
index f04794b9..02808972 100644
--- a/src/app/app-provider-admin/provider-admin/configurations/sms-template/sms-template.component.ts
+++ b/src/app/app-provider-admin/provider-admin/configurations/sms-template/sms-template.component.ts
@@ -392,7 +392,7 @@ export class SmsTemplateComponent implements OnInit, AfterViewInit {
saveSMStemplate(form_values: any) {
const requestObject = {
- createdBy: this.commonData.Userdata.userName,
+ createdBy: this.commonData.uname,
providerServiceMapID: this.providerServiceMapID,
smsParameterMaps: this.smsParameterData.data,
smsTemplate: form_values.smsTemplate,
diff --git a/src/app/app-provider-admin/provider-admin/configurations/user-signature-mapping/user-signature-mapping.component.css b/src/app/app-provider-admin/provider-admin/configurations/user-signature-mapping/user-signature-mapping.component.css
index 413bee2c..a90741d3 100644
--- a/src/app/app-provider-admin/provider-admin/configurations/user-signature-mapping/user-signature-mapping.component.css
+++ b/src/app/app-provider-admin/provider-admin/configurations/user-signature-mapping/user-signature-mapping.component.css
@@ -7,4 +7,49 @@
border:none;
margin:0;
padding:0;
+}
+.mat-header-cell,
+.mat-cell {
+ text-align: left; /* or left/right depending on need */
+ vertical-align: middle;
+}
+.title {
+ margin: 0;
+ padding: 10px;
+ margin-bottom: 10px;
+ color: white;
+ font-weight:700;
+ font-size: 18px;
+ background-color: #0277bd !important;
+ }
+
+ .message {
+ font: 500 20px / 32px Roboto, "Helvetica Neue", sans-serif;
+ padding:0px 24px 0px 24px;
+
+ }
+
+ .info {
+ background: #0277bd;
+ }
+
+ .signature-container {
+ display: flex;
+ justify-content: center; /* center image horizontally */
+ margin: 20px 0; /* space top & bottom */
+}
+
+.signature-img {
+ max-width: 100%;
+ max-height: 200px;
+}
+
+.action {
+ display: flex;
+ justify-content: flex-end; /* align button right */
+ margin: 20px 20px 10px 0; /* spacing: top right bottom left */
+}
+
+.ok-btn {
+ margin-right: 10px; /* small gap from edge */
}
\ No newline at end of file
diff --git a/src/app/app-provider-admin/provider-admin/configurations/user-signature-mapping/user-signature-mapping.component.html b/src/app/app-provider-admin/provider-admin/configurations/user-signature-mapping/user-signature-mapping.component.html
index 9436c4c5..4e711208 100644
--- a/src/app/app-provider-admin/provider-admin/configurations/user-signature-mapping/user-signature-mapping.component.html
+++ b/src/app/app-provider-admin/provider-admin/configurations/user-signature-mapping/user-signature-mapping.component.html
@@ -8,79 +8,117 @@ User Signature Mapping
Designation
-
+
{{ item.designationName }}
-
-
- UserName
-
-
- {{ item.userName }}
-
-
-
-
-
-
-
-
-
-
-
+
![img]()
-
-
-
- Download signature
-
+
-
+
+
+ 0">
+
+
+
+
+ search
+
+
+
+
+
+
+
+ {{ data.username }}'s Signature
+
+
+
![signature]()
+
+
+
+
+ OK
+
+
+
+
+
\ No newline at end of file
diff --git a/src/app/app-provider-admin/provider-admin/configurations/user-signature-mapping/user-signature-mapping.component.ts b/src/app/app-provider-admin/provider-admin/configurations/user-signature-mapping/user-signature-mapping.component.ts
index d64048ea..fa18af58 100644
--- a/src/app/app-provider-admin/provider-admin/configurations/user-signature-mapping/user-signature-mapping.component.ts
+++ b/src/app/app-provider-admin/provider-admin/configurations/user-signature-mapping/user-signature-mapping.component.ts
@@ -19,20 +19,21 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
-import { Component, OnInit } from '@angular/core';
+import { Component, OnInit, TemplateRef, ViewChild } from '@angular/core';
import {
FormBuilder,
FormGroup,
- FormControl,
- FormArray,
- NgForm,
Validators,
} from '@angular/forms';
import { ConfirmationDialogsService } from 'src/app/core/services/dialog/confirmation.service';
import { EmployeeParkingPlaceMappingService } from '../../activities/services/employee-parking-place-mapping.service';
import { dataService } from 'src/app/core/services/dataService/data.service';
import { SessionStorageService } from 'Common-UI/src/registrar/services/session-storage.service';
-
+import { MatDialog } from '@angular/material/dialog';
+import { map, Observable, forkJoin, switchMap, takeUntil, Subject } from 'rxjs';
+import { MatPaginator } from '@angular/material/paginator';
+import { MatSort } from '@angular/material/sort';
+import { MatTableDataSource } from '@angular/material/table';
@Component({
selector: 'app-user-signature-mapping',
templateUrl: './user-signature-mapping.component.html',
@@ -50,6 +51,12 @@ export class UserSignatureMappingComponent implements OnInit {
public imagePath: any;
imgURL: any;
enableDownloadButton = false;
+ displayedColumns: string[] = ['role', 'username', 'upload', 'download', 'view', 'active'];
+ userSignatureTable: any[] = [];
+ selectedUser: any;
+ dataSource = new MatTableDataSource([]);
+ private destroy$ = new Subject();
+
constructor(
private fb: FormBuilder,
@@ -57,14 +64,42 @@ export class UserSignatureMappingComponent implements OnInit {
private alertMessage: ConfirmationDialogsService,
private dataService: dataService,
readonly sessionstorage: SessionStorageService,
- ) {}
+ private dialog: MatDialog,
+
+ ) { }
+
+ @ViewChild('signatureDialog') signatureDialog!: TemplateRef;
+ @ViewChild(MatPaginator) paginator!: MatPaginator;
+ @ViewChild(MatSort) sort!: MatSort;
ngOnInit() {
this.signUploadForm = this.createSignUploadForm();
this.createdBy = this.dataService.uname;
this.serviceProviderID = this.sessionstorage.getItem('service_providerID');
this.getDesignations();
+
+ this.dataSource.filterPredicate = (data: any, filter: string) => {
+ const dataStr = (data.role + data.username).toLowerCase();
+ return dataStr.includes(filter);
+ };
+ }
+
+ ngAfterViewInit() {
+ this.dataSource.paginator = this.paginator;
+ this.dataSource.sort = this.sort;
+ }
+
+ ngAfterViewChecked() {
+ if (this.paginator && this.dataSource.paginator !== this.paginator) {
+ this.dataSource.paginator = this.paginator;
+ }
}
+
+ ngOnDestroy(): void {
+ this.destroy$.next();
+ this.destroy$.complete();
+ }
+
createSignUploadForm() {
return this.fb.group({
designation: [null, Validators.required],
@@ -87,42 +122,91 @@ export class UserSignatureMappingComponent implements OnInit {
},
);
}
+
+
getUserNames() {
const reqObj = {
designationID: this.designation.designationID,
serviceProviderID: this.serviceProviderID,
};
+
this.employeeParkingPlaceMappingService
.getUserNameBasedOnDesig(reqObj)
+ .pipe(
+ switchMap((response: any) => {
+ if (!response?.data) return [];
+ this.userNames = response.data;
+
+ // map users to observables
+ const requests = this.userNames.map((user: any) =>
+ this.employeeParkingPlaceMappingService
+ .checkUsersignatureExist(user.userID)
+ .pipe(
+ map((signRes: any) => ({
+ role: this.designation.designationName,
+ username: user.userName,
+ userID: user.userID,
+ signatureStatus: user?.signatureStatus || 'InActive',
+ signatureUrl: signRes?.data?.signatureUrl || null,
+ signExist: String(signRes?.data?.response).toLowerCase() === 'true',
+ active: signRes?.data?.active || false,
+ statusID: String(signRes?.data?.response).toLowerCase() === 'true',
+ }))
+ )
+ );
+
+ return forkJoin(requests).pipe(
+ map(results => results as any[])
+ ); // run all requests in parallel and cast result to any[]
+ }),
+ takeUntil(this.destroy$)
+ )
.subscribe(
- (response: any) => {
- if (response && response.data) this.userNames = response.data;
- },
- (err) => {
- console.log('usernames not fetched');
+ (usersWithSignatures: any[]) => {
+ this.userSignatureTable = usersWithSignatures;
+ this.dataSource.data = this.userSignatureTable;
},
+ () => console.log('Usernames not fetched')
);
}
+
+
+ // When a user is selected
checkUsersignExist() {
this.imgURL = null;
+ this.selectedUser = this.username; // Store selected user for table
+
this.employeeParkingPlaceMappingService
.checkUsersignatureExist(this.username.userID)
.subscribe(
(response: any) => {
this.signExist = response.data.response;
- if (this.signExist === 'true') {
- this.enableDownloadButton = true;
- } else {
- this.enableDownloadButton = false;
- }
+ this.enableDownloadButton = this.signExist === 'true';
+
+ // Fill table data (example format)
+ this.userSignatureTable = [
+ {
+ role: this.designation.designationName,
+ username: this.username.userName,
+ signatureUrl: response.data.signatureUrl || null,
+ active: response.data.active || false,
+ userID: this.username.userID,
+ statusID: this.username.statusID
+ },
+ ];
+ this.dataSource.data = this.userSignatureTable
},
(err) => {
console.log('Error while fetching response');
- },
+ }
);
}
+
public message: any;
- preview(files: any) {
+
+ preview(files: any, row: any) {
+
+ this.selectedUser = row.userID;
if (files.length === 0) return;
const imgType = files[0].type;
@@ -138,6 +222,7 @@ export class UserSignatureMappingComponent implements OnInit {
this.checkImageSize(reader);
};
}
+
checkImageSize(reader: any) {
if (this.imagePath.size > 20000) {
this.alertMessage.alert('Image size should be less than 20kb');
@@ -165,13 +250,14 @@ export class UserSignatureMappingComponent implements OnInit {
createdBy: this.createdBy,
fileName: this.imagePath.name,
fileType: this.imagePath.type,
- userID: this.username.userID,
+ userID: this.selectedUser,
fileContent: this.imgURL !== undefined ? this.imgURL.split(',')[1] : '',
};
this.employeeParkingPlaceMappingService.uploadSignature(signObj).subscribe(
(response) => {
this.alertMessage.alert('Saved successfully', 'success');
- this.signUploadForm.reset();
+ this.getUserNames(); // Refresh table to show new signature
+
this.imgURL = null;
this.signExist = null;
this.enableDownloadButton = false;
@@ -182,25 +268,135 @@ export class UserSignatureMappingComponent implements OnInit {
},
);
}
- downloadSign() {
+
+ private processDownloadResponse(response: any): { filename: string; url: string } {
+ let filename = 'signature.png';
+ const contentDisposition = response.headers.get('content-disposition');
+
+ if (contentDisposition) {
+ const utf8FilenameRegex = /filename\*\=UTF-8''(.+)/;
+ const asciiFilenameRegex = /filename="?([^"]+)"?/;
+
+ let matches = utf8FilenameRegex.exec(contentDisposition);
+ if (matches?.[1]) {
+ filename = decodeURIComponent(matches[1]);
+ } else {
+ matches = asciiFilenameRegex.exec(contentDisposition);
+ if (matches?.[1]) {
+ filename = decodeURIComponent(matches[1]);
+ }
+ }
+ }
+ // const blob = new Blob([response.body!], { type: response.body!.type });
+ const body: Blob | null = response.body as Blob;
+ if (!body) {
+ throw new Error('Empty response body');
+ }
+ const blob = new Blob([body], { type: (body as any).type || 'application/octet-stream' });
+ const url = URL.createObjectURL(blob);
+
+ return { filename, url };
+ }
+
+ downloadSign(row: any) {
this.employeeParkingPlaceMappingService
- .downloadSign(this.username.userID)
+ .downloadSign(row?.userID)
.subscribe(
- (response: any) => {
- const filename = response.headers.get('filename');
- // let blobResponse = response.body.blob();
- const blob = new Blob([response], { type: response.type });
- console.log(blob, 'blob');
- const url = window.URL.createObjectURL(blob);
+ (response) => {
+ const { filename, url } = this.processDownloadResponse(response);
+
const a = document.createElement('a');
a.href = url;
a.download = filename;
- document.body.appendChild(a);
a.click();
+
+ URL.revokeObjectURL(url);
},
(err) => {
this.alertMessage.alert(err.errorMessage, 'error');
+ }
+ );
+ }
+
+ downloadSignature(userID: any): Observable {
+ return this.employeeParkingPlaceMappingService.downloadSign(userID).pipe(
+ map((response) => {
+ const { url } = this.processDownloadResponse(response);
+ return url;
+ })
+ );
+ }
+
+ // View signature popup
+ openSignatureDialog(row: any) {
+ if (!row.userID) {
+ this.alertMessage.alert('No signature uploaded for this user');
+ return;
+ }
+
+ this.downloadSignature(row.userID).subscribe(
+ (signatureUrl: string) => {
+ // Open dialog with image
+ this.dialogRef = this.dialog.open(this.signatureDialog, {
+ width: '400px',
+ data: {
+ username: row.username,
+ signatureUrl: signatureUrl
+ },
+ });
+ },
+ (err) => {
+ this.alertMessage.alert('Error fetching signature', 'error');
+ }
+ );
+ }
+ applyFilter(event: Event) {
+ const filterValue = (event.target as HTMLInputElement).value;
+ this.dataSource.filter = filterValue.trim().toLowerCase();
+ }
+
+ // Toggle signature status
+ toggleActive(row: any, action: boolean) {
+ const req = { userID: row.userID, active: action, role: this.designation.designationName, username: row.username };
+ this.alertMessage
+ .confirm(
+ 'confirm',
+ 'Are you sure you want to ' + (action ? 'activate' : 'deactivate') + ' this signature?',
+ ).subscribe(
+ (res) => {
+ if (res) {
+
+ this.employeeParkingPlaceMappingService
+ .activateOrDeActivateSignature(req)
+ .subscribe(
+
+ () => {
+ if (action)
+ this.alertMessage.alert('Signature has been Activated', 'success')
+ else
+ this.alertMessage.alert('Signature has been Deactivated', 'success');
+
+ this.getUserNames(); // Refresh table to show new signature
+
+ },
+ (err) => {
+ this.alertMessage.alert('Error updating status', 'error');
+ row.active = !row.active; // rollback on failure
+ }
+ );
+ }
+ },
+ (err) => {
+ console.log(err);
},
);
}
+
+ dialogRef: any;
+
+ closeDialog(): void {
+ if (this.dialogRef) {
+ this.dialogRef.close();
+ }
+ }
}