forked from jsnbuchanan/crowd-funder-for-time-pwa
refine claim certificate view
This commit is contained in:
@@ -476,6 +476,16 @@ export function didInfo(
|
|||||||
return didInfoForContact(did, activeDid, contact, allMyDids).displayName;
|
return didInfoForContact(did, activeDid, contact, allMyDids).displayName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return text description without any references to "you" as user
|
||||||
|
*/
|
||||||
|
export function didInfoForCertificate(
|
||||||
|
did: string | undefined,
|
||||||
|
contacts: Contact[],
|
||||||
|
): string {
|
||||||
|
return didInfoForContact(did, undefined, contactForDid(did, contacts), []).displayName;
|
||||||
|
}
|
||||||
|
|
||||||
let passkeyAccessToken: string = "";
|
let passkeyAccessToken: string = "";
|
||||||
let passkeyTokenExpirationEpochSeconds: number = 0;
|
let passkeyTokenExpirationEpochSeconds: number = 0;
|
||||||
|
|
||||||
|
|||||||
@@ -21,8 +21,8 @@ import { Component, Vue } from "vue-facing-decorator";
|
|||||||
import { nextTick } from "vue";
|
import { nextTick } from "vue";
|
||||||
import QRCode from "qrcode";
|
import QRCode from "qrcode";
|
||||||
|
|
||||||
import { NotificationIface } from "@/constants/app";
|
import { APP_SERVER, NotificationIface } from "@/constants/app";
|
||||||
import { retrieveSettingsForActiveAccount } from "@/db/index";
|
import { db, retrieveSettingsForActiveAccount } from "@/db/index";
|
||||||
import * as endorserServer from "@/libs/endorserServer";
|
import * as endorserServer from "@/libs/endorserServer";
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
@@ -56,7 +56,9 @@ export default class ClaimViewCertificate extends Vue {
|
|||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
this.claimData = await response.json();
|
this.claimData = await response.json();
|
||||||
await nextTick(); // Wait for the DOM to update
|
await nextTick(); // Wait for the DOM to update
|
||||||
this.drawCanvas();
|
if (this.claimData) {
|
||||||
|
this.drawCanvas(this.claimData);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new Error(`Error fetching claim: ${response.statusText}`);
|
throw new Error(`Error fetching claim: ${response.statusText}`);
|
||||||
}
|
}
|
||||||
@@ -71,7 +73,12 @@ export default class ClaimViewCertificate extends Vue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
drawCanvas() {
|
async drawCanvas(
|
||||||
|
claimData: endorserServer.GenericCredWrapper<endorserServer.GenericVerifiableCredential>,
|
||||||
|
) {
|
||||||
|
await db.open();
|
||||||
|
const allContacts = await db.contacts.toArray();
|
||||||
|
|
||||||
const canvas = this.$refs.claimCanvas as HTMLCanvasElement;
|
const canvas = this.$refs.claimCanvas as HTMLCanvasElement;
|
||||||
if (canvas) {
|
if (canvas) {
|
||||||
const CANVAS_WIDTH = 1100;
|
const CANVAS_WIDTH = 1100;
|
||||||
@@ -96,21 +103,43 @@ export default class ClaimViewCertificate extends Vue {
|
|||||||
ctx.font = "bold 20px Arial";
|
ctx.font = "bold 20px Arial";
|
||||||
const claimTypeText =
|
const claimTypeText =
|
||||||
this.endorserServer.capitalizeAndInsertSpacesBeforeCaps(
|
this.endorserServer.capitalizeAndInsertSpacesBeforeCaps(
|
||||||
this.claimData.claimType,
|
claimData.claimType || "",
|
||||||
);
|
);
|
||||||
const claimTypeWidth = ctx.measureText(claimTypeText).width;
|
const claimTypeWidth = ctx.measureText(claimTypeText).width;
|
||||||
ctx.fillText(
|
ctx.fillText(
|
||||||
claimTypeText,
|
claimTypeText,
|
||||||
(CANVAS_WIDTH - claimTypeWidth) / 2, // Center horizontally
|
(CANVAS_WIDTH - claimTypeWidth) / 2, // Center horizontally
|
||||||
CANVAS_HEIGHT * 0.35,
|
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 =
|
const descriptionText =
|
||||||
this.claimData.claim.description || this.claimData.claim.name;
|
claimData.claim.name || claimData.claim.description;
|
||||||
if (descriptionText) {
|
if (descriptionText) {
|
||||||
const descriptionLine =
|
const descriptionLine =
|
||||||
descriptionText.length > 50
|
descriptionText.length > 50
|
||||||
? descriptionText.substring(0, 47) + "..."
|
? descriptionText.substring(0, 85) + "..."
|
||||||
: descriptionText;
|
: descriptionText;
|
||||||
ctx.font = "14px Arial";
|
ctx.font = "14px Arial";
|
||||||
const descriptionWidth = ctx.measureText(descriptionLine).width;
|
const descriptionWidth = ctx.measureText(descriptionLine).width;
|
||||||
@@ -121,26 +150,38 @@ export default class ClaimViewCertificate extends Vue {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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
|
// Draw claim ID
|
||||||
ctx.font = "14px Arial";
|
ctx.font = "14px Arial";
|
||||||
ctx.fillText(this.claimId, CANVAS_WIDTH * 0.3, CANVAS_HEIGHT * 0.62);
|
ctx.fillText(this.claimId, CANVAS_WIDTH * 0.3, CANVAS_HEIGHT * 0.7);
|
||||||
ctx.fillText(
|
ctx.fillText(
|
||||||
"via EndorserSearch.com",
|
"via EndorserSearch.com",
|
||||||
CANVAS_WIDTH * 0.3,
|
CANVAS_WIDTH * 0.3,
|
||||||
CANVAS_HEIGHT * 0.65,
|
CANVAS_HEIGHT * 0.73,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Generate and draw QR code
|
// Generate and draw QR code
|
||||||
const qrCodeCanvas = document.createElement("canvas");
|
const qrCodeCanvas = document.createElement("canvas");
|
||||||
await QRCode.toCanvas(qrCodeCanvas, window.location.href, {
|
await QRCode.toCanvas(
|
||||||
width: 150,
|
|
||||||
color: { light: "#0000" /* Transparent background */ },
|
|
||||||
});
|
|
||||||
ctx.drawImage(
|
|
||||||
qrCodeCanvas,
|
qrCodeCanvas,
|
||||||
CANVAS_WIDTH * 0.57,
|
APP_SERVER + "/claim/" + this.claimId,
|
||||||
CANVAS_HEIGHT * 0.55,
|
{
|
||||||
|
width: 150,
|
||||||
|
color: { light: "#0000" /* Transparent background */ },
|
||||||
|
},
|
||||||
);
|
);
|
||||||
|
ctx.drawImage(qrCodeCanvas, CANVAS_WIDTH * 0.6, CANVAS_HEIGHT * 0.55);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,24 +20,36 @@
|
|||||||
<div class="bg-slate-100 rounded-md overflow-hidden px-4 py-3 mb-4">
|
<div class="bg-slate-100 rounded-md overflow-hidden px-4 py-3 mb-4">
|
||||||
<div class="block flex gap-4 overflow-hidden">
|
<div class="block flex gap-4 overflow-hidden">
|
||||||
<div class="overflow-hidden">
|
<div class="overflow-hidden">
|
||||||
<h2 class="text-md font-bold">
|
<div class="flex justify-between">
|
||||||
{{ capitalizeAndInsertSpacesBeforeCaps(veriClaim.claimType) }}
|
<h2 class="text-md font-bold">
|
||||||
<button
|
{{ capitalizeAndInsertSpacesBeforeCaps(veriClaim.claimType) }}
|
||||||
v-if="
|
<button
|
||||||
['GiveAction', 'Offer', 'PlanAction'].includes(
|
v-if="
|
||||||
veriClaim.claimType as string,
|
['GiveAction', 'Offer', 'PlanAction'].includes(
|
||||||
) && veriClaim.issuer === activeDid
|
veriClaim.claimType as string,
|
||||||
// a PlanAction agent also could edit one of those,
|
) && veriClaim.issuer === activeDid
|
||||||
// but rather than add more Plan-specific logic to detect the agent
|
// a PlanAction agent also could edit one of those,
|
||||||
// we'll let them click the Project link and edit from there
|
// but rather than add more Plan-specific logic to detect the agent
|
||||||
"
|
// we'll let them click the Project link and edit from there
|
||||||
@click="onClickEditClaim"
|
"
|
||||||
title="Edit"
|
@click="onClickEditClaim"
|
||||||
data-testId="editClaimButton"
|
title="Edit"
|
||||||
>
|
data-testId="editClaimButton"
|
||||||
<fa icon="pen" class="text-sm text-blue-500 ml-2 mb-1" />
|
>
|
||||||
</button>
|
<fa icon="pen" class="text-sm text-blue-500 ml-2 mb-1" />
|
||||||
</h2>
|
</button>
|
||||||
|
</h2>
|
||||||
|
<!--
|
||||||
|
<div>
|
||||||
|
<router-link
|
||||||
|
:to="'/claim-cert/' + encodeURIComponent(veriClaim.id)"
|
||||||
|
class="text-blue-500 mt-2"
|
||||||
|
>
|
||||||
|
<fa icon="square" class="text-white bg-yellow-500 p-1" />
|
||||||
|
</router-link>
|
||||||
|
</div>
|
||||||
|
-->
|
||||||
|
</div>
|
||||||
<div class="text-sm">
|
<div class="text-sm">
|
||||||
<div data-testId="description">
|
<div data-testId="description">
|
||||||
<fa icon="message" class="fa-fw text-slate-400" />
|
<fa icon="message" class="fa-fw text-slate-400" />
|
||||||
|
|||||||
Reference in New Issue
Block a user