forked from trent_larson/crowd-funder-for-time-pwa
add page for a printable certificate (which works but isn't too impressive yet)
This commit is contained in:
20
package-lock.json
generated
20
package-lock.json
generated
@@ -24,6 +24,7 @@
|
||||
"@simplewebauthn/browser": "^10.0.0",
|
||||
"@simplewebauthn/server": "^10.0.0",
|
||||
"@tweenjs/tween.js": "^21.1.1",
|
||||
"@types/qrcode": "^1.5.5",
|
||||
"@veramo/core": "^5.6.0",
|
||||
"@veramo/credential-w3c": "^5.6.0",
|
||||
"@veramo/data-store": "^5.6.0",
|
||||
@@ -57,6 +58,7 @@
|
||||
"pina": "^0.20.2204228",
|
||||
"pinia-plugin-persistedstate": "^3.2.1",
|
||||
"qr-code-generator-vue3": "^1.4.21",
|
||||
"qrcode": "^1.5.4",
|
||||
"ramda": "^0.29.1",
|
||||
"readable-stream": "^4.5.2",
|
||||
"reflect-metadata": "^0.1.14",
|
||||
@@ -9766,6 +9768,14 @@
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/qrcode": {
|
||||
"version": "1.5.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/qrcode/-/qrcode-1.5.5.tgz",
|
||||
"integrity": "sha512-CdfBi/e3Qk+3Z/fXYShipBT13OJ2fDO2Q2w5CIP5anLTLIndQG9z6P1cnm+8zCWSpm5dnxMFd/uREtb0EXuQzg==",
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/ramda": {
|
||||
"version": "0.29.11",
|
||||
"dev": true,
|
||||
@@ -13040,10 +13050,6 @@
|
||||
"version": "8.0.0",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/encode-utf8": {
|
||||
"version": "1.0.3",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/encodeurl": {
|
||||
"version": "1.0.2",
|
||||
"license": "MIT",
|
||||
@@ -19720,11 +19726,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/qrcode": {
|
||||
"version": "1.5.3",
|
||||
"license": "MIT",
|
||||
"version": "1.5.4",
|
||||
"resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.5.4.tgz",
|
||||
"integrity": "sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==",
|
||||
"dependencies": {
|
||||
"dijkstrajs": "^1.0.1",
|
||||
"encode-utf8": "^1.0.3",
|
||||
"pngjs": "^5.0.0",
|
||||
"yargs": "^15.3.1"
|
||||
},
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
"@simplewebauthn/browser": "^10.0.0",
|
||||
"@simplewebauthn/server": "^10.0.0",
|
||||
"@tweenjs/tween.js": "^21.1.1",
|
||||
"@types/qrcode": "^1.5.5",
|
||||
"@veramo/core": "^5.6.0",
|
||||
"@veramo/credential-w3c": "^5.6.0",
|
||||
"@veramo/data-store": "^5.6.0",
|
||||
@@ -61,6 +62,7 @@
|
||||
"pina": "^0.20.2204228",
|
||||
"pinia-plugin-persistedstate": "^3.2.1",
|
||||
"qr-code-generator-vue3": "^1.4.21",
|
||||
"qrcode": "^1.5.4",
|
||||
"ramda": "^0.29.1",
|
||||
"readable-stream": "^4.5.2",
|
||||
"reflect-metadata": "^0.1.14",
|
||||
|
||||
BIN
public/img/background/cert-frame-2.jpg
Normal file
BIN
public/img/background/cert-frame-2.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 332 KiB |
@@ -43,6 +43,7 @@ import {
|
||||
faEraser,
|
||||
faEye,
|
||||
faEyeSlash,
|
||||
faFileContract,
|
||||
faFileLines,
|
||||
faFilter,
|
||||
faFloppyDisk,
|
||||
@@ -117,6 +118,7 @@ library.add(
|
||||
faEraser,
|
||||
faEye,
|
||||
faEyeSlash,
|
||||
faFileContract,
|
||||
faFileLines,
|
||||
faFilter,
|
||||
faFloppyDisk,
|
||||
|
||||
@@ -43,6 +43,11 @@ const routes: Array<RouteRecordRaw> = [
|
||||
name: "claim-add-raw",
|
||||
component: () => import("../views/ClaimAddRawView.vue"),
|
||||
},
|
||||
{
|
||||
path: "/claim-cert/:id?",
|
||||
name: "claim-cert",
|
||||
component: () => import("../views/ClaimCertificateView.vue"),
|
||||
},
|
||||
{
|
||||
path: "/confirm-contact",
|
||||
name: "confirm-contact",
|
||||
|
||||
149
src/views/ClaimCertificateView.vue
Normal file
149
src/views/ClaimCertificateView.vue
Normal file
@@ -0,0 +1,149 @@
|
||||
<template>
|
||||
<section id="Content">
|
||||
<div v-if="claimData">
|
||||
<canvas ref="claimCanvas"></canvas>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
canvas {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Vue } from "vue-facing-decorator";
|
||||
import { nextTick } from "vue";
|
||||
import QRCode from "qrcode";
|
||||
|
||||
import { NotificationIface } from "@/constants/app";
|
||||
import { retrieveSettingsForActiveAccount } from "@/db/index";
|
||||
import * as endorserServer from "@/libs/endorserServer";
|
||||
|
||||
@Component
|
||||
export default class ClaimViewCertificate extends Vue {
|
||||
$notify!: (notification: NotificationIface, timeout?: number) => void;
|
||||
|
||||
activeDid = "";
|
||||
allMyDids: Array<string> = [];
|
||||
apiServer = "";
|
||||
claimId = "";
|
||||
claimData = null;
|
||||
|
||||
endorserServer = endorserServer;
|
||||
|
||||
async created() {
|
||||
const settings = await retrieveSettingsForActiveAccount();
|
||||
this.activeDid = settings.activeDid || "";
|
||||
this.apiServer = settings.apiServer || "";
|
||||
const pathParams = window.location.pathname.substring(
|
||||
"/claim-cert/".length,
|
||||
);
|
||||
this.claimId = pathParams;
|
||||
await this.fetchClaim();
|
||||
}
|
||||
|
||||
async fetchClaim() {
|
||||
try {
|
||||
const response = await fetch(
|
||||
`${this.apiServer}/api/claim/${this.claimId}`,
|
||||
);
|
||||
if (response.ok) {
|
||||
this.claimData = await response.json();
|
||||
await nextTick(); // Wait for the DOM to update
|
||||
this.drawCanvas();
|
||||
} else {
|
||||
throw new Error(`Error fetching claim: ${response.statusText}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Failed to load claim:", error);
|
||||
this.$notify({
|
||||
group: "alert",
|
||||
type: "danger",
|
||||
title: "Error",
|
||||
text: "There was a problem loading the claim.",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
drawCanvas() {
|
||||
const canvas = this.$refs.claimCanvas as HTMLCanvasElement;
|
||||
if (canvas) {
|
||||
const CANVAS_WIDTH = 1100;
|
||||
const CANVAS_HEIGHT = 850;
|
||||
|
||||
// size to approximate portrait of 8.5"x11"
|
||||
canvas.width = CANVAS_WIDTH;
|
||||
canvas.height = CANVAS_HEIGHT;
|
||||
const ctx = canvas.getContext("2d");
|
||||
if (ctx) {
|
||||
// Load the background image
|
||||
const backgroundImage = new Image();
|
||||
backgroundImage.src = "/img/background/cert-frame-2.jpg";
|
||||
backgroundImage.onload = async () => {
|
||||
// Draw the background image
|
||||
ctx.drawImage(backgroundImage, 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
|
||||
|
||||
// Set font and styles
|
||||
ctx.fillStyle = "black";
|
||||
|
||||
// Draw claim type
|
||||
ctx.font = "bold 20px Arial";
|
||||
const claimTypeText =
|
||||
this.endorserServer.capitalizeAndInsertSpacesBeforeCaps(
|
||||
this.claimData.claimType,
|
||||
);
|
||||
const claimTypeWidth = ctx.measureText(claimTypeText).width;
|
||||
ctx.fillText(
|
||||
claimTypeText,
|
||||
(CANVAS_WIDTH - claimTypeWidth) / 2, // Center horizontally
|
||||
CANVAS_HEIGHT * 0.35,
|
||||
);
|
||||
|
||||
const descriptionText =
|
||||
this.claimData.claim.description || this.claimData.claim.name;
|
||||
if (descriptionText) {
|
||||
const descriptionLine =
|
||||
descriptionText.length > 50
|
||||
? descriptionText.substring(0, 47) + "..."
|
||||
: descriptionText;
|
||||
ctx.font = "14px Arial";
|
||||
const descriptionWidth = ctx.measureText(descriptionLine).width;
|
||||
ctx.fillText(
|
||||
descriptionLine,
|
||||
(CANVAS_WIDTH - descriptionWidth) / 2,
|
||||
CANVAS_HEIGHT * 0.45,
|
||||
);
|
||||
}
|
||||
|
||||
// Draw claim ID
|
||||
ctx.font = "14px Arial";
|
||||
ctx.fillText(this.claimId, CANVAS_WIDTH * 0.3, CANVAS_HEIGHT * 0.62);
|
||||
ctx.fillText(
|
||||
"via EndorserSearch.com",
|
||||
CANVAS_WIDTH * 0.3,
|
||||
CANVAS_HEIGHT * 0.65,
|
||||
);
|
||||
|
||||
// Generate and draw QR code
|
||||
const qrCodeCanvas = document.createElement("canvas");
|
||||
await QRCode.toCanvas(qrCodeCanvas, window.location.href, {
|
||||
width: 150,
|
||||
color: { light: "#0000" /* Transparent background */ },
|
||||
});
|
||||
ctx.drawImage(
|
||||
qrCodeCanvas,
|
||||
CANVAS_WIDTH * 0.57,
|
||||
CANVAS_HEIGHT * 0.55,
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -157,6 +157,14 @@
|
||||
<fa icon="comment" class="text-slate-400" />
|
||||
{{ issuerName }} posted that.
|
||||
</div>
|
||||
<!--
|
||||
<div>
|
||||
<router-link :to="'/claim-cert/' + encodeURIComponent(veriClaim.id)">
|
||||
<fa icon="file-contract" class="text-slate-400" />
|
||||
<span class="ml-2 text-blue-500">Printable Certificate</span>
|
||||
</router-link>
|
||||
</div>
|
||||
-->
|
||||
|
||||
<div class="mt-8">
|
||||
<button
|
||||
@@ -885,7 +893,6 @@ export default class ClaimView extends Vue {
|
||||
this.veriClaim as GenericCredWrapper<OfferVerifiableCredential>,
|
||||
),
|
||||
};
|
||||
console.log("giver & dialog", giver, this.$refs.customGiveDialog);
|
||||
(this.$refs.customGiveDialog as GiftedDialog).open(
|
||||
giver,
|
||||
undefined,
|
||||
|
||||
Reference in New Issue
Block a user