You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
232 lines
6.5 KiB
232 lines
6.5 KiB
<template>
|
|
<section id="Content">
|
|
<div v-if="claimData">
|
|
<canvas ref="claimCanvas"></canvas>
|
|
<div class="qr-code-container">
|
|
<QRCodeVue
|
|
ref="qrCodeRef"
|
|
:value="qrCodeData"
|
|
:size="200"
|
|
level="H"
|
|
render-as="svg"
|
|
:margin="0"
|
|
:color="{ dark: '#000000', light: '#ffffff' }"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</template>
|
|
|
|
<script lang="ts">
|
|
import { Component, Vue } from "vue-facing-decorator";
|
|
import { nextTick } from "vue";
|
|
import QRCodeVue from "qrcode.vue";
|
|
|
|
import { NotificationIface } from "../constants/app";
|
|
import { db, retrieveSettingsForActiveAccount } from "../db/index";
|
|
import * as endorserServer from "../libs/endorserServer";
|
|
import { GenericCredWrapper, GenericVerifiableCredential } from "../interfaces";
|
|
import { logger } from "../utils/logger";
|
|
|
|
@Component({
|
|
components: {
|
|
QRCodeVue,
|
|
},
|
|
})
|
|
export default class ClaimReportCertificateView extends Vue {
|
|
$notify!: (notification: NotificationIface, timeout?: number) => void;
|
|
|
|
activeDid = "";
|
|
allMyDids: Array<string> = [];
|
|
apiServer = "";
|
|
claimId = "";
|
|
claimData: GenericCredWrapper<GenericVerifiableCredential> | null = null;
|
|
|
|
endorserServer = endorserServer;
|
|
|
|
private qrCodeRef: InstanceType<typeof QRCodeVue> | null = null;
|
|
private readonly CANVAS_WIDTH = 1100;
|
|
private readonly CANVAS_HEIGHT = 850;
|
|
|
|
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
|
|
if (this.claimData) {
|
|
this.drawCanvas(this.claimData);
|
|
}
|
|
} else {
|
|
throw new Error(`Error fetching claim: ${response.statusText}`);
|
|
}
|
|
} catch (error) {
|
|
logger.error("Failed to load claim:", error);
|
|
this.$notify({
|
|
group: "alert",
|
|
type: "danger",
|
|
title: "Error",
|
|
text: "There was a problem loading the claim.",
|
|
});
|
|
}
|
|
}
|
|
|
|
async drawCanvas(claimData: GenericCredWrapper<GenericVerifiableCredential>) {
|
|
await db.open();
|
|
const allContacts = await db.contacts.toArray();
|
|
|
|
const canvas = this.$refs.claimCanvas as HTMLCanvasElement;
|
|
if (canvas) {
|
|
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,
|
|
this.CANVAS_WIDTH,
|
|
this.CANVAS_HEIGHT,
|
|
);
|
|
|
|
// Set font and styles
|
|
ctx.fillStyle = "black";
|
|
|
|
// Draw claim type
|
|
ctx.font = "bold 20px Arial";
|
|
const claimTypeText =
|
|
this.endorserServer.capitalizeAndInsertSpacesBeforeCaps(
|
|
claimData.claimType || "",
|
|
);
|
|
const claimTypeWidth = ctx.measureText(claimTypeText).width;
|
|
ctx.fillText(
|
|
claimTypeText,
|
|
(this.CANVAS_WIDTH - claimTypeWidth) / 2, // Center horizontally
|
|
this.CANVAS_HEIGHT * 0.33,
|
|
);
|
|
|
|
if (claimData.claim.agent) {
|
|
const presentedText = "Presented to ";
|
|
ctx.font = "14px Arial";
|
|
const presentedWidth = ctx.measureText(presentedText).width;
|
|
ctx.fillText(
|
|
presentedText,
|
|
(this.CANVAS_WIDTH - presentedWidth) / 2, // Center horizontally
|
|
this.CANVAS_HEIGHT * 0.37,
|
|
);
|
|
const agentText = endorserServer.didInfoForCertificate(
|
|
claimData.claim.agent,
|
|
allContacts,
|
|
);
|
|
ctx.font = "bold 20px Arial";
|
|
const agentWidth = ctx.measureText(agentText).width;
|
|
ctx.fillText(
|
|
agentText,
|
|
(this.CANVAS_WIDTH - agentWidth) / 2, // Center horizontally
|
|
this.CANVAS_HEIGHT * 0.4,
|
|
);
|
|
}
|
|
|
|
const descriptionText =
|
|
claimData.claim.name || claimData.claim.description;
|
|
if (descriptionText) {
|
|
const descriptionLine =
|
|
descriptionText.length > 50
|
|
? descriptionText.substring(0, 75) + "..."
|
|
: descriptionText;
|
|
ctx.font = "14px Arial";
|
|
const descriptionWidth = ctx.measureText(descriptionLine).width;
|
|
ctx.fillText(
|
|
descriptionLine,
|
|
(this.CANVAS_WIDTH - descriptionWidth) / 2,
|
|
this.CANVAS_HEIGHT * 0.45,
|
|
);
|
|
}
|
|
|
|
// Draw claim issuer & recipient
|
|
if (claimData.issuer) {
|
|
ctx.font = "14px Arial";
|
|
const issuerText =
|
|
"Issued by " +
|
|
endorserServer.didInfoForCertificate(
|
|
claimData.issuer,
|
|
allContacts,
|
|
);
|
|
ctx.fillText(
|
|
issuerText,
|
|
this.CANVAS_WIDTH * 0.3,
|
|
this.CANVAS_HEIGHT * 0.6,
|
|
);
|
|
}
|
|
|
|
// Draw claim ID
|
|
ctx.font = "14px Arial";
|
|
ctx.fillText(
|
|
this.claimId,
|
|
this.CANVAS_WIDTH * 0.3,
|
|
this.CANVAS_HEIGHT * 0.7,
|
|
);
|
|
ctx.fillText(
|
|
"via EndorserSearch.com",
|
|
this.CANVAS_WIDTH * 0.3,
|
|
this.CANVAS_HEIGHT * 0.73,
|
|
);
|
|
|
|
// Generate and draw QR code
|
|
await this.generateQRCode();
|
|
};
|
|
}
|
|
}
|
|
}
|
|
|
|
private async generateQRCode() {
|
|
if (!this.qrCodeRef) return;
|
|
|
|
const canvas = await this.qrCodeRef.toCanvas();
|
|
const ctx = canvas.getContext("2d");
|
|
if (!ctx) return;
|
|
|
|
// Draw the QR code on the report canvas
|
|
ctx.drawImage(canvas, this.CANVAS_WIDTH * 0.6, this.CANVAS_HEIGHT * 0.55);
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style scoped>
|
|
canvas {
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
z-index: 1;
|
|
}
|
|
|
|
.qr-code-container {
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
z-index: 2;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
}
|
|
</style>
|
|
|