|
|
|
<template>
|
|
|
|
<!-- QUICK NAV -->
|
|
|
|
<nav id="QuickNav" class="fixed bottom-0 left-0 right-0 bg-slate-200 z-50">
|
|
|
|
<ul class="flex text-2xl p-2 gap-2">
|
|
|
|
<!-- Home Feed -->
|
|
|
|
<li class="basis-1/5 rounded-md text-slate-500">
|
|
|
|
<router-link :to="{ name: 'home' }" class="block text-center py-3 px-1">
|
|
|
|
<fa icon="house-chimney" class="fa-fw"></fa>
|
|
|
|
</router-link>
|
|
|
|
</li>
|
|
|
|
<!-- Search -->
|
|
|
|
<li class="basis-1/5 rounded-md text-slate-500">
|
|
|
|
<router-link
|
|
|
|
:to="{ name: 'discover' }"
|
|
|
|
class="block text-center py-3 px-1"
|
|
|
|
>
|
|
|
|
<fa icon="magnifying-glass" class="fa-fw"></fa>
|
|
|
|
</router-link>
|
|
|
|
</li>
|
|
|
|
<!-- Projects -->
|
|
|
|
<li class="basis-1/5 rounded-md text-slate-500">
|
|
|
|
<router-link
|
|
|
|
:to="{ name: 'projects' }"
|
|
|
|
class="block text-center py-3 px-1"
|
|
|
|
>
|
|
|
|
<fa icon="folder-open" class="fa-fw"></fa>
|
|
|
|
</router-link>
|
|
|
|
</li>
|
|
|
|
<!-- Contacts -->
|
|
|
|
<li class="basis-1/5 rounded-md text-slate-500">
|
|
|
|
<router-link
|
|
|
|
:to="{ name: 'contacts' }"
|
|
|
|
class="block text-center py-3 px-1"
|
|
|
|
>
|
|
|
|
<fa icon="users" class="fa-fw"></fa>
|
|
|
|
</router-link>
|
|
|
|
</li>
|
|
|
|
<!-- Profile -->
|
|
|
|
<li class="basis-1/5 rounded-md bg-slate-400 text-white">
|
|
|
|
<router-link
|
|
|
|
:to="{ name: 'account' }"
|
|
|
|
class="block text-center py-3 px-1"
|
|
|
|
>
|
|
|
|
<fa icon="circle-user" class="fa-fw"></fa>
|
|
|
|
</router-link>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
|
|
</nav>
|
|
|
|
|
|
|
|
<!-- CONTENT -->
|
|
|
|
<section id="Content" class="p-6 pb-24">
|
|
|
|
<!-- Heading -->
|
|
|
|
<h1 id="ViewHeading" class="text-4xl text-center font-light pt-4 mb-8">
|
|
|
|
Your Contact Info
|
|
|
|
</h1>
|
|
|
|
|
|
|
|
<!--
|
|
|
|
Play with display options: https://qr-code-styling.com/
|
|
|
|
See docs: https://www.npmjs.com/package/qr-code-generator-vue3
|
|
|
|
-->
|
|
|
|
<QRCodeVue3
|
|
|
|
:value="this.qrValue"
|
|
|
|
:cornersSquareOptions="{ type: 'extra-rounded' }"
|
|
|
|
:dotsOptions="{ type: 'square' }"
|
|
|
|
class="flex justify-center"
|
|
|
|
/>
|
|
|
|
|
|
|
|
<!-- This same popup code is in many files. -->
|
|
|
|
<div v-bind:class="computedAlertClassNames()">
|
|
|
|
<button
|
|
|
|
class="close-button bg-slate-200 w-8 leading-loose rounded-full absolute top-2 right-2"
|
|
|
|
@click="onClickClose()"
|
|
|
|
>
|
|
|
|
<fa icon="xmark"></fa>
|
|
|
|
</button>
|
|
|
|
<p>{{ alertMessage }}</p>
|
|
|
|
</div>
|
|
|
|
</section>
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<script lang="ts">
|
|
|
|
import QRCodeVue3 from "qr-code-generator-vue3";
|
|
|
|
import { Component, Vue } from "vue-facing-decorator";
|
|
|
|
import { accountsDB, db } from "@/db";
|
|
|
|
import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
|
|
|
|
import * as R from "ramda";
|
|
|
|
import { SimpleSigner } from "@/libs/crypto";
|
|
|
|
import * as didJwt from "did-jwt";
|
|
|
|
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
|
|
const Buffer = require("buffer/").Buffer;
|
|
|
|
|
|
|
|
@Component({
|
|
|
|
components: {
|
|
|
|
QRCodeVue3,
|
|
|
|
},
|
|
|
|
})
|
|
|
|
export default class ContactQRScanShow extends Vue {
|
|
|
|
activeDid = "";
|
|
|
|
apiServer = "";
|
|
|
|
qrValue = "";
|
|
|
|
|
|
|
|
// 'created' hook runs when the Vue instance is first created
|
|
|
|
async created() {
|
|
|
|
await db.open();
|
|
|
|
const settings = await db.settings.get(MASTER_SETTINGS_KEY);
|
|
|
|
this.activeDid = settings?.activeDid || "";
|
|
|
|
this.apiServer = settings?.apiServer || "";
|
|
|
|
|
|
|
|
await accountsDB.open();
|
|
|
|
const accounts = await accountsDB.accounts.toArray();
|
|
|
|
const account = R.find((acc) => acc.did === this.activeDid, accounts);
|
|
|
|
if (!account) {
|
|
|
|
this.alertMessage = "You have no identity yet.";
|
|
|
|
} else {
|
|
|
|
const identity = JSON.parse(account?.identity || "null");
|
|
|
|
if (!identity) {
|
|
|
|
throw new Error("No identity found.");
|
|
|
|
}
|
|
|
|
|
|
|
|
const publicKeyHex = identity.keys[0].publicKeyHex;
|
|
|
|
const publicEncKey = Buffer.from(publicKeyHex, "hex").toString("base64");
|
|
|
|
const contactInfo = {
|
|
|
|
iat: Date.now(),
|
|
|
|
iss: this.activeDid,
|
|
|
|
own: {
|
|
|
|
name: (settings?.firstName || "") + " " + (settings?.lastName || ""),
|
|
|
|
publicEncKey,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
const alg = undefined;
|
|
|
|
const privateKeyHex: string = identity.keys[0].privateKeyHex;
|
|
|
|
const signer = await SimpleSigner(privateKeyHex);
|
|
|
|
// create a JWT for the request
|
|
|
|
const vcJwt: string = await didJwt.createJWT(contactInfo, {
|
|
|
|
alg: alg,
|
|
|
|
issuer: identity.did,
|
|
|
|
signer: signer,
|
|
|
|
});
|
|
|
|
const viewPrefix = "https://endorser.ch/contact?jwt=";
|
|
|
|
this.qrValue = viewPrefix + vcJwt;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// This same popup code is in many files.
|
|
|
|
alertMessage = "";
|
|
|
|
public onClickClose() {
|
|
|
|
this.alertMessage = "";
|
|
|
|
}
|
|
|
|
public computedAlertClassNames() {
|
|
|
|
return {
|
|
|
|
hidden: !this.alertMessage,
|
|
|
|
"dismissable-alert": true,
|
|
|
|
"bg-slate-100": true,
|
|
|
|
"p-5": true,
|
|
|
|
rounded: true,
|
|
|
|
"drop-shadow-lg": true,
|
|
|
|
fixed: true,
|
|
|
|
"top-3": true,
|
|
|
|
"inset-x-3": true,
|
|
|
|
"transition-transform": true,
|
|
|
|
"ease-in": true,
|
|
|
|
"duration-300": true,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
</script>
|