Contract Signing and contract printing

This commit is contained in:
2023-03-08 21:59:10 +01:00
parent eaa79c3541
commit 5605ee9497
10 changed files with 230 additions and 46 deletions

View File

@@ -1,7 +1,7 @@
import {Component, Input, OnInit} from '@angular/core';
import { fabric } from 'fabric';
import {ActivatedRoute, ParamMap} from "@angular/router";
import {DomSanitizer} from "@angular/platform-browser";
import { Component, Input, OnInit } from '@angular/core';
import { ActivatedRoute, ParamMap } from "@angular/router";
import { DomSanitizer } from "@angular/platform-browser";
import { ImageUploaderCrudService } from "@common/crud/crud.service";
export class BaseContractsComponent {
@@ -24,9 +24,36 @@ export class ContractsNewComponent extends BaseContractsComponent {
}
@Component({
templateUrl: '../base-view/templates/card.template.html'
template:`
<label>Download Link:</label>
<div class="input-group mb-12">
<span class="input-group-text"><a href="{{ this.contractPrintLink! }}" target="_blank">{{ this.contractPrintLink! }}&nbsp;</a></span>
<button type="button" class="btn btn-light" [cdkCopyToClipboard]="this.contractPrintLink!"><i-bs name="text-paragraph"/></button>
</div>
<base-card
[resource_id]="this.resource_id"
[resource]="this.resource"
[schema]="this.schema">
</base-card>
`,
})
export class ContractsCardComponent extends BaseContractsComponent{
resource_id: string | null = null;
contractPrintLink: string | null = null;
constructor(
private route: ActivatedRoute
) {
super()
}
ngOnInit(): void {
if (this.resource_id === null) {
this.route.paramMap.subscribe((params: ParamMap) => {
this.resource_id = params.get('id')
this.contractPrintLink = `${location.origin}/api/v1/contract/print/pdf/${this.resource_id}`
})
}
}
}
@Component({
@@ -47,7 +74,17 @@ export class ContractsCardComponent extends BaseContractsComponent{
<span>Signature</span>
</ng-template>
<ng-template ngbPanelContent>
<signature-drawer></signature-drawer>
<ng-container *ngIf="this.affixed">This Contract has already been signed by {{ this.signatory }}</ng-container>
<div class="row" *ngIf="!this.affixed">
<signature-drawer class="col-7"
(signatureDrawn$)="postSignature($event)"></signature-drawer>
<div class="col-5">
<p>Cette page est à la destination exclusive de <strong>{{ this.signatory }}</strong></p>
<p>Si vous n'êtes <strong>pas</strong> {{ this.signatory }}, veuillez <strong>fermer cette page immédiatement</strong> et surpprimer tous les liens en votre possession menant vers celle-ci.</p>
<p>En vous maintenant et/ou en interagissant avec cette page, vous enfreignez l'article L.229 du code pénal de l'Etat de San Andreas pour <strong>usurpation d'identité</strong> et vous vous exposez ainsi à une amende de 20 000$ ainsi qu'à des poursuites civiles.</p>
<p>Le cabinet Cooper, Hillman & Toshi LLC</p>
</div>
</div>
</ng-template>
</ngb-panel>
</ngb-accordion>
@@ -55,18 +92,41 @@ export class ContractsCardComponent extends BaseContractsComponent{
})
export class ContractsSignatureComponent implements OnInit {
signature_id: string | null = null;
signature: any = {}
signatory = ""
affixed = false;
constructor(
private route: ActivatedRoute,
private sanitizer: DomSanitizer
private route: ActivatedRoute,
private sanitizer: DomSanitizer,
private crudService: ImageUploaderCrudService,
) {}
ngOnInit() {this.route.paramMap.subscribe((params: ParamMap) => {
this.signature_id = params.get('id')
})
ngOnInit() {
this.route.paramMap.subscribe((params: ParamMap) => {
this.signature_id = params.get('id');
this.crudService.get('contract/signature', this.signature_id!).subscribe( (response:any) => {
this.signature = response;
this.affixed = this.signature.signature_affixed;
if (this.signature.representative) {
this.signatory = this.signature.representative.entity_data.firstname + " " + this.signature.representative.entity_data.lastname;
} else {
this.signatory = this.signature.entity.entity_data.firstname + " " + this.signature.entity.entity_data.lastname;
}
})
})
}
getPreview() {
return this.sanitizer.bypassSecurityTrustResourceUrl("/api/v1/contract/print/preview/" + this.signature_id);
}
postSignature(image: string) {
this.crudService.upload('contract/signature', this.signature_id!, image).subscribe((v: any) => {
if (v) {
this.affixed = true;
}
})
}
}

View File

@@ -7,12 +7,13 @@ import { DraftsCardComponent, DraftsListComponent, DraftsNewComponent, DraftsNew
import { FormlyModule } from "@ngx-formly/core";
import { FormlyBootstrapModule } from "@ngx-formly/bootstrap";
import { ForeignkeyTypeComponent } from "@common/crud/types/foreignkey.type";
import { CrudService } from "@common/crud/crud.service";
import { CrudService, ImageUploaderCrudService } from "@common/crud/crud.service";
import { NgbAccordionModule, NgbCollapseModule } from "@ng-bootstrap/ng-bootstrap";
import { allIcons, NgxBootstrapIconsModule } from "ngx-bootstrap-icons";
import { ContractsCardComponent, ContractsListComponent, ContractsNewComponent, ContractsSignatureComponent } from "../contracts/contracts.component";
import { AlphaRangeComponent, BlackBlueRangeComponent, SignatureDrawerComponent } from "./signature-drawer/signature-drawer.component";
import { ClipboardModule } from "@angular/cdk/clipboard";
@NgModule({
@@ -29,6 +30,7 @@ import { AlphaRangeComponent, BlackBlueRangeComponent, SignatureDrawerComponent
]
}),
FormlyBootstrapModule,
ClipboardModule,
],
declarations: [
DraftsListComponent,
@@ -43,7 +45,7 @@ import { AlphaRangeComponent, BlackBlueRangeComponent, SignatureDrawerComponent
BlackBlueRangeComponent,
AlphaRangeComponent
],
providers: [CrudService]
providers: [CrudService, ImageUploaderCrudService]
})
export class ContractsModule {
}

View File

@@ -1,8 +1,8 @@
<div class="row align-items-start">
<canvas id="signatureCanvas" class="col" width="320" height="320"></canvas>
<div class="col-sm-2">
<canvas id="signatureCanvas" class="col-9" width="320" height="320"></canvas>
<div class="col-3" style="width: 90px">
<div class="card">
<span class="btn btn-light btn-file">
<i-bs name="image-fill"></i-bs><input #imageInput type="file" accept="image/png, image/gif, image/jpeg, image/bmp" (change)="addImage($event)">
@@ -13,7 +13,6 @@
<alpha-range (change)="updateAlpha($event)"></alpha-range>
</div>
</div>
<div class="card">
<button
type="button"
@@ -37,7 +36,11 @@
</div>
</div>
</div>
<button class="btn btn-primary">Sign!</button>
<button
type="button"
class="btn btn-primary"
(click)="sign()"
>Sign!</button>
<button
type="button"
class="btn btn-danger"

View File

@@ -8,6 +8,8 @@ import { fabric } from 'fabric';
})
export class SignatureDrawerComponent implements OnInit
{
@Output() signatureDrawn$ = new EventEmitter<string>()
size = 320;
canvas: any;
isEditImage = false;
@@ -26,6 +28,14 @@ export class SignatureDrawerComponent implements OnInit
'selection:updated': function() {self.handleElement()},
'selection:created': function() {self.handleElement()}
});
const image = localStorage.getItem('signature_image');
if (image) {
fabric.Image.fromURL(image , function(img: any) {
self.canvas.add(img);
self.canvas.renderAll();
})
}
}
toggleDrawing() {
@@ -160,6 +170,15 @@ export class SignatureDrawerComponent implements OnInit
clear() {
this.canvas.clear();
}
sign() {
const image = this.canvas.toDataURL({
format: 'png',
quality: 0.8
});
localStorage.setItem('signature_image', image);
this.signatureDrawn$.next(image)
}
}
@Component({
@@ -222,4 +241,4 @@ export class AlphaRangeComponent implements OnInit
this.change.emit(this.value)
}
}
}

