Commit 5b458bab authored by YoussefElmoudene's avatar YoussefElmoudene

first commit

parent 0300e24a
Pipeline #738 failed with stages
...@@ -30,7 +30,9 @@ ...@@ -30,7 +30,9 @@
"src/assets" "src/assets"
], ],
"styles": [ "styles": [
"src/styles.scss" "src/styles.scss",
"node_modules/primeng/resources/themes/lara-light-blue/theme.css",
"node_modules/primeng/resources/primeng.min.css"
], ],
"scripts": [] "scripts": []
}, },
...@@ -39,8 +41,8 @@ ...@@ -39,8 +41,8 @@
"budgets": [ "budgets": [
{ {
"type": "initial", "type": "initial",
"maximumWarning": "500kb", "maximumWarning": "2mb",
"maximumError": "1mb" "maximumError": "2mb"
}, },
{ {
"type": "anyComponentStyle", "type": "anyComponentStyle",
...@@ -62,6 +64,10 @@ ...@@ -62,6 +64,10 @@
"defaultConfiguration": "production" "defaultConfiguration": "production"
}, },
"serve": { "serve": {
"options": {
"host": "0.0.0.0",
"port": 4200
},
"builder": "@angular-devkit/build-angular:dev-server", "builder": "@angular-devkit/build-angular:dev-server",
"configurations": { "configurations": {
"production": { "production": {
...@@ -93,7 +99,9 @@ ...@@ -93,7 +99,9 @@
"src/assets" "src/assets"
], ],
"styles": [ "styles": [
"src/styles.scss" "src/styles.scss",
"node_modules/primeng/resources/themes/lara-light-blue/theme.css",
"node_modules/primeng/resources/primeng.min.css"
], ],
"scripts": [] "scripts": []
} }
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
"scripts": { "scripts": {
"ng": "ng", "ng": "ng",
"start": "ng serve", "start": "ng serve",
"build": "ng build", "build": "ng build --configuration production",
"watch": "ng build --watch --configuration development", "watch": "ng build --watch --configuration development",
"test": "ng test" "test": "ng test"
}, },
...@@ -18,6 +18,10 @@ ...@@ -18,6 +18,10 @@
"@angular/platform-browser": "^16.2.0", "@angular/platform-browser": "^16.2.0",
"@angular/platform-browser-dynamic": "^16.2.0", "@angular/platform-browser-dynamic": "^16.2.0",
"@angular/router": "^16.2.0", "@angular/router": "^16.2.0",
"@types/pdfjs-dist": "^2.10.378",
"ngx-lottie": "^10.0.0",
"pdfjs-dist": "^4.5.136",
"primeng": "^16.9.1",
"rxjs": "~7.8.0", "rxjs": "~7.8.0",
"tslib": "^2.3.0", "tslib": "^2.3.0",
"zone.js": "~0.13.0" "zone.js": "~0.13.0"
...@@ -27,12 +31,15 @@ ...@@ -27,12 +31,15 @@
"@angular/cli": "^16.2.14", "@angular/cli": "^16.2.14",
"@angular/compiler-cli": "^16.2.0", "@angular/compiler-cli": "^16.2.0",
"@types/jasmine": "~4.3.0", "@types/jasmine": "~4.3.0",
"autoprefixer": "^10.4.20",
"jasmine-core": "~4.6.0", "jasmine-core": "~4.6.0",
"karma": "~6.4.0", "karma": "~6.4.0",
"karma-chrome-launcher": "~3.2.0", "karma-chrome-launcher": "~3.2.0",
"karma-coverage": "~2.2.0", "karma-coverage": "~2.2.0",
"karma-jasmine": "~5.1.0", "karma-jasmine": "~5.1.0",
"karma-jasmine-html-reporter": "~2.1.0", "karma-jasmine-html-reporter": "~2.1.0",
"postcss": "^8.4.41",
"tailwindcss": "^3.4.9",
"typescript": "~5.1.3" "typescript": "~5.1.3"
} }
} }
import { NgModule } from '@angular/core'; import {NgModule} from '@angular/core';
import { RouterModule, Routes } from '@angular/router'; import {RouterModule, Routes} from '@angular/router';
import {ScannerComponent} from "./modules/pdf-scanner/scanner/scanner.component";
import {ScanCompletedComponent} from "./modules/pdf-scanner/scan-completed/scan-completed.component";
import {
ScanCompletedMethodTwoComponent
} from "./modules/pdf-scanner/scan-completed-method-two/scan-completed.method.two.component";
const routes: Routes = []; const routes: Routes = [
{
path: '',
pathMatch: 'full',
redirectTo: 'pdf-scanner'
},
{
path: 'pdf-scanner',
component: ScannerComponent,
},
{
path: 'scan-completed/:origin/:scanned',
component: ScanCompletedComponent,
},
{
path: 'scanner-completed/view',
component: ScanCompletedMethodTwoComponent,
},
];
@NgModule({ @NgModule({
imports: [RouterModule.forRoot(routes)], imports: [RouterModule.forRoot(routes)],
exports: [RouterModule] exports: [RouterModule]
}) })
export class AppRoutingModule { } export class AppRoutingModule {
}
This diff is collapsed.
import { TestBed } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { AppComponent } from './app.component';
describe('AppComponent', () => {
beforeEach(() => TestBed.configureTestingModule({
imports: [RouterTestingModule],
declarations: [AppComponent]
}));
it('should create the app', () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.componentInstance;
expect(app).toBeTruthy();
});
it(`should have as title 'sky-pdf-scanner-front'`, () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.componentInstance;
expect(app.title).toEqual('sky-pdf-scanner-front');
});
it('should render title', () => {
const fixture = TestBed.createComponent(AppComponent);
fixture.detectChanges();
const compiled = fixture.nativeElement as HTMLElement;
expect(compiled.querySelector('.content span')?.textContent).toContain('sky-pdf-scanner-front app is running!');
});
});
import { Component } from '@angular/core'; import {Component, Input} from '@angular/core';
import {AnimationOptions} from "ngx-lottie";
@Component({ @Component({
selector: 'app-root', selector: 'app-root',
......
import { NgModule } from '@angular/core'; import {NgModule} from '@angular/core';
import { BrowserModule } from '@angular/platform-browser'; import {BrowserModule} from '@angular/platform-browser';
import { AppRoutingModule } from './app-routing.module'; import {AppRoutingModule} from './app-routing.module';
import { AppComponent } from './app.component'; import {AppComponent} from './app.component';
import {HeaderComponent} from './modules/layout/header/header.component';
import {NgOptimizedImage} from "@angular/common";
import {LayoutComponent} from './modules/layout/layout.component';
import {ScannerComponent} from './modules/pdf-scanner/scanner/scanner.component';
import {MessageService} from "primeng/api";
import {ToastModule} from "primeng/toast";
import {BrowserAnimationsModule} from "@angular/platform-browser/animations";
import {ScanCompletedComponent} from './modules/pdf-scanner/scan-completed/scan-completed.component';
import {SafePipe} from "./core/pipes/safe.pipe";
import {ReaderDialogComponent} from './modules/pdf-scanner/scan-completed/reader-dialog/reader-dialog.component';
import {DialogModule} from "primeng/dialog";
import {HttpClientModule} from "@angular/common/http";
import {
ScanCompletedMethodTwoComponent
} from "./modules/pdf-scanner/scan-completed-method-two/scan-completed.method.two.component";
import {LoaderComponent} from './modules/layout/loader/loader.component';
import {LottieModule} from "ngx-lottie";
import player from 'lottie-web';
import {TooltipModule} from "primeng/tooltip";
// Factory function that returns the lottie-web player
export function playerFactory() {
return player;
}
@NgModule({ @NgModule({
declarations: [ declarations: [
AppComponent SafePipe,
AppComponent,
HeaderComponent,
LayoutComponent,
ScannerComponent,
ScanCompletedComponent,
ReaderDialogComponent,
ScanCompletedMethodTwoComponent,
LoaderComponent
], ],
imports: [ imports: [
BrowserModule, BrowserModule,
AppRoutingModule HttpClientModule,
AppRoutingModule,
NgOptimizedImage,
ToastModule,
BrowserAnimationsModule,
DialogModule,
LottieModule.forRoot({player: playerFactory}),
TooltipModule,
// Correctly configure the LottieModule
], ],
providers: [], providers: [MessageService, SafePipe],
bootstrap: [AppComponent] bootstrap: [AppComponent]
}) })
export class AppModule { } export class AppModule {
}
export class ScanResponse {
Score: string = ''
message: string = ''
// @ts-ignore
original_pdf: {
differences_found: number,
filename: string
}
// @ts-ignore
scanned_pdf: {
differences_found: number,
filename: string
}
statuscode: string = ''
}
import {Pipe, PipeTransform} from "@angular/core";
import {DomSanitizer} from "@angular/platform-browser";
@Pipe({name: 'safe'})
export class SafePipe implements PipeTransform {
constructor(private sanitizer: DomSanitizer) {
}
transform(url: string) {
return this.sanitizer.bypassSecurityTrustResourceUrl(url);
}
}
import {Injectable} from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class LoaderService {
private _showLoader: boolean = false
constructor() {
}
get showLoader(): boolean {
return this._showLoader;
}
public show(): void {
this._showLoader = true;
}
public hide(): void {
this._showLoader = false;
}
}
<div class="w-full bg-primary flex items-center justify-center shadow-lg h-[75px]">
<div class="max-w-6xl w-full flex items-center justify-center">
<img class="w-[90px] h-[40px]" ngSrc="/assets/logo/logo.svg" width="237" height="89" alt="">
</div>
</div>
import {Component} from '@angular/core';
@Component({
selector: 'app-header',
templateUrl: './header.component.html'
})
export class HeaderComponent {
constructor() {
}
}
<div *ngIf="showLoader" class="loader-overlay">
<ng-lottie [options]="options"></ng-lottie>
</div>
<div class="w-full h-screen">
<p-toast></p-toast>
<app-header></app-header>
<router-outlet></router-outlet>
</div>
import {Component, Input} from '@angular/core';
import {AnimationOptions} from "ngx-lottie";
import {LoaderService} from "../../core/services/loader.service";
@Component({
selector: 'app-layout',
templateUrl: './layout.component.html'
})
export class LayoutComponent {
@Input() options: AnimationOptions;
constructor(private loader: LoaderService) {
this.options = {
path: '/assets/loader/loader.json', // This will be set dynamically
loop: true,
autoplay: true,
};
}
get showLoader(): boolean {
return this.loader.showLoader;
}
}
import { Component } from '@angular/core';
@Component({
selector: 'app-loader',
templateUrl: './loader.component.html',
styleUrls: ['./loader.component.scss']
})
export class LoaderComponent {
}
<div class="w-full px-5 flex items-center justify-center">
<div class="w-full max-w-6xl flex flex-col items-center justify-center">
<div class="w-full my-12 text-center text-2xl font-semibold">
Contract Compliance
</div>
<div class="w-full grid grid-cols-1 gap-4 md:grid-cols-2 md:gap-8">
<div (click)="openDialog()" class="flex flex-col gap-2 items-start justify-center">
<p>Original document :</p>
<div (click)="openDialog()" class="w-full hover:shadow-2xl
h-72 border border-dashed p-4 rounded-md
flex flex-col border-[#DEDCDC] items-center justify-center">
<embed [src]="originalUrl | safe" type="application/pdf" width="100%" height="100%"/>
</div>
</div>
<div (click)="openDialog()" class="flex flex-col gap-2 items-start justify-center">
<p>Scanned document :</p>
<div (click)="openDialog()" class="w-full hover:shadow-2xl
h-72 border border-dashed p-4 rounded-md
flex flex-col border-[#DEDCDC] items-center justify-center">
<embed (click)="openDialog()"
[src]="scannedUrl | safe" type="application/pdf" width="100%" height="100%"/>
</div>
</div>
</div>
<div class="w-full mb-2 flex flex-col gap-4 mt-12 items-center justify-center">
<div class="w-auto px-5 py-2 border-2 border-solid border-[#39B7FA] rounded-md">
Compliance score : 0.9
</div>
<button (click)="startScan()"
class="primary-button transition duration-700 ease-in-out
p-2 rounded-xl">
Retry
</button>
</div>
</div>
</div>
<app-reader-dialog></app-reader-dialog>
import {ChangeDetectorRef, Component, OnInit} from '@angular/core';
import {ScannerService} from "../scanner.service";
import {ActivatedRoute, Router} from "@angular/router";
@Component({
selector: 'app-scan-two-completed',
templateUrl: './scan-completed.method.two.component.html'
})
export class ScanCompletedMethodTwoComponent implements OnInit {
constructor(private service: ScannerService,
private route: ActivatedRoute,
private changeDetector: ChangeDetectorRef,
private router: Router) {
}
get originalUrl(): string {
return this.service.originalUrl;
}
set originalUrl(value: string) {
this.service.originalUrl = value;
}
get scannedUrl(): string {
return this.service.scannedUrl;
}
get showDialog(): boolean {
return this.service.showDialog;
}
set showDialog(value: boolean) {
this.service.showDialog = value;
}
get originalFile(): File | null {
return this.service.originalFile;
}
set originalFile(value: File | null) {
this.service.originalFile = value;
}
get scannedFile(): File | null {
return this.service.scannedFile;
}
set scannedFile(value: File | null) {
this.service.scannedFile = value;
}
startScan() {
this.router.navigate(['/pdf-scanner'])
}
ngOnInit() {
const originName: string = this.route.snapshot.params['origin']
const scannedName: string = this.route.snapshot.params['scanned']
console.log(this.scannedUrl)
console.log(this.originalUrl)
}
openDialog() {
this.showDialog = true
}
}
<p-dialog header="PDF reader" [(visible)]="showDialog"
[style]="{width: '80vw'}"
[maximizable]="true">
<div class="w-full grid grid-cols-1 gap-4 md:grid-cols-2 md:gap-8">
<div class="flex flex-col gap-2 items-start justify-center">
<p>Original document :</p>
<div class="w-full
h-screen border border-dashed p-4 rounded-md
flex flex-col border-[#DEDCDC] items-center justify-center">
<embed [src]="originalUrl | safe" type="application/pdf" width="100%" height="100%"/>
</div>
</div>
<div class="flex flex-col gap-2 items-start justify-center">
<p>Original document :</p>
<div class="w-full
h-screen border border-dashed p-4 rounded-md
flex flex-col border-[#DEDCDC] items-center justify-center">
<embed [src]="scannedUrl | safe" type="application/pdf" width="100%" height="100%"/>
</div>
</div>
</div>
</p-dialog>
import {Component} from '@angular/core';
import {ScannerService} from "../../scanner.service";
@Component({
selector: 'app-reader-dialog',
templateUrl: './reader-dialog.component.html'
})
export class ReaderDialogComponent {
constructor(private service: ScannerService) {
}
get originalUrl(): string {
return this.service.originalUrl;
}
get scannedUrl(): string {
return this.service.scannedUrl;
}
get showDialog(): boolean {
return this.service.showDialog;
}
set showDialog(value: boolean) {
this.service.showDialog = value;
}
}
<div class="w-full px-5 flex items-center justify-center">
<div class="w-full max-w-6xl flex flex-col items-center justify-center">
<div class="w-full my-10 text-center text-2xl font-semibold">
Contract Compliance
</div>
<div class="w-full grid grid-cols-1 gap-4 md:grid-cols-2 md:gap-8">
<div
class="flex flex-col gap-2 items-start justify-center">
<p>Original document :</p>
<div class="w-full
h-72 border border-dashed p-4 rounded-md
flex flex-col gap-2 border-[#DEDCDC] items-center justify-center">
<div class="w-full flex items-end justify-end">
<button
[pTooltip]="'full screen'"
tooltipPosition="top"
(click)="openDialog()">
<svg class="text-gray-500 justify-end w-5 h-5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
<path
d="M320 0c-17.7 0-32 14.3-32 32s14.3 32 32 32l82.7 0L201.4 265.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L448 109.3l0 82.7c0 17.7 14.3 32 32 32s32-14.3 32-32l0-160c0-17.7-14.3-32-32-32L320 0zM80 32C35.8 32 0 67.8 0 112L0 432c0 44.2 35.8 80 80 80l320 0c44.2 0 80-35.8 80-80l0-112c0-17.7-14.3-32-32-32s-32 14.3-32 32l0 112c0 8.8-7.2 16-16 16L80 448c-8.8 0-16-7.2-16-16l0-320c0-8.8 7.2-16 16-16l112 0c17.7 0 32-14.3 32-32s-14.3-32-32-32L80 32z"/>
</svg>
</button>
</div>
<embed [src]="originalUrl | safe" type="application/pdf" width="100%" height="100%"/>
</div>
</div>
<div
class="flex flex-col gap-2 items-start justify-center">
<p>Scanned document :</p>
<div class="w-full
h-72 border border-dashed p-4 rounded-md
flex gap-2 flex-col border-[#DEDCDC] items-center justify-center">
<div class="w-full flex items-end justify-end">
<button
[pTooltip]="'full screen'"
tooltipPosition="top"
(click)="openDialog()">
<svg class="text-gray-500 justify-end w-5 h-5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
<path
d="M320 0c-17.7 0-32 14.3-32 32s14.3 32 32 32l82.7 0L201.4 265.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L448 109.3l0 82.7c0 17.7 14.3 32 32 32s32-14.3 32-32l0-160c0-17.7-14.3-32-32-32L320 0zM80 32C35.8 32 0 67.8 0 112L0 432c0 44.2 35.8 80 80 80l320 0c44.2 0 80-35.8 80-80l0-112c0-17.7-14.3-32-32-32s-32 14.3-32 32l0 112c0 8.8-7.2 16-16 16L80 448c-8.8 0-16-7.2-16-16l0-320c0-8.8 7.2-16 16-16l112 0c17.7 0 32-14.3 32-32s-14.3-32-32-32L80 32z"/>
</svg>
</button>
</div>
<embed
[src]="scannedUrl | safe" type="application/pdf" width="100%" height="100%"/>
</div>
</div>
</div>
<div class="w-full flex mb-2 flex-col gap-4 mt-12 items-center justify-center">
<div class="w-auto px-5 py-2 border-2 border-solid border-[#39B7FA] rounded-md">
Compliance score :
<span class="font-semibold">
{{ score() }}%
</span>
</div>
<button (click)="startScan()"
class="primary-button transition duration-700 ease-in-out
p-2 rounded-xl">
Retry
</button>
</div>
</div>
</div>
<app-reader-dialog></app-reader-dialog>
import {ChangeDetectorRef, Component, OnInit} from '@angular/core';
import {ScannerService} from "../scanner.service";
import {ActivatedRoute, Router} from "@angular/router";
import {LoaderService} from "../../../core/services/loader.service";
@Component({
selector: 'app-scan-completed',
templateUrl: './scan-completed.component.html'
})
export class ScanCompletedComponent implements OnInit {
constructor(private service: ScannerService,
private route: ActivatedRoute,
private loaderService: LoaderService,
private changeDetector: ChangeDetectorRef,
private router: Router) {
}
get originalUrl(): string {
return this.service.originalUrl;
}
set originalUrl(value: string) {
this.service.originalUrl = value;
}
get scannedUrl(): string {
return this.service.scannedUrl;
}
set scannedUrl(value: string) {
this.service.scannedUrl = value;
}
get showDialog(): boolean {
return this.service.showDialog;
}
set showDialog(value: boolean) {
this.service.showDialog = value;
}
startScan() {
this.router.navigate(['/pdf-scanner'])
}
ngOnInit() {
const originName: string = this.route.snapshot.params['origin']
const scannedName: string = this.route.snapshot.params['scanned']
if (originName) {
this.service.getFileByName(originName)
.subscribe(response => {
console.log(response)
this.savePDF(response, 'ORIGINAL')
})
}
if (scannedName) {
this.service.getFileByName(scannedName)
.subscribe(response => {
console.log(response)
console.log(response)
this.savePDF(response, 'SCANNED')
})
}
const interval = setInterval(() => {
this.loaderService.hide()
clearInterval(interval)
}, 2000)
}
private async readPdfFile(file: File, type: string) {
try {
const arrayBuffer = await file.arrayBuffer(); // Await the promise here
const blob = new Blob([arrayBuffer], {type: 'application/pdf'});
const fileUrl = URL.createObjectURL(blob);
if (type === 'ORIGINAL') {
this.originalUrl = fileUrl;
} else if (type === 'SCANNED') {
this.scannedUrl = fileUrl;
}
console.log(fileUrl);
// Trigger change detection if necessary
this.changeDetector.detectChanges();
} catch (error) {
console.error('Error reading PDF file:', error);
}
}
savePDF(pdfBlob: Blob, type: string) {
const file = new Blob([pdfBlob], {type: 'application/pdf'});
const fileURL = URL.createObjectURL(file);
// Storing the PDF in an object
if (type === 'ORIGINAL') {
this.originalUrl = fileURL;
} else if (type === 'SCANNED') {
this.scannedUrl = fileURL;
}
// You can now use `pdfObject` to manipulate the PDF.
}
openDialog() {
this.showDialog = true
}
score(): string {
const score = localStorage.getItem('score')
if (score)
return score
else return '100';
}
}
import {Injectable} from '@angular/core';
import {HttpClient, HttpHeaders} from "@angular/common/http";
import {environment} from "../../../environments/environment";
import {Observable} from "rxjs";
import {ScanResponse} from "../../core/models/scan.response.model";
@Injectable({
providedIn: 'root'
})
export class ScannerService {
URL: string = environment.BASE_URL
private _originalFile: File | null = null
private _scannedFile: File | null = null
private _showDialog: boolean = false
private _originalUrl: string = ''
private _scannedUrl: string = ''
private _originalFileValidated: boolean | null = null
private _scannedFileValidated: boolean | null = null
constructor(private http: HttpClient) {
}
get originalFileValidated(): boolean | null {
return this._originalFileValidated;
}
set originalFileValidated(value: boolean | null) {
this._originalFileValidated = value;
}
get scannedFileValidated(): boolean | null {
return this._scannedFileValidated;
}
set scannedFileValidated(value: boolean | null) {
this._scannedFileValidated = value;
}
get originalUrl(): string {
return this._originalUrl;
}
set originalUrl(value: string) {
this._originalUrl = value;
}
get scannedUrl(): string {
return this._scannedUrl;
}
set scannedUrl(value: string) {
this._scannedUrl = value;
}
get showDialog(): boolean {
return this._showDialog;
}
set showDialog(value: boolean) {
this._showDialog = value;
}
get originalFile(): File | null {
return this._originalFile;
}
set originalFile(value: File | null) {
this._originalFile = value;
}
get scannedFile(): File | null {
return this._scannedFile;
}
set scannedFile(value: File | null) {
this._scannedFile = value;
}
public scanFile(original: File, scanned: File): Observable<ScanResponse> {
const formData = new FormData();
formData.set('original_pdf', original);
formData.set('scanned_pdf', scanned);
// @ts-ignore
return this.http.post<ScanResponse>(`${this.URL}process_pdfs`, formData)
}
public getFileByName(fileName: string): Observable<Blob> {
const headers = new HttpHeaders({
'ngrok-skip-browser-warning': 'true'
});
// @ts-ignore
return this.http.get<Blob>(`${this.URL}download/outputs/${fileName}`,
{
headers: headers,
responseType: 'blob' as 'json'
})
}
}
<div class="w-full px-5 flex items-center justify-center">
<div class="w-full max-w-6xl flex flex-col items-center justify-center">
<div class="w-full my-12 text-center text-2xl font-semibold">
Contract Compliance
</div>
<div class="w-full grid grid-cols-1 gap-4 md:grid-cols-2 md:gap-8">
<div class="flex flex-col gap-2 items-start justify-center">
<p>Original document :</p>
<div class="w-full hover:shadow-2xl hover:border-[3px]
hover:shadow-blue-500/50 hover:animate-pulse
h-72 border border-dashed p-4 rounded-md
flex flex-col items-center justify-center"
[ngClass]="{
'border-red-500': originalFileValidated === false,
'border-[#189A2E]': originalFileValidated === true,
'border-[#DEDCDC]': originalFileValidated === null
}"
(drop)="onFileDropped($event,'ORIGINAL')"
(dragover)="onDragOver($event)">
<input
type="file"
accept="application/pdf"
class="hidden"
#originalFileInput
(change)="onFileSelected($event,'ORIGINAL')"
/>
<div class="text-center cursor-pointer" (click)="originalFileInput.click()">
<img
ngSrc="{{originalFileValidated === true ? '/assets/icons/doc-verified.png':'/assets/icons/file.svg'}}"
alt="Upload Icon"
class="mx-auto"
height="87" width="86"/>
<p [ngClass]="originalFileValidated === true ? 'text-[#189A2E]':'text-gray-500'"
class="mt-2">
{{ originalFileValidated === true ? originalFile?.name : 'Drag and drop choose file to upload your PDF file.' }}
</p>
</div>
</div>
<div *ngIf="originalFileValidated === false" class="w-full text-center font-semibold text-red-500">
Field original document is required!
</div>
</div>
<div class="flex flex-col gap-2 items-start justify-center">
<p>Scanned document :</p>
<div class="w-full hover:shadow-2xl hover:border-[3px] hover:shadow-blue-500/50
hover:animate-pulse
h-72 border border-dashed p-4 rounded-md
flex flex-col items-center justify-center"
[ngClass]="{
'border-red-500': scannedFileValidated === false,
'border-[#189A2E]': scannedFileValidated === true,
'border-[#DEDCDC]': scannedFileValidated === null
}"
(drop)="onFileDropped($event,'SCANNED')"
(dragover)="onDragOver($event)">
<input
type="file"
accept="application/pdf"
class="hidden"
#scannedFileInput
(change)="onFileSelected($event,'SCANNED')"
/>
<div class="text-center cursor-pointer" (click)="scannedFileInput.click()">
<img
ngSrc="{{scannedFileValidated === true ? '/assets/icons/doc-verified.png':'/assets/icons/file.svg'}}"
alt="Upload Icon"
class="mx-auto"
height="87" width="86"/>
<p [ngClass]="scannedFileValidated === true ? 'text-[#189A2E]':'text-gray-500'"
class="mt-2">
{{ scannedFileValidated === true ? scannedFile?.name : 'Drag and drop choose file to upload your PDF file.' }}
</p>
</div>
</div>
<div *ngIf="scannedFileValidated === false" class="w-full text-center font-semibold text-red-500">
Field scanned document is required!
</div>
</div>
</div>
<div class="w-full flex mt-10 mb-4 items-center justify-center">
<button (click)="startScan()"
class="primary-button transition duration-700 ease-in-out
p-2 rounded-xl">
Start scan
</button>
</div>
</div>
</div>
import {Component} from '@angular/core';
import {MessageService} from "primeng/api";
import {Router} from "@angular/router";
import {ScannerService} from "../scanner.service";
import {LoaderService} from "../../../core/services/loader.service";
@Component({
selector: 'app-scanner',
templateUrl: './scanner.component.html'
})
export class ScannerComponent {
constructor(private messageService: MessageService,
private loaderService: LoaderService,
private service: ScannerService,
private router: Router) {
}
get originalFileValidated(): boolean | null {
return this.service.originalFileValidated;
}
set originalFileValidated(value: boolean | null) {
this.service.originalFileValidated = value;
}
get scannedFileValidated(): boolean | null {
return this.service.scannedFileValidated;
}
set scannedFileValidated(value: boolean | null) {
this.service.scannedFileValidated = value;
}
get originalFile(): File | null {
return this.service.originalFile;
}
set originalFile(value: File | null) {
this.service.originalFile = value;
}
get scannedFile(): File | null {
return this.service.scannedFile;
}
set scannedFile(value: File | null) {
this.service.scannedFile = value;
}
get originalUrl(): string {
return this.service.originalUrl;
}
set originalUrl(value: string) {
this.service.originalUrl = value;
}
get scannedUrl(): string {
return this.service.scannedUrl;
}
set scannedUrl(value: string) {
this.service.scannedUrl = value;
}
onFileSelected(event: any, type: string): void {
const file: File = event.target.files[0];
//accept only pdf files
if (file && file.type === 'application/pdf') {
this.handleFile(file, type)
} else {
this.messageService.add({
severity: 'warn',
summary: 'warning',
detail: 'Only pdf file allowed.'
});
}
}
onFileDropped(event: DragEvent, type: string): void {
event.preventDefault();
const file = event.dataTransfer?.files[0];
//accept only pdf files
if (file && file.type === 'application/pdf') {
this.handleFile(file, type)
} else {
this.messageService.add({
severity: 'warn',
summary: 'warning',
detail: 'Only pdf file allowed.'
});
}
}
handleFile(file: File, type: string) {
if (type === 'ORIGINAL') {
this.originalFileValidated = true
this.originalFile = file
}
if (type === 'SCANNED') {
this.scannedFileValidated = true
this.scannedFile = file
}
}
onDragOver(event: DragEvent): void {
event.preventDefault();
}
startScan() {
// check if the original file is not empty
if (this.originalFile === null) {
this.originalFileValidated = false
return
}
// check if the scanned file is not empty
if (this.scannedFile === null) {
this.scannedFileValidated = false
return
}
//show loader
this.loaderService.show()
//scan the two files
this.service.scanFile(this.originalFile, this.scannedFile)
.subscribe(res => {
console.log(res)
this.loaderService.hide()
if (res?.statuscode === '000') {
localStorage.setItem('score', res.Score)
this.router.navigate(['scan-completed/' + res?.original_pdf?.filename + '/' + res?.scanned_pdf?.filename])
} else {
this.loaderService.hide()
this.messageService.add({
severity: 'error',
summary: 'Error',
detail: res?.message
})
}
}, error => {
this.loaderService.hide()
console.log(error)
this.messageService.add({
severity: 'error',
summary: 'Error',
detail: error?.error?.message || 'something went wrong.'
})
})
}
/**
* takes as parameter Blob and generate url for the file
* @param pdfBlob
*/
savePDF(pdfBlob: Blob) {
const file = new Blob([pdfBlob], {type: 'application/pdf'});
const fileURL = URL.createObjectURL(file);
this.originalUrl = fileURL
this.scannedUrl = fileURL
this.router.navigate(['/scanner-completed/view'])
}
}
<svg width="86" height="87" viewBox="0 0 86 87" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<rect y="1" width="74" height="74" fill="url(#pattern0_1_6)"/>
<defs>
<pattern id="pattern0_1_6" patternContentUnits="objectBoundingBox" width="1" height="1">
<use xlink:href="#image0_1_6" transform="scale(0.00390625)"/>
</pattern>
<image id="image0_1_6" width="256" height="256" xlink:href="data:image/png;base64,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"/>
</defs>
</svg>
{"nm":"Comp 1","ddd":0,"h":500,"w":500,"meta":{"g":"LottieFiles AE "},"layers":[{"ty":4,"nm":"Shape Layer 2","sr":1,"st":0,"op":125,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[-146.25,68.75,0],"ix":1},"s":{"a":0,"k":[374.035,374.035,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0.667,"y":1},"s":[292.879,246.15,0],"t":0,"ti":[0,0,0],"to":[-17.836,0,0]},{"o":{"x":0.333,"y":0},"i":{"x":0.667,"y":1},"s":[185.86,246.15,0],"t":11.5,"ti":[-17.836,0,0],"to":[0,0,0]},{"s":[292.879,246.15,0],"t":23}],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Ellipse 1","ix":1,"cix":2,"np":3,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[7.594,0],[0,-7.594],[-7.594,0],[0,7.594]],"o":[[-7.594,0],[0,7.594],[7.594,0],[0,-7.594]],"v":[[0,-13.75],[-13.75,0],[0,13.75],[13.75,0]]},"ix":2}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[0.2235,0.7176,0.9804],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[-146.25,68.75],"ix":2},"r":{"a":0,"k":-9.395,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":1},{"ty":4,"nm":"Shape Layer 1","sr":1,"st":0,"op":125,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[-146.25,68.75,0],"ix":1},"s":{"a":0,"k":[374.035,374.035,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0.667,"y":1},"s":[188.879,246.15,0],"t":0,"ti":[0,0,0],"to":[17.002,0,0]},{"o":{"x":0.333,"y":0},"i":{"x":0.667,"y":1},"s":[290.893,246.15,0],"t":11.5,"ti":[17.002,0,0],"to":[0,0,0]},{"s":[188.879,246.15,0],"t":23}],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Ellipse 1","ix":1,"cix":2,"np":3,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[7.594,0],[0,-7.594],[-7.594,0],[0,7.594]],"o":[[-7.594,0],[0,7.594],[7.594,0],[0,-7.594]],"v":[[0,-13.75],[-13.75,0],[0,13.75],[13.75,0]]},"ix":2}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[0.0902,0.3608,0.5765],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[-146.25,68.75],"ix":2},"r":{"a":0,"k":-9.395,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":2},{"ty":4,"nm":"Shape Layer 3","sr":1,"st":0,"op":125,"ip":125,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[1,8,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[251,258,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Rectangle 1","ix":1,"cix":2,"np":3,"it":[{"ty":"rc","bm":0,"hd":false,"mn":"ADBE Vector Shape - Rect","nm":"Rectangle Path 1","d":1,"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"s":{"a":0,"k":[518,524],"ix":2}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[0.2235,0.7176,0.9804],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[1,8],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":3}],"v":"4.8.0","fr":25,"op":23,"ip":0,"assets":[]}
\ No newline at end of file
<svg width="119" height="45" viewBox="0 0 119 45" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M17.8612 37.9483C21.2374 37.9483 24.6136 37.9207 27.9882 37.9571C30.6091 37.9859 31.7356 36.9945 31.7927 35.4446C31.8546 33.7391 30.2204 32.5155 27.9152 32.5005C24.1376 32.4766 20.3585 32.5005 16.5809 32.4779C11.5262 32.4465 7.9596 30.3607 6.87916 26.4992C6.14776 23.8901 6.10651 21.1932 7.47729 18.6532C8.7735 16.2524 11.2184 15.0439 14.4708 15.0112C20.23 14.9535 25.9923 14.9661 31.7515 14.9974C35.9352 15.02 39.0274 17.3354 39.4208 20.6134C39.4811 21.1141 39.121 21.0363 38.7545 21.0363C36.2144 21.0338 33.6759 21.0301 31.1359 21.0301C26.8316 21.0301 22.5257 21.0301 18.2214 21.0301C16.0573 21.0301 14.7421 21.9449 14.7119 23.4647C14.6802 25.0723 15.9828 26.1553 18.1373 26.1867C22.0688 26.2444 26.0034 26.2193 29.9349 26.2771C33.9583 26.3361 36.9998 27.704 38.7989 30.6218C39.4192 31.6283 39.6509 32.7163 39.7128 33.8182C39.8444 36.1675 40.0158 38.5469 38.4435 40.6828C36.7919 42.9255 34.3502 44.2507 30.9756 44.2633C25.3386 44.2833 19.7032 44.2695 14.0662 44.272C11.6943 44.272 9.61119 43.7425 8.09287 42.2114C7.05685 41.166 6.56026 39.9474 6.34449 38.641C6.25723 38.1076 6.40637 37.9069 7.17584 37.9144C10.7361 37.952 14.2979 37.9307 17.8596 37.9307V37.9495L17.8612 37.9483Z" fill="#FAFAFB"/>
<path d="M82.6718 16.7844C78.312 20.5958 74.0077 24.3807 69.6605 28.1343C69.064 28.6489 69.5764 28.8773 69.8842 29.1521C72.4037 31.4111 74.9405 33.6562 77.4743 35.9051C80.4395 38.538 83.4048 41.1697 86.3684 43.8026C86.4874 43.908 86.5985 44.0197 86.8539 44.2619C84.5994 44.2619 82.5163 44.2619 80.4332 44.2619C80.1333 44.2619 80.0238 44.0586 79.8684 43.9218C74.2171 38.9898 68.6658 33.9863 63.1414 28.9639C62.8399 28.6903 62.6242 28.497 63.0494 28.1243C67.882 23.8913 72.694 19.6445 77.4949 15.3902C77.8407 15.0839 78.1977 14.9848 78.6959 14.9861C82.5369 14.9961 86.3764 14.9999 90.2174 14.9735C90.8504 14.9697 91.2011 15.1203 91.5311 15.5558C94.3678 19.3182 96.9745 23.1822 99.6907 26.9973C99.7637 27.1003 99.8557 27.1956 100.003 27.3726C100.917 26.0636 101.785 24.8062 102.67 23.5562C104.476 21.0036 106.305 18.4611 108.091 15.8997C108.544 15.2509 109.043 14.9271 110.086 14.9597C112.743 15.0413 115.409 14.9873 118.128 14.9873C117.996 15.5407 117.576 15.9361 117.259 16.364C112.948 22.1569 108.632 27.9486 104.303 33.734C104.036 34.0892 103.943 34.4393 103.944 34.8421C103.955 37.7825 103.936 40.7217 103.963 43.6621C103.968 44.1314 103.835 44.2895 103.208 44.2808C101.103 44.2481 98.9958 44.2381 96.8904 44.2782C96.205 44.2908 96.0781 44.1076 96.0797 43.6219C96.0924 40.6828 96.0416 37.7424 96.0876 34.8032C96.0971 34.1544 95.7576 33.6662 95.3848 33.1755C92.5655 29.4684 89.7256 25.7712 86.8841 22.0741C85.7433 20.5907 84.5868 19.1162 83.4286 17.6403C83.2033 17.3529 82.9431 17.0844 82.675 16.7807L82.6718 16.7844Z" fill="#FAFAFB"/>
<path d="M51.9072 25.4123C53.7587 23.5537 55.6022 21.6901 57.4632 19.8378C58.9625 18.3431 60.4825 16.8622 61.9897 15.3726C62.2292 15.1366 62.4688 14.981 62.9083 14.9835C65.8799 15.0024 68.8531 14.9936 71.8834 14.9936C71.8215 15.3588 71.4852 15.5533 71.2424 15.7792C66.8509 19.8591 62.4625 23.9402 58.0392 27.9988C57.4553 28.5347 57.5045 28.8823 58.0677 29.3981C63.0796 33.9938 68.0598 38.6108 73.0479 43.2241C73.3684 43.5202 73.6698 43.8277 73.9776 44.1264C73.8206 44.3535 73.5762 44.2544 73.3906 44.2557C70.6966 44.2669 68.0027 44.2582 65.3087 44.2757C64.8708 44.2782 64.5868 44.1841 64.306 43.9055C61.0314 40.6539 57.7393 37.4136 54.4472 34.1732C54.2188 33.9486 54.0252 33.6901 53.6777 33.5558C53.6254 33.5947 53.5826 33.6286 53.5381 33.6612C51.9183 34.8635 51.3915 36.3217 51.5597 38.0737C51.7326 39.8758 51.5518 41.698 51.639 43.5077C51.6724 44.208 51.3709 44.3058 50.6078 44.2895C48.6896 44.2481 46.7667 44.2368 44.8486 44.2807C44.0823 44.2983 43.8824 44.1465 43.884 43.529C43.9125 34.9312 43.903 26.3335 43.903 17.7357C43.903 17.0254 43.9252 16.3138 43.8856 15.6047C43.8618 15.1642 43.9538 14.9635 44.6186 14.9773C46.6922 15.0187 48.7674 15.0111 50.8426 14.9886C51.428 14.9823 51.6136 15.0814 51.6073 15.5872C51.5787 18.5263 51.6073 21.4654 51.6216 24.4046C51.6216 24.7171 51.6549 25.0283 51.6723 25.3395C51.7517 25.3634 51.831 25.3872 51.9103 25.4123H51.9072Z" fill="#FAFAFB"/>
<path d="M31.0567 0.701859C36.7381 0.701859 42.4179 0.701859 48.0994 0.701859C49.0085 0.701859 49.7034 0.976695 49.9842 1.71964C50.2349 2.37975 49.9778 2.93947 49.2956 3.32725C48.8562 3.57825 48.3056 3.63597 47.7646 3.63597C36.5557 3.63848 25.3467 3.64099 14.1377 3.63848C12.8844 3.63848 11.9911 2.9357 11.9959 1.98694C12.0007 1.16369 12.7622 0.696838 14.106 0.696838C19.7557 0.696838 25.407 0.696838 31.0567 0.696838V0.703112V0.701859Z" fill="#FAFAFB"/>
<path d="M38.8736 6.85142C44.555 6.85142 50.2349 6.85142 55.9163 6.85142C56.8254 6.85142 57.5203 7.12627 57.8011 7.86921C58.0518 8.52932 57.7948 9.08903 57.1125 9.47682C56.6731 9.72781 56.1225 9.78554 55.5815 9.78554C44.3726 9.78805 33.1636 9.79056 21.9546 9.78805C20.7013 9.78805 19.808 9.08526 19.8128 8.13651C19.8176 7.31325 20.5791 6.84641 21.9229 6.84641C27.5726 6.84641 33.2239 6.84641 38.8736 6.84641V6.85268V6.85142Z" fill="#FAFAFB"/>
<path d="M5.74183 3.85815C4.29807 3.8067 3.19224 2.89057 3.2795 1.81883C3.36518 0.758383 4.55033 -0.0548356 5.92587 0.00289291C7.25063 0.0593664 8.27078 0.956669 8.21367 2.01586C8.15496 3.11647 7.09515 3.9071 5.74341 3.85941L5.74183 3.85815Z" fill="#39B7FA"/>
<path d="M11.0774 6.59396C12.5021 6.60651 13.5127 7.42224 13.4984 8.54795C13.4842 9.57451 12.3609 10.4291 11.0393 10.4179C9.65423 10.4053 8.57855 9.55318 8.58013 8.47014C8.58172 7.36201 9.62249 6.58016 11.0774 6.59271V6.59396Z" fill="#39B7FA"/>
<path d="M0 8.43745C0.0190386 7.31677 0.988419 6.5801 2.41948 6.59892C3.79978 6.61775 4.89609 7.51254 4.84373 8.57675C4.79613 9.54308 3.65382 10.4052 2.40838 10.4153C1.07251 10.4266 -0.0174505 9.52927 0.0015881 8.4362L0 8.43745Z" fill="#39B7FA"/>
</svg>
const url = 'https://741d-102-50-242-63.ngrok-free.app/'
export const environment = {
production: true,
BASE_URL: url,
}
const url = 'https://741d-102-50-242-63.ngrok-free.app/'
export const environment = {
production: false,
BASE_URL: url,
}
/* You can add global styles to this file, and also import other style files */ @import "primeng/resources/themes/lara-light-blue/theme.css";
@import "primeng/resources/primeng.css";
@tailwind base;
@tailwind components;
@tailwind utilities;
body {
margin: 0 !important;
}
.bg-primary {
background-color: #052C40;;
}
.primary-button {
background-color: #116B9A;
color: white;
padding: 10px 20px;
border-radius: 8px;
}
.primary-button:hover {
background-color: white;
color: #116B9A;
border: 1px solid #116B9A;
padding: 10px 20px;
border-radius: 8px;
}
.loader-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgb(0 0 0 / 31%);
display: flex;
justify-content: center;
align-items: center;
z-index: 9999;
}
ng-lottie {
width: 100px;
height: 100px;
}
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
"./src/**/*.{html,ts}",
],
theme: {
extend: {},
},
plugins: [],
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment