From 58cc256169225e9f6b6f04db3a7db880ddcea7a6 Mon Sep 17 00:00:00 2001 From: atif118-mfsys Date: Mon, 12 Jan 2026 17:45:21 +0500 Subject: [PATCH] added export data in excel and added som validations in logger manager screen --- package.json | 3 + src/app/logging/logging.component.html | 9 +- src/app/logging/logging.component.ts | 12 ++- src/app/services/auth.service.ts | 92 ------------------- .../shared/services/excel-export.service.ts | 28 ++++++ src/app/utils/app.constants.ts | 18 +++- src/assets/i18n/Arabic.json | 4 +- src/assets/i18n/English.json | 4 +- src/styles.scss | 31 +++++++ 9 files changed, 100 insertions(+), 101 deletions(-) delete mode 100644 src/app/services/auth.service.ts create mode 100644 src/app/shared/services/excel-export.service.ts diff --git a/package.json b/package.json index 1f0edd1..e6e48a5 100644 --- a/package.json +++ b/package.json @@ -27,13 +27,16 @@ "@ngx-translate/core": "^17.0.0", "@ngx-translate/http-loader": "^16.0.1", "@types/crypto-js": "^4.2.2", + "@types/file-saver": "^2.0.7", "bootstrap": "^5.3.8", "crypto-js": "^4.2.0", "express": "^4.18.2", + "file-saver": "^2.0.5", "ngx-spinner": "^19.0.0", "ngx-toastr": "^19.1.0", "rxjs": "~7.8.0", "tslib": "^2.3.0", + "xlsx": "^0.18.5", "zone.js": "~0.15.0" }, "devDependencies": { diff --git a/src/app/logging/logging.component.html b/src/app/logging/logging.component.html index b9dfb49..269b92a 100644 --- a/src/app/logging/logging.component.html +++ b/src/app/logging/logging.component.html @@ -60,7 +60,7 @@ maxlength="500" appNoWhitespaces rows="3" />
@@ -71,6 +71,10 @@ *ngIf="logsSearchForm.errors?.['toDateInvalid']"> {{ 'toDateInvalidError' | translate }}
+
+ {{ 'toDateGreaterThanToday' | translate }} +
@@ -122,6 +126,9 @@ placeholder="{{ 'search' | translate }}"> + + + diff --git a/src/app/logging/logging.component.ts b/src/app/logging/logging.component.ts index dd6c8d8..de95ba4 100644 --- a/src/app/logging/logging.component.ts +++ b/src/app/logging/logging.component.ts @@ -2,13 +2,14 @@ import { Component, OnInit } from '@angular/core'; import { FormBuilder, FormGroup, FormsModule, ReactiveFormsModule, Validators } from '@angular/forms'; import { NgSelectModule } from '@ng-select/ng-select'; import { TranslateModule } from '@ngx-translate/core'; -import { pageSizeOptions, toDateAfterFromDateValidator } from '../utils/app.constants'; +import { LOGGING_DETAILS_FILE_NAME, pageSizeOptions, toDateAfterFromDateValidator } from '../utils/app.constants'; import { CommonModule, DatePipe } from '@angular/common'; import { HttpParams } from '@angular/common/http'; import { URIKey } from '../utils/uri-enums'; import { HttpURIService } from '../app.http.uri.service'; import { LogsManagementResponse } from '../utils/app.interfaces'; import { TableFilterPipe } from '../shared/pipes/table-filter.pipe'; +import { ExcelExportService } from '../shared/services/excel-export.service'; @Component({ selector: 'app-logging', @@ -34,7 +35,8 @@ export class LoggingComponent implements OnInit { constructor( private fb: FormBuilder, private httpService: HttpURIService, - private datePipe: DatePipe + private datePipe: DatePipe, + private excelExportServic: ExcelExportService ) { } ngOnInit() { @@ -73,7 +75,7 @@ export class LoggingComponent implements OnInit { this.isLoading = false; }, error: (err) => { - console.error('Error fetching BOD data:', err); + console.error('Error fetching logging details data:', err); this.logsList = []; this.isLoading = false; } @@ -113,4 +115,8 @@ export class LoggingComponent implements OnInit { this.logsDataExpanded = !this.logsDataExpanded; } + exportDataInExcel(){ + this.excelExportServic.exportExcel(this.logsList, LOGGING_DETAILS_FILE_NAME) + } + } diff --git a/src/app/services/auth.service.ts b/src/app/services/auth.service.ts deleted file mode 100644 index 6074aea..0000000 --- a/src/app/services/auth.service.ts +++ /dev/null @@ -1,92 +0,0 @@ -import { Injectable } from '@angular/core'; -import { tap } from 'rxjs/operators'; -import { HttpService } from '../shared/services/http.service'; -import { MiscService } from '../shared/services/misc.service'; -import { Router } from '@angular/router'; -import { User } from '../models/user'; -import { HttpErrorResponse } from '@angular/common/http'; -import { CONSTANTS } from '../utils/app.constants'; -import { StorageService } from '../shared/services/storage.service'; - - -@Injectable({ - providedIn: 'root' -}) -export class AuthService { - - constructor(private httpService: HttpService, private miscService: MiscService, private router: Router, private storageService: StorageService) { } - firstLogin: boolean = false; - private token: string = ""; - - async login(User_Data: User) { - let login = false; - let userId = User_Data.Username; - let password = User_Data.Password; - let data = { "userId": userId, "password": password}; - - let url = '/authentication/login'; - - let response: any = await this.httpService.postRequest(url, data)!.toPromise(); - if (!(response instanceof HttpErrorResponse)) { - if ((await response["errorMessage"] == undefined)) { - if (response) { - login = true; - localStorage.setItem('userId', userId); - let res = JSON.parse(JSON.stringify(response)); - // let permission = JSON.parse(res['userPermission']); - // localStorage.setItem('SIDENAV', res['userPermission']); - localStorage.setItem('userFullname', res.user.userFullname); - localStorage.setItem('userId', res.user.userId); - localStorage.setItem('token', res.token); - this.firstLogin = response.requiresPasswordChange; - this.storageService.setItem('firstLogin', this.firstLogin ? 'true' : 'false'); - return res; - - } - } - let res = response; - return res; - - } - } - - IsLoggedIn() { - if (this.storageService.getItem('userId') !== null) - return true; - else - return false; - } - - logout() { - window.history.state; - localStorage.clear(); - this.router.navigate(['login']) - } - - getToken(): string { - this.token = localStorage.getItem('token') || ""; - return this.token; - } - - setToken(token: string) { - this.token = token; - localStorage.setItem('token', token); - } - - refreshToken() { - let uCreds = { token: this.getToken() }; - let porOrgacode = CONSTANTS.POR_ORGACODE; - let refreshTokenData: any = { - cmpUserId: localStorage.getItem('userId'), - token: uCreds.token, - porOrgacode: porOrgacode - } - return this.httpService.postRequest("/refreshToken", refreshTokenData)!.pipe( - tap((response: any) => { - localStorage.removeItem('token') - localStorage.setItem('token', JSON.stringify(response.token)); - this.setToken(response.token); - }) - ); - } -} diff --git a/src/app/shared/services/excel-export.service.ts b/src/app/shared/services/excel-export.service.ts new file mode 100644 index 0000000..d0b0c7d --- /dev/null +++ b/src/app/shared/services/excel-export.service.ts @@ -0,0 +1,28 @@ +import { Injectable } from '@angular/core'; +import { saveAs } from 'file-saver'; +import * as XLSX from 'xlsx'; +import { EXCEL_FILE_EXTENSION, EXCEL_FILE_TYPE } from '../../utils/app.constants'; + +@Injectable({ + providedIn: 'root' +}) +export class ExcelExportService { + + constructor() { } + + private fileType = EXCEL_FILE_TYPE; + private fileExtension = EXCEL_FILE_EXTENSION; + + public exportExcel(jsonData: any[], fileName: string): void { + + const ws: XLSX.WorkSheet = XLSX.utils.json_to_sheet(jsonData); + const wb: XLSX.WorkBook = { Sheets: { 'data': ws }, SheetNames: ['data'] }; + const excelBuffer: any = XLSX.write(wb, { bookType: 'xlsx', type: 'array' }); + this.saveExcelFile(excelBuffer, fileName); + } + + private saveExcelFile(buffer: any, fileName: string): void { + const data: Blob = new Blob([buffer], {type: this.fileType}); + saveAs.saveAs(data, fileName + this.fileExtension); + } +} diff --git a/src/app/utils/app.constants.ts b/src/app/utils/app.constants.ts index 5c27437..c93736a 100644 --- a/src/app/utils/app.constants.ts +++ b/src/app/utils/app.constants.ts @@ -16,11 +16,23 @@ export const toDateAfterFromDateValidator: ValidatorFn = ( const fromDate = group.get('fromDate')?.value; const toDate = group.get('toDate')?.value; + const currentDate = new Date().toISOString(); + if (!fromDate || !toDate) { return null; } - return toDate >= fromDate - ? null - : { toDateInvalid: true }; + if(toDate < fromDate) + return { toDateInvalid: true } + else if(toDate >= currentDate) + return { toDateGreaterThanToday: true } + else + return null + }; + +export const EXCEL_FILE_TYPE = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8'; + +export const EXCEL_FILE_EXTENSION = '.xlsx'; + +export const LOGGING_DETAILS_FILE_NAME = 'logging-manager-details' diff --git a/src/assets/i18n/Arabic.json b/src/assets/i18n/Arabic.json index fa0b624..aa3054f 100644 --- a/src/assets/i18n/Arabic.json +++ b/src/assets/i18n/Arabic.json @@ -251,5 +251,7 @@ "noLoggingDetailsFound": "لم يتم العثور على تفاصيل التسجيل", "ERR_SEC_0001": "البريد الإلكتروني موجود بالفعل", "ERR_SEC_0002": "اسم المستخدم موجود بالفعل", - "ERR_SEC_0003": "كلمة المرور القديمة غير صحيحة" + "ERR_SEC_0003": "كلمة المرور القديمة غير صحيحة", + "toDateGreaterThanToday": "يجب أن يكون التاريخ الحالي أقل من التاريخ الحالي", + "fromDateGreaterThanToday": "يجب أن يكون تاريخ البدء أقل من التاريخ الحالي" } \ No newline at end of file diff --git a/src/assets/i18n/English.json b/src/assets/i18n/English.json index 7770d94..a1fd3e9 100644 --- a/src/assets/i18n/English.json +++ b/src/assets/i18n/English.json @@ -251,5 +251,7 @@ "noLoggingDetailsFound": "No Logging Details found", "ERR_SEC_0001": "Email already exists", "ERR_SEC_0002": "Username already exists", - "ERR_SEC_0003": "Old Password is not correct" + "ERR_SEC_0003": "Old Password is not correct", + "toDateGreaterThanToday": "To Date must be less than Current Date", + "fromDateGreaterThanToday": "From Date must be less than Current Date" } \ No newline at end of file diff --git a/src/styles.scss b/src/styles.scss index 571bf5b..e3fc20b 100644 --- a/src/styles.scss +++ b/src/styles.scss @@ -169,3 +169,34 @@ ng-select.form-select-sm { width: 98% !important; } +#downloadReport { + width: 30px; + height: 30px; + border: 2px solid #64B5F6; + border-radius: 50%; + background: transparent; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + padding: 0; + transition: all 0.25s ease; +} + +#downloadReport i { + color: #64B5F6; + font-size: 16px; +} + +#downloadReport:hover { + background-color: #64B5F6; +} + +#downloadReport:hover i { + color: #ffffff; +} + +#downloadReport:focus { + outline: none; + box-shadow: 0 0 0 3px rgba(76, 175, 80, 0.35); +} \ No newline at end of file -- 2.32.0