View File

@@ -15,7 +15,7 @@ import { ArrayTypeComponent } from "./types/array.type";
import { ObjectTypeComponent } from "./types/object.type";
import { DatetimeTypeComponent } from "./types/datetime.type";
import { DateTypeComponent } from "./types/date.type";
import { ApiService, CrudService } from "./crud.service";
import { ApiService, CrudService, ImageUploaderCrudService } from "./crud.service";
import { CrudFormlyJsonschemaService } from "./crud-formly-jsonschema.service";
import { NgbModule} from "@ng-bootstrap/ng-bootstrap";
import { allIcons, NgxBootstrapIconsModule } from "ngx-bootstrap-icons";
@@ -49,6 +49,7 @@ import { ClipboardModule } from '@angular/cdk/clipboard';
JsonschemasService,
ApiService,
CrudService,
ImageUploaderCrudService,
CrudFormlyJsonschemaService,
DictionaryService
],

View File

@@ -116,3 +116,28 @@ export class CrudService extends ApiService {
);
}
}
@Injectable()
export class ImageUploaderCrudService extends CrudService {
public upload(resource: string, signature_id: string, image: string) {
const formData: FormData = new FormData();
formData.append("signature_file", dataURIToBlob(image), signature_id + ".png");
return this.http.post<{ menu: [{}] }>(
`${this.api_root}/${resource.toLowerCase()}/${signature_id}`,
formData
);
}
}
function dataURIToBlob(dataURI: string) {
const splitDataURI = dataURI.split(',')
const byteString = splitDataURI[0].indexOf('base64') >= 0 ? atob(splitDataURI[1]) : decodeURI(splitDataURI[1])
const mimeString = splitDataURI[0].split(':')[1].split(';')[0]
const ia = new Uint8Array(byteString.length)
for (let i = 0; i < byteString.length; i++)
ia[i] = byteString.charCodeAt(i)
return new Blob([ia], { type: mimeString })
}