Changes: - Move v-model directives before other attributes - Move v-bind directives before event handlers - Reorder attributes for better readability - Fix template attribute ordering across components - Improve eslint rules - add default vite config for testing (handles nostr error too) This follows Vue.js style guide recommendations for attribute ordering and improves template consistency.
191 lines
5.7 KiB
Vue
191 lines
5.7 KiB
Vue
<template>
|
|
<section id="Content">
|
|
<div v-if="claimData">
|
|
<canvas ref="claimCanvas"></canvas>
|
|
</div>
|
|
</section>
|
|
</template>
|
|
|
|
<script lang="ts">
|
|
import { Component, Vue } from "vue-facing-decorator";
|
|
import { nextTick } from "vue";
|
|
import QRCode from "qrcode";
|
|
|
|
import { APP_SERVER, NotificationIface } from "../constants/app";
|
|
import { db, retrieveSettingsForActiveAccount } from "../db/index";
|
|
import * as endorserServer from "../libs/endorserServer";
|
|
|
|
@Component
|
|
export default class ClaimReportCertificateView 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
|
|
if (this.claimData) {
|
|
this.drawCanvas(this.claimData);
|
|
}
|
|
} 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.",
|
|
});
|
|
}
|
|
}
|
|
|
|
async drawCanvas(
|
|
claimData: endorserServer.GenericCredWrapper<endorserServer.GenericVerifiableCredential>,
|
|
) {
|
|
await db.open();
|
|
const allContacts = await db.contacts.toArray();
|
|
|
|
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(
|
|
claimData.claimType || "",
|
|
);
|
|
const claimTypeWidth = ctx.measureText(claimTypeText).width;
|
|
ctx.fillText(
|
|
claimTypeText,
|
|
(CANVAS_WIDTH - claimTypeWidth) / 2, // Center horizontally
|
|
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,
|
|
(CANVAS_WIDTH - presentedWidth) / 2, // Center horizontally
|
|
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,
|
|
(CANVAS_WIDTH - agentWidth) / 2, // Center horizontally
|
|
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,
|
|
(CANVAS_WIDTH - descriptionWidth) / 2,
|
|
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, CANVAS_WIDTH * 0.3, CANVAS_HEIGHT * 0.6);
|
|
}
|
|
|
|
// Draw claim ID
|
|
ctx.font = "14px Arial";
|
|
ctx.fillText(this.claimId, CANVAS_WIDTH * 0.3, CANVAS_HEIGHT * 0.7);
|
|
ctx.fillText(
|
|
"via EndorserSearch.com",
|
|
CANVAS_WIDTH * 0.3,
|
|
CANVAS_HEIGHT * 0.73,
|
|
);
|
|
|
|
// Generate and draw QR code
|
|
const qrCodeCanvas = document.createElement("canvas");
|
|
await QRCode.toCanvas(
|
|
qrCodeCanvas,
|
|
APP_SERVER + "/claim/" + this.claimId,
|
|
{
|
|
width: 150,
|
|
color: { light: "#0000" /* Transparent background */ },
|
|
},
|
|
);
|
|
ctx.drawImage(qrCodeCanvas, CANVAS_WIDTH * 0.6, CANVAS_HEIGHT * 0.55);
|
|
};
|
|
}
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style scoped>
|
|
canvas {
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
}
|
|
</style>
|