diff --git a/EnvelopeGenerator.Form/frmFieldEditor.vb b/EnvelopeGenerator.Form/frmFieldEditor.vb index bda3bef0..210b65e1 100644 --- a/EnvelopeGenerator.Form/frmFieldEditor.vb +++ b/EnvelopeGenerator.Form/frmFieldEditor.vb @@ -19,6 +19,10 @@ Partial Public Class frmFieldEditor Public Property SelectedReceiver As EnvelopeReceiver = Nothing Public Property State As State + Private Const SIGNATURE_LABEL = "Signatur" + Private Const SIGNATURE_WIDTH As Single = 1 + Private Const SIGNATURE_HEIGHT As Single = 0.5 + Public Sub New() InitializeComponent() End Sub @@ -118,7 +122,7 @@ Partial Public Class frmFieldEditor AddHandler GDViewer.BeforeAnnotationAddedByUser, AddressOf Viewer_BeforeAnnotationAddedByUser AddHandler GDViewer.AnnotationAddedByUser, AddressOf Viewer_AnnotationAddedByUser - GDViewer.AddStickyNoteAnnotationInteractive("SIGNATUR", Color.Black, "Arial", FontStyle.Regular, 10, 1, 0) + GDViewer.AddStickyNoteAnnotationInteractive(SIGNATURE_LABEL, Color.Black, "Arial", FontStyle.Regular, 10, 1, 0) End If @@ -131,8 +135,8 @@ Partial Public Class frmFieldEditor If TypeOf oAnnotation Is AnnotationStickyNote Then Dim oStickyNote As AnnotationStickyNote = oAnnotation - oStickyNote.Width = 1 - oStickyNote.Height = 1 + oStickyNote.Width = SIGNATURE_WIDTH + oStickyNote.Height = SIGNATURE_HEIGHT oStickyNote.Tag = oTag ApplyAnnotationStyle(oAnnotation) @@ -213,19 +217,6 @@ Partial Public Class frmFieldEditor Next End Sub - - Private Sub ApplyAnnotationStyle(ByRef pAnnotation As Annotation) - If TypeOf pAnnotation Is AnnotationStickyNote Then - Dim oStickyNote As AnnotationStickyNote = pAnnotation - oStickyNote.Fill = True - oStickyNote.FillColor = Color.LightGoldenrodYellow - oStickyNote.Text = "SIGNATUR" - oStickyNote.Alignment = StringAlignment.Center - oStickyNote.LineAlignment = StringAlignment.Center - End If - End Sub - - Private Sub btnDelete_ItemClick(sender As Object, e As ItemClickEventArgs) Handles btnDelete.ItemClick Dim oSelected = GDViewer.GetSelectedAnnotationIdx() @@ -264,8 +255,9 @@ Partial Public Class frmFieldEditor oAnnotation.Left = CSng(pElement.X) oAnnotation.Top = CSng(pElement.Y) oAnnotation.Fill = True - oAnnotation.FillColor = Color.DarkRed - oAnnotation.Text = "SIGNATUR" + oAnnotation.FillColor = Color.Gainsboro + oAnnotation.BorderWidth = 0.01 + oAnnotation.Text = SIGNATURE_LABEL oAnnotation.Tag = GetAnnotationTag(pReceiverId, oPage, pElement.Id) Else Dim oStatus = Manager.GetStat() @@ -274,6 +266,18 @@ Partial Public Class frmFieldEditor End If End Sub + Private Sub ApplyAnnotationStyle(ByRef pAnnotation As Annotation) + If TypeOf pAnnotation Is AnnotationStickyNote Then + Dim oAnnotation As AnnotationStickyNote = pAnnotation + oAnnotation.Fill = True + oAnnotation.FillColor = Color.Gainsboro + oAnnotation.Text = SIGNATURE_LABEL + oAnnotation.Alignment = StringAlignment.Center + oAnnotation.LineAlignment = StringAlignment.Center + oAnnotation.BorderWidth = 0.01 + End If + End Sub + Private Sub ClearAnnotations() Dim oPageCount = GDViewer.PageCount diff --git a/EnvelopeGenerator.Web/Controllers/BaseController.cs b/EnvelopeGenerator.Web/Controllers/BaseController.cs index 168e2607..c310b674 100644 --- a/EnvelopeGenerator.Web/Controllers/BaseController.cs +++ b/EnvelopeGenerator.Web/Controllers/BaseController.cs @@ -9,7 +9,7 @@ namespace EnvelopeGenerator.Web.Controllers { internal DatabaseService database; internal LogConfig logConfig; - internal Logger logger; + public Logger logger; public BaseController(DatabaseService database, LoggingService logging) { diff --git a/EnvelopeGenerator.Web/Controllers/EnvelopeController.cs b/EnvelopeGenerator.Web/Controllers/EnvelopeController.cs index 4c0f8fc4..445f4ff3 100644 --- a/EnvelopeGenerator.Web/Controllers/EnvelopeController.cs +++ b/EnvelopeGenerator.Web/Controllers/EnvelopeController.cs @@ -1,8 +1,6 @@ -using DigitalData.Modules.Logging; -using EnvelopeGenerator.Common; +using EnvelopeGenerator.Common; using EnvelopeGenerator.Web.Services; using Microsoft.AspNetCore.Mvc; -using static EnvelopeGenerator.Web.Constants; namespace EnvelopeGenerator.Web.Controllers { diff --git a/EnvelopeGenerator.Web/Controllers/HistoryController.cs b/EnvelopeGenerator.Web/Controllers/HistoryController.cs index 0f166b58..96d46be5 100644 --- a/EnvelopeGenerator.Web/Controllers/HistoryController.cs +++ b/EnvelopeGenerator.Web/Controllers/HistoryController.cs @@ -2,8 +2,6 @@ using EnvelopeGenerator.Web.Services; using Microsoft.AspNetCore.Mvc; using static EnvelopeGenerator.Common.Constants; -using System; -using static System.Collections.Specialized.BitVector32; namespace EnvelopeGenerator.Web.Controllers { diff --git a/EnvelopeGenerator.Web/Controllers/HomeController.cs b/EnvelopeGenerator.Web/Controllers/HomeController.cs index 34f446ea..737bb872 100644 --- a/EnvelopeGenerator.Web/Controllers/HomeController.cs +++ b/EnvelopeGenerator.Web/Controllers/HomeController.cs @@ -6,21 +6,19 @@ using System.Diagnostics; namespace EnvelopeGenerator.Web.Controllers { - public class HomeController : Controller + public class HomeController : BaseController { private readonly EnvelopeService _envelopeService; - private readonly ILogger _logger; - public HomeController(ILogger logger, EnvelopeService envelopeService) + public HomeController(DatabaseService database, LoggingService logging, EnvelopeService envelopeService): base(database, logging) { _envelopeService = envelopeService; - _logger = logger; } [HttpGet] [Route("/")] public IActionResult Index() - { + { var receiverId = 1; List envelopes = _envelopeService.LoadEnvelopes(receiverId); @@ -29,13 +27,23 @@ namespace EnvelopeGenerator.Web.Controllers [HttpGet] [Route("/EnvelopeKey/{EnvelopeReceiverId}")] - public IActionResult Show() + public IActionResult ShowEnvelope() { ViewData["EnvelopeKey"] = HttpContext.Request.RouteValues["EnvelopeReceiverId"]; return View(); } + [HttpGet] + [Route("/EnvelopeKey/{EnvelopeReceiverId}/Success")] + public IActionResult EnvelopeSigned() + { + ViewData["EnvelopeKey"] = HttpContext.Request.RouteValues["EnvelopeReceiverId"]; + + return View(); + } + + [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] public IActionResult Error() { diff --git a/EnvelopeGenerator.Web/EnvelopeGenerator.Web.csproj b/EnvelopeGenerator.Web/EnvelopeGenerator.Web.csproj index a397157a..fb5ba155 100644 --- a/EnvelopeGenerator.Web/EnvelopeGenerator.Web.csproj +++ b/EnvelopeGenerator.Web/EnvelopeGenerator.Web.csproj @@ -1,4 +1,4 @@ - + net6.0 @@ -12,21 +12,22 @@ + + + + - ..\DDModules\Base\bin\Debug\DigitalData.Modules.Base.dll + ..\..\DDModules\Base\bin\Debug\DigitalData.Modules.Base.dll - ..\DDModules\Config\bin\Debug\DigitalData.Modules.Config.dll + ..\..\DDModules\Config\bin\Debug\DigitalData.Modules.Config.dll - ..\DDModules\Database\bin\Debug\DigitalData.Modules.Database.dll + ..\..\DDModules\Database\bin\Debug\DigitalData.Modules.Database.dll - ..\DDModules\Logging\bin\Debug\DigitalData.Modules.Logging.dll - - - ..\EnvelopeGenerator\EnvelopeGenerator.Common\bin\Debug\EnvelopeGenerator.Common.dll + ..\..\DDModules\Logging\bin\Debug\DigitalData.Modules.Logging.dll diff --git a/EnvelopeGenerator.Web/Views/Home/EnvelopeSigned.cshtml b/EnvelopeGenerator.Web/Views/Home/EnvelopeSigned.cshtml new file mode 100644 index 00000000..a08172c7 --- /dev/null +++ b/EnvelopeGenerator.Web/Views/Home/EnvelopeSigned.cshtml @@ -0,0 +1,21 @@ +@{ + ViewData["Title"] = "Privacy Policy"; +} + +
+
+
+ + + + +
+

Umschlag erfolgreich signiert!

+
+ +
+

Sie haben das Dokument erfolgreich signiert. Im Anschluss erhalten Sie eine schriftliche Bestätigung.

+
+ + +
diff --git a/EnvelopeGenerator.Web/Views/Home/Index.cshtml b/EnvelopeGenerator.Web/Views/Home/Index.cshtml index d66c9c85..e191b918 100644 --- a/EnvelopeGenerator.Web/Views/Home/Index.cshtml +++ b/EnvelopeGenerator.Web/Views/Home/Index.cshtml @@ -11,8 +11,27 @@ } } -@foreach (Envelope envelope in @Model) -{ -
  • @envelope.Title
  • -} +
    +
    + +
    + +
    + Show image + +
    + + + +
    diff --git a/EnvelopeGenerator.Web/Views/Home/Show.cshtml b/EnvelopeGenerator.Web/Views/Home/ShowEnvelope.cshtml similarity index 100% rename from EnvelopeGenerator.Web/Views/Home/Show.cshtml rename to EnvelopeGenerator.Web/Views/Home/ShowEnvelope.cshtml diff --git a/EnvelopeGenerator.Web/wwwroot/css/site.css b/EnvelopeGenerator.Web/wwwroot/css/site.css index e69de29b..6f1d1f67 100644 --- a/EnvelopeGenerator.Web/wwwroot/css/site.css +++ b/EnvelopeGenerator.Web/wwwroot/css/site.css @@ -0,0 +1,34 @@ +/* + Colors taken from: + https://tailwindcss.com/docs/customizing-colors#default-color-palette +*/ + +.button-finish { + transition: background-color linear 300ms; + background-color: #059669; + color: white; + border-left: none; +} + + .button-finish:hover, .button-finish:focus, .button-finish:active { + background-color: #10b981; + color: white; + } + +.button-reset { + transition: background-color linear 300ms; + background-color: #2563eb; + color: white; +} + + .button-reset:hover, .button-reset:focus, .button-reset:active { + background-color: #3b82f6; + color: white; + } + +#page-success header .icon { + display: inline-block; + border-radius: 100px; + padding: 15px; + margin-bottom: 2rem; +} \ No newline at end of file diff --git a/EnvelopeGenerator.Web/wwwroot/js/annotation.js b/EnvelopeGenerator.Web/wwwroot/js/annotation.js index 38fbe031..8fddcad8 100644 --- a/EnvelopeGenerator.Web/wwwroot/js/annotation.js +++ b/EnvelopeGenerator.Web/wwwroot/js/annotation.js @@ -20,7 +20,7 @@ )) ).flatMap((annotations) => annotations.reduce((acc, annotation) => acc.concat(annotation), []) - ).filter((annotation) => !!annotation.isSignature); + ).filter((annotation) => !!annotation.isSignature || annotation.description == "FRAME"); //deleting all Annotations return await instance.delete(pageAnnotations); } @@ -50,9 +50,9 @@ const annotation = this.createSignatureAnnotation(id, width, height, top, left, page) console.log(annotation) - const formField = new SignatureFormField({ + const formField = new PSPDFKit.FormFields.SignatureFormField({ name: id, - annotationIds: List([annotation.id]) + annotationIds: PSPDFKit.Immutable.List([annotation.id]) }) console.log(formField) @@ -64,12 +64,54 @@ id: id, pageIndex: pageIndex, formFieldName: id, - boundingBox: new Rect({ width, height, top, left }) + boundingBox: new PSPDFKit.Geometry.Rect({ width, height, top, left }) }) return annotation } + async createAnnotationFrameBlob(receiverName, width, height) { + const canvas = document.createElement("canvas"); + canvas.width = width; + canvas.height = height; + + const ctx = canvas.getContext("2d"); + + const date = new Date(); + const dateString = date.toLocaleDateString("de-DE"); + + const signatureLength = 100; + + ctx.beginPath(); + + ctx.moveTo(30, 10); + ctx.lineTo(signatureLength, 10); + + ctx.moveTo(30, 10); + ctx.arcTo(10, 10, 10, 30, 20); + + ctx.moveTo(10, 30); + ctx.arcTo(10, 50, 30, 50, 20); + + ctx.moveTo(30, 50); + ctx.lineTo(signatureLength, 50); + + ctx.strokeStyle = "darkblue"; + ctx.stroke(); + + ctx.fillStyle = "black"; + ctx.font = "10px serif"; + ctx.fillText("Signed by", 30, 10) + ctx.fillText(receiverName + ", " + dateString, 15, 60) + + return new Promise(resolve => { + canvas.toBlob((blob) => { + const url = URL.createObjectURL(blob); + resolve(url) + }) + }) + } + inchToPoint(inch) { return inch * 72; } diff --git a/EnvelopeGenerator.Web/wwwroot/js/app.js b/EnvelopeGenerator.Web/wwwroot/js/app.js index d3b738e5..a6cd13a3 100644 --- a/EnvelopeGenerator.Web/wwwroot/js/app.js +++ b/EnvelopeGenerator.Web/wwwroot/js/app.js @@ -22,6 +22,7 @@ class App { this.Instance = null; this.currentDocument = null; + this.currentReceiver = null; } // This function will be called in the ShowEnvelope.razor page @@ -32,6 +33,9 @@ class App { console.debug("Loading envelope from database..") const envelopeObject = await this.Network.getEnvelope(this.envelopeKey); this.currentDocument = envelopeObject.envelope.documents[0]; + this.currentReceiver = envelopeObject.receiver; + + console.log(envelopeObject) // Load the document from the filestore console.debug("Loading document from filestore") @@ -47,13 +51,85 @@ class App { this.Instance = await this.UI.loadPSPDFKit(arrayBuffer, this.container) this.UI.configurePSPDFKit(this.Instance, this.handleClick.bind(this)) + this.Instance.addEventListener("annotations.load", this.handleAnnotationsLoad) + this.Instance.addEventListener("annotations.change", this.handleAnnotationsChange) + this.Instance.addEventListener("annotations.create", this.handleAnnotationsCreate.bind(this)) + // Load annotations into PSPDFKit console.debug("Loading annotations..") - const annotations = this.Annotation.createAnnotations(this.currentDocument) - const createdAnnotations = await this.Instance.create(annotations) - const description = "Umschlag wurde geöffnet" - await this.Network.postHistory(this.envelopeKey, ActionType.Seen, description); + try { + const annotations = this.Annotation.createAnnotations(this.currentDocument) + const createdAnnotations = await this.Instance.create(annotations) + + const description = "Umschlag wurde geöffnet" + await this.Network.postHistory(this.envelopeKey, ActionType.Seen, description); + } catch (e) { + console.error(e) + } + + } + + handleAnnotationsLoad(loadedAnnotations) { + console.log("annotations loaded", loadedAnnotations.toJS()); + } + + handleAnnotationsChange() {} + + async handleAnnotationsCreate(createdAnnotations) { + console.log("annotations created"); + + console.log(createdAnnotations.toJS()) + + const annotation = createdAnnotations.toJS()[0]; + const isFormField = !!annotation.formFieldName; + const isSignature = !!annotation.isSignature; + + console.log("form field", isFormField, "signature", isSignature) + + //if (!isSignature) { + // return; + //} + + //if (!(isFormField && isSignature)) { + // return; + //} + + if (isFormField === false && isSignature === true) { + + + const left = annotation.boundingBox.left - 25; + const top = annotation.boundingBox.top - 25; + const width = 150; + const height = 75; + + console.log(annotation.boundingBox) + + const imageUrl = await this.Annotation.createAnnotationFrameBlob(this.currentReceiver.name, width, height); + + const request = await fetch(imageUrl); + const blob = await request.blob(); + const imageAttachmentId = await this.Instance.createAttachment(blob); + const frameAnnotation = new PSPDFKit.Annotations.ImageAnnotation({ + pageIndex: annotation.pageIndex, + isSignature: false, + readOnly: true, + locked: true, + lockedContents: true, + contentType: 'image/png', + imageAttachmentId, + description: 'FRAME', + boundingBox: new PSPDFKit.Geometry.Rect({ + left: left, + top: top, + width: width, + height: height, + }), + }); + + this.Instance.create(frameAnnotation); + + } } async handleClick(eventType) { diff --git a/EnvelopeGenerator.Web/wwwroot/js/ui.js b/EnvelopeGenerator.Web/wwwroot/js/ui.js index c4618ccc..a710d42d 100644 --- a/EnvelopeGenerator.Web/wwwroot/js/ui.js +++ b/EnvelopeGenerator.Web/wwwroot/js/ui.js @@ -16,6 +16,7 @@ // and a arraybuffer which represents the document that should be displayed. loadPSPDFKit(arrayBuffer, container) { return PSPDFKit.load({ + styleSheets: ['/css/site.css'], container: container, document: arrayBuffer, autoSaveMode: "DISABLED", @@ -26,24 +27,20 @@ isEditableAnnotation: function (annotation) { // Check if the annotation is a signature // This will allow new signatures, but not allow edits. - return !annotation.isSignature; + console.log(annotation.isSignature, annotation.description) + + if (annotation.isSignature || annotation.description == "FRAME") { + return false; + } + + return true; + + //return !annotation.isSignature; } }) } configurePSPDFKit(instance, handler) { - instance.addEventListener("annotations.load", (loadedAnnotations) => { - console.log("annotations loaded", loadedAnnotations.toJS()); - }) - - instance.addEventListener("annotations.change", () => { - console.log("annotations changed") - }) - - instance.addEventListener("annotations.create", async (createdAnnotations) => { - console.log("annotations created"); - }) - const toolbarItems = this.getToolbarItems(instance, handler) instance.setToolbarItems(toolbarItems) @@ -56,14 +53,22 @@ return defaultItems.concat(customItems) } + createElementFromHTML(html) { + const el = document.createElement('div') + el.innerHTML = html.trim() + + return el.firstChild + } + getCustomItems = function (callback) { - const customItems = [ + return [ { type: "custom", id: "button-reset", className: "button-reset", title: "Zurücksetzen", onPress() { + console.log("RESET") callback("RESET") }, icon: ` @@ -77,15 +82,11 @@ className: "button-finish", title: "Abschließen", onPress() { + console.log("FINISH") callback("FINISH") - }, - icon: ` - - - ` + } } ] - return customItems } getDefaultItems(items) { diff --git a/EnvelopeGenerator.sln b/EnvelopeGenerator.sln index d8604b8c..a3b35620 100644 --- a/EnvelopeGenerator.sln +++ b/EnvelopeGenerator.sln @@ -9,9 +9,7 @@ Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "EnvelopeGenerator.Form", "E EndProject Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "EnvelopeGenerator.Common", "EnvelopeGenerator.Common\EnvelopeGenerator.Common.vbproj", "{6EA0C51F-C2B1-4462-8198-3DE0B32B74F8}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EnvelopeGenerator.WebOld", "EnvelopeGenerator.WebOld\EnvelopeGenerator.WebOld.csproj", "{43F5983D-FCA5-4DC8-A42D-150766966A62}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EnvelopeGenerator.Web", "EnvelopeGenerator.Web\EnvelopeGenerator.Web.csproj", "{5E0E17C0-FF5A-4246-BF87-1ADD85376A27}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EnvelopeGenerator.Web", "EnvelopeGenerator.Web\EnvelopeGenerator.Web.csproj", "{5E0E17C0-FF5A-4246-BF87-1ADD85376A27}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -31,10 +29,6 @@ Global {6EA0C51F-C2B1-4462-8198-3DE0B32B74F8}.Debug|Any CPU.Build.0 = Debug|Any CPU {6EA0C51F-C2B1-4462-8198-3DE0B32B74F8}.Release|Any CPU.ActiveCfg = Release|Any CPU {6EA0C51F-C2B1-4462-8198-3DE0B32B74F8}.Release|Any CPU.Build.0 = Release|Any CPU - {43F5983D-FCA5-4DC8-A42D-150766966A62}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {43F5983D-FCA5-4DC8-A42D-150766966A62}.Debug|Any CPU.Build.0 = Debug|Any CPU - {43F5983D-FCA5-4DC8-A42D-150766966A62}.Release|Any CPU.ActiveCfg = Release|Any CPU - {43F5983D-FCA5-4DC8-A42D-150766966A62}.Release|Any CPU.Build.0 = Release|Any CPU {5E0E17C0-FF5A-4246-BF87-1ADD85376A27}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {5E0E17C0-FF5A-4246-BF87-1ADD85376A27}.Debug|Any CPU.Build.0 = Debug|Any CPU {5E0E17C0-FF5A-4246-BF87-1ADD85376A27}.Release|Any CPU.ActiveCfg = Release|Any CPU