forked from trent_larson/crowd-funder-for-time-pwa
add Confirm Gift screen for simpler confirmation
This commit is contained in:
@@ -54,7 +54,7 @@
|
||||
}"
|
||||
class="text-blue-500"
|
||||
>
|
||||
Photo, ...
|
||||
Photo & Details ...
|
||||
</router-link>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -70,7 +70,7 @@ export const isGlobalUri = (uri: string) => {
|
||||
return uri && uri.match(new RegExp(/^[A-Za-z][A-Za-z0-9+.-]+:/));
|
||||
};
|
||||
|
||||
export const giveIsConfirmable = (veriClaim: GenericCredWrapper) => {
|
||||
export const isGiveAction = (veriClaim: GenericCredWrapper) => {
|
||||
return veriClaim.claimType === "GiveAction";
|
||||
};
|
||||
|
||||
@@ -91,7 +91,7 @@ export const isGiveRecordTheUserCanConfirm = (
|
||||
confirmerIdList: string[] = [],
|
||||
) => {
|
||||
return (
|
||||
giveIsConfirmable(veriClaim) &&
|
||||
isGiveAction(veriClaim) &&
|
||||
!confirmerIdList.includes(activeDid) &&
|
||||
veriClaim.issuer !== activeDid &&
|
||||
!containsHiddenDid(veriClaim.claim)
|
||||
|
||||
@@ -11,10 +11,12 @@ import "./assets/styles/tailwind.css";
|
||||
|
||||
import { library } from "@fortawesome/fontawesome-svg-core";
|
||||
import {
|
||||
faArrowDown,
|
||||
faArrowLeft,
|
||||
faArrowRight,
|
||||
faArrowRotateBackward,
|
||||
faArrowUpRightFromSquare,
|
||||
faArrowUp,
|
||||
faBan,
|
||||
faBitcoinSign,
|
||||
faBurst,
|
||||
@@ -47,6 +49,7 @@ import {
|
||||
faGlobe,
|
||||
faHammer,
|
||||
faHand,
|
||||
faHandHoldingDollar,
|
||||
faHandHoldingHeart,
|
||||
faHouseChimney,
|
||||
faImagePortrait,
|
||||
@@ -77,10 +80,12 @@ import {
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
|
||||
library.add(
|
||||
faArrowDown,
|
||||
faArrowLeft,
|
||||
faArrowRight,
|
||||
faArrowRotateBackward,
|
||||
faArrowUpRightFromSquare,
|
||||
faArrowUp,
|
||||
faBan,
|
||||
faBitcoinSign,
|
||||
faBurst,
|
||||
@@ -113,6 +118,7 @@ library.add(
|
||||
faGlobe,
|
||||
faHammer,
|
||||
faHand,
|
||||
faHandHoldingDollar,
|
||||
faHandHoldingHeart,
|
||||
faHouseChimney,
|
||||
faImagePortrait,
|
||||
|
||||
@@ -43,14 +43,19 @@ const routes: Array<RouteRecordRaw> = [
|
||||
name: "confirm-contact",
|
||||
component: () => import("../views/ConfirmContactView.vue"),
|
||||
},
|
||||
{
|
||||
path: "/confirm-gift/:id?",
|
||||
name: "confirm-gift",
|
||||
component: () => import("@/views/ConfirmGiftView.vue"),
|
||||
},
|
||||
{
|
||||
path: "/contact-amounts",
|
||||
name: "contact-amounts",
|
||||
component: () => import("../views/ContactAmountsView.vue"),
|
||||
},
|
||||
{
|
||||
path: "/contact-gives",
|
||||
name: "contact-gives",
|
||||
path: "/contact-gift",
|
||||
name: "contact-gift",
|
||||
component: () => import("../views/ContactGiftingView.vue"),
|
||||
},
|
||||
{
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
@click="$router.go(-1)"
|
||||
class="text-lg text-center px-2 py-1 absolute -left-2 -top-1"
|
||||
>
|
||||
<fa icon="chevron-left" class="fa-fw"></fa>
|
||||
<fa icon="chevron-left" class="fa-fw" />
|
||||
</button>
|
||||
Verifiable Claim Details
|
||||
</h1>
|
||||
@@ -35,16 +35,16 @@
|
||||
"
|
||||
class="ml-2 mr-2"
|
||||
>
|
||||
<fa icon="copy" class="text-slate-400 fa-fw"></fa>
|
||||
<fa icon="copy" class="text-slate-400 fa-fw" />
|
||||
</button>
|
||||
<span v-show="showIdCopy">Copied ID</span>
|
||||
</div>
|
||||
<div>
|
||||
<fa icon="message" class="fa-fw text-slate-400"></fa>
|
||||
<fa icon="message" class="fa-fw text-slate-400" />
|
||||
{{ veriClaim.claim?.description }}
|
||||
</div>
|
||||
<div>
|
||||
<fa icon="user" class="fa-fw text-slate-400"></fa>
|
||||
<fa icon="user" class="fa-fw text-slate-400" />
|
||||
{{ veriClaim.issuer }}
|
||||
<span v-if="!serverUtil.isEmptyOrHiddenDid(veriClaim.issuer)">
|
||||
<button
|
||||
@@ -56,13 +56,13 @@
|
||||
"
|
||||
class="ml-2 mr-2"
|
||||
>
|
||||
<fa icon="copy" class="text-slate-400 fa-fw"></fa>
|
||||
<fa icon="copy" class="text-slate-400 fa-fw" />
|
||||
</button>
|
||||
<span v-show="showDidCopy">Copied DID</span>
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<fa icon="calendar" class="fa-fw text-slate-400"></fa>
|
||||
<fa icon="calendar" class="fa-fw text-slate-400" />
|
||||
{{ veriClaim.issuedAt?.replace(/T/, " ").replace(/Z/, " UTC") }}
|
||||
</div>
|
||||
|
||||
@@ -121,7 +121,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="columns-3">
|
||||
<div class="flex columns-3">
|
||||
<button
|
||||
class="col-span-1 bg-gradient-to-b from-blue-400 to-blue-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-4 py-2 rounded-md"
|
||||
v-if="
|
||||
@@ -137,6 +137,16 @@
|
||||
<fa icon="circle-check" class="ml-2 text-white cursor-pointer" />
|
||||
</button>
|
||||
|
||||
<span class="px-4 py-2">
|
||||
<router-link
|
||||
v-if="libsUtil.isGiveAction(veriClaim)"
|
||||
:to="'/confirm-gift/' + encodeURIComponent(veriClaim.id)"
|
||||
class="col-span-1 text-blue-500"
|
||||
>
|
||||
Confirmation Details...
|
||||
</router-link>
|
||||
</span>
|
||||
|
||||
<button
|
||||
v-if="libsUtil.canFulfillOffer(veriClaim)"
|
||||
@click="openFulfillGiftDialog()"
|
||||
@@ -148,7 +158,7 @@
|
||||
</div>
|
||||
<GiftedDialog ref="customGiveDialog" />
|
||||
|
||||
<div v-if="libsUtil.giveIsConfirmable(veriClaim)">
|
||||
<div v-if="libsUtil.isGiveAction(veriClaim)">
|
||||
<h2 class="font-bold uppercase text-xl mt-8 mb-2">Confirmations</h2>
|
||||
|
||||
<span v-if="totalConfirmers() === 0">Nobody has confirmed this.</span>
|
||||
@@ -319,7 +329,7 @@
|
||||
class="list-disc p-4"
|
||||
>
|
||||
<div class="text-sm">
|
||||
<fa icon="minus" class="fa-fw"></fa>
|
||||
<fa icon="minus" class="fa-fw" />
|
||||
The {{ visibleDidPath }} is visible to:
|
||||
</div>
|
||||
<div class="ml-12 p-1">
|
||||
@@ -341,8 +351,7 @@
|
||||
</span>
|
||||
<span v-if="veriClaim.publicUrls?.[visDid]"
|
||||
>, found at
|
||||
<fa icon="globe" class="fa-fw text-slate-400"></fa
|
||||
> <a
|
||||
<fa icon="globe" class="fa-fw text-slate-400" /> <a
|
||||
:href="veriClaim.publicUrls?.[visDid]"
|
||||
class="text-blue-500"
|
||||
>{{
|
||||
@@ -474,10 +483,10 @@ export default class ClaimView extends Vue {
|
||||
|
||||
await accountsDB.open();
|
||||
const accounts = accountsDB.accounts;
|
||||
const accountsArr = await accounts?.toArray();
|
||||
const accountsArr: Array<Account> = await accounts?.toArray();
|
||||
this.allMyDids = accountsArr.map((acc) => acc.did);
|
||||
const account = accountsArr.find((acc) => acc.did === this.activeDid);
|
||||
this.accountIdentityStr = account?.identity || "null";
|
||||
this.accountIdentityStr = (account?.identity as string) || "null";
|
||||
const identity = JSON.parse(this.accountIdentityStr);
|
||||
|
||||
const pathParam = window.location.pathname.substring("/claim/".length);
|
||||
@@ -666,7 +675,7 @@ export default class ClaimView extends Vue {
|
||||
const accounts = accountsDB.accounts;
|
||||
const accountsArr: Account[] = await accounts?.toArray();
|
||||
const account = accountsArr.find((acc) => acc.did === this.activeDid);
|
||||
const identity = JSON.parse(account?.identity || "null");
|
||||
const identity = JSON.parse((account?.identity as string) || "null");
|
||||
|
||||
const url =
|
||||
this.apiServer + "/api/claim/full/" + encodeURIComponent(claimId);
|
||||
|
||||
933
src/views/ConfirmGiftView.vue
Normal file
933
src/views/ConfirmGiftView.vue
Normal file
@@ -0,0 +1,933 @@
|
||||
<template>
|
||||
<QuickNav />
|
||||
<!-- CONTENT -->
|
||||
<section id="Content" class="p-6 pb-24 max-w-3xl mx-auto">
|
||||
<!-- Breadcrumb -->
|
||||
<div id="ViewBreadcrumb" class="mb-8">
|
||||
<h1 class="text-lg text-center font-light relative px-7">
|
||||
<!-- Back -->
|
||||
<button
|
||||
@click="$router.go(-1)"
|
||||
class="text-lg text-center px-2 py-1 absolute -left-2 -top-1"
|
||||
>
|
||||
<fa icon="chevron-left" class="fa-fw" />
|
||||
</button>
|
||||
<span
|
||||
v-if="
|
||||
libsUtil.isGiveRecordTheUserCanConfirm(
|
||||
veriClaim,
|
||||
activeDid,
|
||||
confirmerIdList,
|
||||
)
|
||||
"
|
||||
>
|
||||
Do you agree?
|
||||
</span>
|
||||
<span v-else> Details </span>
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
<div v-if="detailsForGive">
|
||||
<div class="flex justify-center">
|
||||
<button
|
||||
class="col-span-1 bg-gradient-to-b from-blue-400 to-blue-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-4 py-2 rounded-md"
|
||||
v-if="
|
||||
libsUtil.isGiveRecordTheUserCanConfirm(
|
||||
veriClaim,
|
||||
activeDid,
|
||||
confirmerIdList,
|
||||
)
|
||||
"
|
||||
@click="confirmConfirmClaim()"
|
||||
>
|
||||
Confirm
|
||||
<fa icon="circle-check" class="ml-2 text-white cursor-pointer" />
|
||||
</button>
|
||||
<button
|
||||
v-else
|
||||
@click="notifyWhyCannotConfirm()"
|
||||
class="col-span-1 bg-gradient-to-b from-slate-400 to-slate-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-4 py-2 rounded-md"
|
||||
>
|
||||
Confirm
|
||||
<fa icon="circle-check" class="ml-2 text-white cursor-pointer" />
|
||||
</button>
|
||||
<a
|
||||
class="col-span-1 bg-gradient-to-b from-blue-400 to-blue-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white ml-2 px-4 py-2 rounded-md"
|
||||
:href="urlForNewGive"
|
||||
>
|
||||
Record One of Your Own
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Details -->
|
||||
<div class="bg-slate-100 rounded-md overflow-hidden px-4 py-3 mt-4">
|
||||
<div class="block flex gap-4 overflow-hidden">
|
||||
<div class="overflow-hidden">
|
||||
<div class="text-sm">
|
||||
<div>
|
||||
<fa icon="arrow-down" class="fa-fw text-slate-400" />
|
||||
{{ giverName }}
|
||||
</div>
|
||||
<div class="ml-6">gave</div>
|
||||
<div v-if="veriClaim.claim?.object">
|
||||
<fa icon="hand-holding-dollar" class="fa-fw text-slate-400" />
|
||||
{{
|
||||
displayAmount(
|
||||
veriClaim.claim.object.unitCode,
|
||||
veriClaim.claim.object.amountOfThisGood,
|
||||
)
|
||||
}}
|
||||
600
|
||||
</div>
|
||||
<div>
|
||||
<fa icon="message" class="fa-fw text-slate-400" />
|
||||
{{ veriClaim.claim?.object ? "and" : "" }}
|
||||
{{ veriClaim.claim?.description }}
|
||||
</div>
|
||||
<div>
|
||||
<fa icon="arrow-up" class="fa-fw text-slate-400" />
|
||||
to {{ recipientName }}
|
||||
</div>
|
||||
<div>
|
||||
<fa icon="calendar" class="fa-fw text-slate-400" />
|
||||
{{ veriClaim.issuedAt?.replace(/T/, " ").replace(/Z/, " UTC") }}
|
||||
</div>
|
||||
|
||||
<!-- Fullfills Links -->
|
||||
|
||||
<!-- fullfills links for a give -->
|
||||
<div class="mt-2" v-if="detailsForGive?.fulfillsPlanHandleId">
|
||||
<router-link
|
||||
:to="
|
||||
'/project/' +
|
||||
encodeURIComponent(detailsForGive?.fulfillsPlanHandleId)
|
||||
"
|
||||
class="text-blue-500 mt-2 cursor-pointer"
|
||||
target="_blank"
|
||||
>
|
||||
This fulfills a bigger plan
|
||||
<fa icon="arrow-up-right-from-square" class="fa-fw" />
|
||||
</router-link>
|
||||
</div>
|
||||
<!-- if there's another, it's probably fulfilling an offer, too -->
|
||||
<div
|
||||
v-if="
|
||||
detailsForGive?.fulfillsType &&
|
||||
detailsForGive?.fulfillsType !== 'PlanAction' &&
|
||||
detailsForGive?.fulfillsHandleId
|
||||
"
|
||||
>
|
||||
<!-- router-link to /claim/ only changes URL path -->
|
||||
<router-link
|
||||
:to="
|
||||
'/claim/' +
|
||||
encodeURIComponent(detailsForGive?.fulfillsHandleId)
|
||||
"
|
||||
class="text-blue-500 mt-2 cursor-pointer"
|
||||
target="_blank"
|
||||
>
|
||||
This fulfills
|
||||
{{
|
||||
capitalizeAndInsertSpacesBeforeCapsWithAPrefix(
|
||||
detailsForGive.fulfillsType,
|
||||
)
|
||||
}}
|
||||
<fa icon="arrow-up-right-from-square" class="fa-fw" />
|
||||
</router-link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-2">
|
||||
<fa icon="comment" class="fa-fw text-slate-400" />
|
||||
{{ issuerName }} said that.
|
||||
</div>
|
||||
|
||||
<div class="flex justify-center">
|
||||
<button
|
||||
v-if="
|
||||
libsUtil.isGiveRecordTheUserCanConfirm(
|
||||
veriClaim,
|
||||
activeDid,
|
||||
confirmerIdList,
|
||||
)
|
||||
"
|
||||
@click="confirmConfirmClaim()"
|
||||
class="col-span-1 bg-gradient-to-b from-blue-400 to-blue-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-4 py-2 rounded-md"
|
||||
>
|
||||
Confirm
|
||||
<fa icon="circle-check" class="ml-2 text-white cursor-pointer" />
|
||||
</button>
|
||||
<button
|
||||
v-else
|
||||
@click="notifyWhyCannotConfirm()"
|
||||
class="col-span-1 bg-gradient-to-b from-slate-400 to-slate-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-4 py-2 rounded-md"
|
||||
>
|
||||
Confirm
|
||||
<fa icon="circle-check" class="ml-2 text-white cursor-pointer" />
|
||||
</button>
|
||||
<a
|
||||
class="col-span-1 bg-gradient-to-b from-blue-400 to-blue-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white ml-2 px-4 py-2 rounded-md"
|
||||
:href="urlForNewGive"
|
||||
>
|
||||
Record One of Your Own
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div v-if="libsUtil.isGiveAction(veriClaim)" class="mt-4">
|
||||
<h2 class="font-bold uppercase text-xl mt-8 mb-2">Confirmations</h2>
|
||||
|
||||
<span v-if="totalConfirmers() === 0">Nobody has confirmed this.</span>
|
||||
<span v-else-if="totalConfirmers() === 1">
|
||||
One person has confirmed this.
|
||||
</span>
|
||||
<span v-else>
|
||||
{{ totalConfirmers() }} people have confirmed this.
|
||||
</span>
|
||||
|
||||
<div v-if="totalConfirmers() > 0">
|
||||
<div
|
||||
v-if="
|
||||
confirmerIdList.length === 0 && confsVisibleToIdList.length === 0
|
||||
"
|
||||
>
|
||||
Nobody that you know confirmed this claim, nor do they have any
|
||||
confirmers in their network.
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="
|
||||
confirmerIdList.length === 0 && confsVisibleToIdList.length > 0
|
||||
"
|
||||
>
|
||||
<!-- Only show if this person has links to confirmers (below). -->
|
||||
Nobody that you know has issued or confirmed this claim.
|
||||
</div>
|
||||
<div v-if="confirmerIdList.length > 0">
|
||||
The following people have issued or confirmed this claim.
|
||||
<ul class="ml-4">
|
||||
<li
|
||||
v-for="confirmerId in confirmerIdList"
|
||||
:key="confirmerId"
|
||||
class="list-disc ml-4"
|
||||
>
|
||||
<div class="flex gap-4">
|
||||
<div class="grow overflow-hidden">
|
||||
<div class="text-sm">
|
||||
{{ didInfo(confirmerId) }}
|
||||
<span v-if="!serverUtil.isEmptyOrHiddenDid(confirmerId)">
|
||||
<button
|
||||
@click="
|
||||
copyToClipboard(
|
||||
'The DID of ' + confirmerId,
|
||||
confirmerId,
|
||||
)
|
||||
"
|
||||
>
|
||||
<fa icon="copy" class="text-slate-400 fa-fw" />
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!--
|
||||
Never need to show this message:
|
||||
"Nobody that you know can see someone who has confirmed this claim."
|
||||
|
||||
If there is nobody in the confirmerIdList then we'll show the combined "nobody" message.
|
||||
If there is somebody in the confirmerIdList then that's all they need to show.
|
||||
-->
|
||||
|
||||
<!-- Now show anyone linked to confirmers. -->
|
||||
<div v-if="confsVisibleToIdList.length > 0">
|
||||
The following people can connect you with people who have issued or
|
||||
confirmed this claim.
|
||||
<ul class="ml-4">
|
||||
<li
|
||||
v-for="confsVisibleTo in confsVisibleToIdList"
|
||||
:key="confsVisibleTo"
|
||||
class="list-disc ml-4"
|
||||
>
|
||||
<div class="flex gap-4">
|
||||
<div class="grow overflow-hidden">
|
||||
<div class="text-sm">
|
||||
{{ didInfo(confsVisibleTo) }}
|
||||
<span
|
||||
v-if="!serverUtil.isEmptyOrHiddenDid(confsVisibleTo)"
|
||||
>
|
||||
<button
|
||||
@click="
|
||||
copyToClipboard(
|
||||
'The DID of ' + confsVisibleTo,
|
||||
confsVisibleTo,
|
||||
)
|
||||
"
|
||||
>
|
||||
<fa icon="copy" class="text-slate-400 fa-fw" />
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- explain if user cannot confirm -->
|
||||
<!-- Note that these conditions are mirrored in userCanConfirm(). -->
|
||||
<div v-if="confirmerIdList.includes(activeDid)">
|
||||
You have confirmed this claim.
|
||||
</div>
|
||||
<div v-else-if="veriClaim.issuer == activeDid">
|
||||
You cannot confirm this because you issued this claim, so you already
|
||||
count as confirming it.
|
||||
</div>
|
||||
<div v-else-if="serverUtil.containsHiddenDid(veriClaim.claim)">
|
||||
You cannot confirm this because it contains hidden identifiers.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2
|
||||
class="font-bold uppercase text-xl text-blue-500 mt-8 mb-2 cursor-pointer"
|
||||
@click="showDetails = !showDetails"
|
||||
>
|
||||
{{ serverUtil.containsHiddenDid(veriClaim) ? "Visible " : "" }}Details
|
||||
<span v-if="!showDetails">...</span>
|
||||
</h2>
|
||||
<div v-if="showDetails">
|
||||
<div
|
||||
v-if="
|
||||
serverUtil.containsHiddenDid(veriClaim) &&
|
||||
R.isEmpty(veriClaimDidsVisible)
|
||||
"
|
||||
class="mb-2"
|
||||
>
|
||||
Some of the details are not visible to you; they show as "HIDDEN".
|
||||
They are not visible to any of your direct contacts, either.
|
||||
<span v-if="canShare">
|
||||
If you'd like to ask any of your contacts to take a look and see if
|
||||
their contacts can see more details,
|
||||
<a @click="onClickShareClaim()" class="text-blue-500"
|
||||
>click to send them this info</a
|
||||
>
|
||||
and see if they are willing to make an introduction.
|
||||
</span>
|
||||
<span v-else>
|
||||
If you'd like to ask any of your contacts to take a look and see if
|
||||
their contacts can see more details,
|
||||
<a
|
||||
@click="copyToClipboard('Location', windowLocation.href)"
|
||||
class="text-blue-500"
|
||||
>share this page with them</a
|
||||
>
|
||||
and see if they are willing to make an introduction.
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div v-if="!R.isEmpty(veriClaimDidsVisible)">
|
||||
Some of the details are not visible to you but they are visible to
|
||||
some of your contacts.
|
||||
<span v-if="canShare">
|
||||
If you'd like an introduction,
|
||||
<a @click="onClickShareClaim()" class="text-blue-500"
|
||||
>click to share the information with them and ask if they'll tell
|
||||
you more about the participants.</a
|
||||
>
|
||||
</span>
|
||||
<span v-else>
|
||||
If you'd like an introduction,
|
||||
<a
|
||||
@click="copyToClipboard('Location', windowLocation.href)"
|
||||
class="text-blue-500"
|
||||
>share this page with them and ask if they'll tell you more about
|
||||
about the participants.</a
|
||||
>
|
||||
</span>
|
||||
|
||||
<div
|
||||
v-for="(visibleDidPath, index) of Object.keys(veriClaimDidsVisible)"
|
||||
:key="index"
|
||||
class="list-disc p-4"
|
||||
>
|
||||
<div class="text-sm">
|
||||
<fa icon="minus" class="fa-fw" />
|
||||
The {{ visibleDidPath }} is visible to:
|
||||
</div>
|
||||
<div class="ml-12 p-1">
|
||||
<ul>
|
||||
<li
|
||||
v-for="(visDid, idx2) of veriClaimDidsVisible[visibleDidPath]"
|
||||
:key="idx2"
|
||||
class="list-disc"
|
||||
>
|
||||
<div class="text-sm mt-2">
|
||||
<span>
|
||||
{{ didInfo(visDid) }}
|
||||
<span v-if="!serverUtil.isEmptyOrHiddenDid(visDid)">
|
||||
<button
|
||||
@click="
|
||||
copyToClipboard('The DID of ' + visDid, visDid)
|
||||
"
|
||||
>
|
||||
<fa icon="copy" class="text-slate-400 fa-fw" />
|
||||
</button>
|
||||
</span>
|
||||
<span v-if="veriClaim.publicUrls?.[visDid]"
|
||||
>, found at
|
||||
<fa icon="globe" class="fa-fw text-slate-400" />
|
||||
<a
|
||||
:href="veriClaim.publicUrls?.[visDid]"
|
||||
class="text-blue-500"
|
||||
>{{
|
||||
veriClaim.publicUrls[visDid].substring(
|
||||
veriClaim.publicUrls[visDid].indexOf("//") + 2,
|
||||
)
|
||||
}}
|
||||
</a>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Keep the dump contents directly between > and < to avoid weird spacing. -->
|
||||
<pre
|
||||
class="text-sm overflow-x-scroll px-4 py-3 bg-slate-100 rounded-md"
|
||||
>{{ veriClaimDump }}</pre
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else>This does not have details to confirm.</div>
|
||||
|
||||
<div class="mt-4">
|
||||
<a
|
||||
@click="showClaimPage(veriClaim.id)"
|
||||
class="text-blue-500 cursor-pointer"
|
||||
>
|
||||
<fa icon="file-lines" class="pl-2" />
|
||||
All Generic Info
|
||||
</a>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { AxiosError, RawAxiosRequestHeaders } from "axios";
|
||||
import * as yaml from "js-yaml";
|
||||
import * as R from "ramda";
|
||||
import { IIdentifier } from "@veramo/core";
|
||||
import { Component, Vue } from "vue-facing-decorator";
|
||||
import { useClipboard } from "@vueuse/core";
|
||||
|
||||
import GiftedDialog from "@/components/GiftedDialog.vue";
|
||||
import QuickNav from "@/components/QuickNav.vue";
|
||||
import { NotificationIface } from "@/constants/app";
|
||||
import { accountsDB, db } from "@/db/index";
|
||||
import { Account } from "@/db/tables/accounts";
|
||||
import { Contact } from "@/db/tables/contacts";
|
||||
import { MASTER_SETTINGS_KEY, Settings } from "@/db/tables/settings";
|
||||
import { accessToken } from "@/libs/crypto";
|
||||
import * as serverUtil from "@/libs/endorserServer";
|
||||
import { displayAmount, GiverReceiverInputInfo } from "@/libs/endorserServer";
|
||||
import * as libsUtil from "@/libs/util";
|
||||
import { isGiveAction } from "@/libs/util";
|
||||
|
||||
@Component({
|
||||
methods: { displayAmount },
|
||||
components: { GiftedDialog, QuickNav },
|
||||
})
|
||||
export default class ClaimView extends Vue {
|
||||
$notify!: (notification: NotificationIface, timeout?: number) => void;
|
||||
|
||||
accountIdentityStr: string = "null";
|
||||
activeDid = "";
|
||||
allMyDids: Array<string> = [];
|
||||
allContacts: Array<Contact> = [];
|
||||
apiServer = "";
|
||||
|
||||
canShare = false;
|
||||
confirmerIdList: string[] = []; // list of DIDs that have confirmed this claim excluding the issuer
|
||||
confsVisibleErrorMessage = "";
|
||||
confsVisibleToIdList: string[] = []; // list of DIDs that can see any confirmer
|
||||
detailsForGive = null;
|
||||
giverName = "";
|
||||
issuerName = "";
|
||||
numConfsNotVisible = 0; // number of hidden DIDs in the confirmerIdList, minus the issuer if they aren't visible
|
||||
recipientName = "";
|
||||
showDetails = false;
|
||||
urlForNewGive = "";
|
||||
veriClaim = serverUtil.BLANK_GENERIC_SERVER_RECORD;
|
||||
veriClaimDump = "";
|
||||
veriClaimDidsVisible = {};
|
||||
windowLocation = window.location;
|
||||
|
||||
R = R;
|
||||
yaml = yaml;
|
||||
libsUtil = libsUtil;
|
||||
serverUtil = serverUtil;
|
||||
|
||||
resetThisValues() {
|
||||
this.confirmerIdList = [];
|
||||
this.confsVisibleErrorMessage = "";
|
||||
this.confsVisibleToIdList = [];
|
||||
this.detailsForGive = null;
|
||||
this.numConfsNotVisible = 0;
|
||||
this.urlForNewGive = "";
|
||||
this.veriClaim = serverUtil.BLANK_GENERIC_SERVER_RECORD;
|
||||
this.veriClaimDump = "";
|
||||
}
|
||||
|
||||
async mounted() {
|
||||
await db.open();
|
||||
const settings = (await db.settings.get(MASTER_SETTINGS_KEY)) as Settings;
|
||||
this.activeDid = settings?.activeDid || "";
|
||||
this.apiServer = settings?.apiServer || "";
|
||||
this.allContacts = await db.contacts.toArray();
|
||||
|
||||
await accountsDB.open();
|
||||
const accounts = accountsDB.accounts;
|
||||
const accountsArr: Array<Account> = await accounts?.toArray();
|
||||
this.allMyDids = accountsArr.map((acc) => acc.did);
|
||||
const account = accountsArr.find((acc) => acc.did === this.activeDid);
|
||||
this.accountIdentityStr = (account?.identity as string) || "null";
|
||||
const identity = JSON.parse(this.accountIdentityStr);
|
||||
|
||||
const pathParam = window.location.pathname.substring(
|
||||
"/confirm-gift/".length,
|
||||
);
|
||||
let claimId;
|
||||
if (pathParam) {
|
||||
claimId = decodeURIComponent(pathParam);
|
||||
await this.loadClaim(claimId, identity);
|
||||
} else {
|
||||
this.$notify(
|
||||
{
|
||||
group: "alert",
|
||||
type: "danger",
|
||||
title: "Error",
|
||||
text: "No claim ID was provided.",
|
||||
},
|
||||
3000,
|
||||
);
|
||||
}
|
||||
|
||||
// When Chrome compatibility is fixed https://developer.mozilla.org/en-US/docs/Web/API/Web_Share_API#api.navigator.canshare
|
||||
// then use this truer check: navigator.canShare && navigator.canShare()
|
||||
this.canShare = !!navigator.share;
|
||||
}
|
||||
|
||||
// insert a space before any capital letters except the initial letter
|
||||
// (and capitalize initial letter, just in case)
|
||||
capitalizeAndInsertSpacesBeforeCaps(text: string) {
|
||||
return !text
|
||||
? ""
|
||||
: text[0].toUpperCase() + text.substr(1).replace(/([A-Z])/g, " $1");
|
||||
}
|
||||
|
||||
capitalizeAndInsertSpacesBeforeCapsWithAPrefix(text: string) {
|
||||
const word = this.capitalizeAndInsertSpacesBeforeCaps(text);
|
||||
if (word) {
|
||||
// if the word starts with a vowel, use "an" instead of "a"
|
||||
const firstLetter = word[0].toLowerCase();
|
||||
const vowels = ["a", "e", "i", "o", "u"];
|
||||
const particle = vowels.includes(firstLetter) ? "an" : "a";
|
||||
return particle + " " + word;
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
totalConfirmers() {
|
||||
return (
|
||||
this.numConfsNotVisible +
|
||||
this.confirmerIdList.length +
|
||||
this.confsVisibleToIdList.length
|
||||
);
|
||||
}
|
||||
|
||||
public async getIdentity(activeDid: string): Promise<IIdentifier> {
|
||||
await accountsDB.open();
|
||||
const account = (await accountsDB.accounts
|
||||
.where("did")
|
||||
.equals(activeDid)
|
||||
.first()) as Account;
|
||||
const identity = JSON.parse(account?.identity || "null");
|
||||
|
||||
if (!identity) {
|
||||
throw new Error(
|
||||
"Attempted to load project records with no identifier available.",
|
||||
);
|
||||
}
|
||||
return identity;
|
||||
}
|
||||
|
||||
public async getHeaders(identity: IIdentifier) {
|
||||
const headers: RawAxiosRequestHeaders = {
|
||||
"Content-Type": "application/json",
|
||||
};
|
||||
if (identity) {
|
||||
const token = await accessToken(identity);
|
||||
headers["Authorization"] = "Bearer " + token;
|
||||
}
|
||||
return headers;
|
||||
}
|
||||
|
||||
// Isn't there a better way to make this available to the template?
|
||||
didInfo(did: string | undefined) {
|
||||
return serverUtil.didInfo(
|
||||
did,
|
||||
this.activeDid,
|
||||
this.allMyDids,
|
||||
this.allContacts,
|
||||
);
|
||||
}
|
||||
|
||||
async loadClaim(claimId: string, identity: IIdentifier) {
|
||||
const urlPath = libsUtil.isGlobalUri(claimId)
|
||||
? "/api/claim/byHandle/"
|
||||
: "/api/claim/";
|
||||
const url = this.apiServer + urlPath + encodeURIComponent(claimId);
|
||||
|
||||
try {
|
||||
const headers = await this.getHeaders(identity);
|
||||
const resp = await this.axios.get(url, { headers });
|
||||
// resp.data is:
|
||||
// - a Jwt from https://api.endorser.ch/api-docs/
|
||||
// - with a Give from https://endorser.ch/doc/html/transactions.html#id3
|
||||
if (resp.status === 200) {
|
||||
this.veriClaim = resp.data;
|
||||
this.veriClaimDump = yaml.dump(this.veriClaim);
|
||||
this.veriClaimDidsVisible = libsUtil.findAllVisibleToDids(
|
||||
this.veriClaim,
|
||||
true,
|
||||
);
|
||||
} else {
|
||||
// actually, axios typically throws an error so we never get here
|
||||
console.error("Error getting claim:", resp);
|
||||
this.$notify(
|
||||
{
|
||||
group: "alert",
|
||||
type: "danger",
|
||||
title: "Error",
|
||||
text: "There was a problem retrieving that claim.",
|
||||
},
|
||||
3000,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// retrieve more details on Give, Offer, or Plan
|
||||
if (this.veriClaim.claimType !== "GiveAction") {
|
||||
// no need to go further... this page is for gifts
|
||||
return;
|
||||
}
|
||||
|
||||
this.issuerName = this.didInfo(this.veriClaim.issuer);
|
||||
|
||||
this.urlForNewGive = "/gifted-details?";
|
||||
if (this.veriClaim.claim.object) {
|
||||
if (this.veriClaim.claim.object.amountOfThisGood) {
|
||||
this.urlForNewGive +=
|
||||
"&amountInput=" +
|
||||
encodeURIComponent(
|
||||
String(this.veriClaim.claim.object.amountOfThisGood),
|
||||
);
|
||||
}
|
||||
if (this.veriClaim.claim.object.unitCode) {
|
||||
this.urlForNewGive +=
|
||||
"&unitCode=" +
|
||||
encodeURIComponent(this.veriClaim.claim.object.unitCode as string);
|
||||
}
|
||||
}
|
||||
if (this.veriClaim.claim.description) {
|
||||
this.urlForNewGive +=
|
||||
"&description=" +
|
||||
encodeURIComponent(this.veriClaim.claim.description as string);
|
||||
}
|
||||
this.giverName = this.didInfo(
|
||||
this.veriClaim.claim.agent?.identifier as string,
|
||||
);
|
||||
if (this.veriClaim.claim.agent) {
|
||||
this.urlForNewGive +=
|
||||
"&giverDid=" +
|
||||
encodeURIComponent(this.veriClaim.claim.agent.identifier as string) +
|
||||
"&giverName=" +
|
||||
encodeURIComponent(this.giverName);
|
||||
}
|
||||
this.recipientName = this.didInfo(
|
||||
this.veriClaim.claim.recipient?.identifier as string,
|
||||
);
|
||||
if (this.veriClaim.claim.recipient) {
|
||||
this.urlForNewGive +=
|
||||
"&recipientDid=" +
|
||||
encodeURIComponent(
|
||||
this.veriClaim.claim.recipient.identifier as string,
|
||||
) +
|
||||
"&recipientName=" +
|
||||
encodeURIComponent(this.recipientName);
|
||||
}
|
||||
if (this.veriClaim.claim.image) {
|
||||
this.urlForNewGive +=
|
||||
"&image=" + encodeURIComponent(this.veriClaim.claim.image as string);
|
||||
}
|
||||
if (this.veriClaim.claim.fulfills) {
|
||||
this.urlForNewGive += this.fulfillsUrlSnippet(
|
||||
this.veriClaim.claim.fulfills,
|
||||
);
|
||||
if (Array.isArray(this.veriClaim.claim.fulfills)) {
|
||||
for (const fulfills of this.veriClaim.claim.fulfills) {
|
||||
console.log("adding fulfills:", fulfills);
|
||||
this.urlForNewGive += this.fulfillsUrlSnippet(fulfills);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const giveUrl =
|
||||
this.apiServer +
|
||||
"/api/v2/report/gives?handleId=" +
|
||||
encodeURIComponent(this.veriClaim.handleId as string);
|
||||
const giveHeaders = await this.getHeaders(identity);
|
||||
const giveResp = await this.axios.get(giveUrl, {
|
||||
headers: giveHeaders,
|
||||
});
|
||||
// giveResp.data is a Give from https://api.endorser.ch/api-docs/
|
||||
if (giveResp.status === 200) {
|
||||
this.detailsForGive = giveResp.data.data[0];
|
||||
} else {
|
||||
console.error("Error getting detailed give info:", giveResp);
|
||||
this.$notify(
|
||||
{
|
||||
group: "alert",
|
||||
type: "danger",
|
||||
title: "Error",
|
||||
text: "Something went wrong retrieving gift data.",
|
||||
},
|
||||
3000,
|
||||
);
|
||||
}
|
||||
|
||||
// retrieve the list of confirmers
|
||||
const confirmUrl =
|
||||
this.apiServer +
|
||||
"/api/report/issuersWhoClaimedOrConfirmed?claimId=" +
|
||||
encodeURIComponent(serverUtil.stripEndorserPrefix(claimId));
|
||||
const confirmHeaders = await this.getHeaders(identity);
|
||||
const response = await this.axios.get(confirmUrl, {
|
||||
headers: confirmHeaders,
|
||||
});
|
||||
if (response.status === 200) {
|
||||
const resultList1 = response.data.result || [];
|
||||
const resultList2 = R.reject(serverUtil.isHiddenDid, resultList1);
|
||||
const resultList3 = R.reject(
|
||||
(did: string) => did === this.veriClaim.issuer,
|
||||
resultList2,
|
||||
);
|
||||
this.confirmerIdList = resultList3;
|
||||
this.numConfsNotVisible = resultList1.length - resultList2.length;
|
||||
if (resultList3.length === resultList2.length) {
|
||||
// the issuer was not in the "visible" list so they must be hidden
|
||||
// so subtract them from the non-visible confirmers count
|
||||
this.numConfsNotVisible = this.numConfsNotVisible - 1;
|
||||
}
|
||||
this.confsVisibleToIdList =
|
||||
response.data.result.resultVisibleToDids || [];
|
||||
} else {
|
||||
this.confsVisibleErrorMessage =
|
||||
"Had problems retrieving confirmations.";
|
||||
}
|
||||
} catch (error: unknown) {
|
||||
const serverError = error as AxiosError;
|
||||
console.error("Error retrieving claim:", serverError);
|
||||
this.$notify(
|
||||
{
|
||||
group: "alert",
|
||||
type: "danger",
|
||||
title: "Error",
|
||||
text: "Something went wrong retrieving claim data.",
|
||||
},
|
||||
3000,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fulfillsUrlSnippet(object) {
|
||||
if (object["@type"] === "PlanAction") {
|
||||
return "&projectId=" + encodeURIComponent(object.identifier);
|
||||
} else if (object["@type"] === "OfferAction") {
|
||||
return "&offerId=" + encodeURIComponent(object.identifier);
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
confirmConfirmClaim() {
|
||||
this.$notify(
|
||||
{
|
||||
group: "modal",
|
||||
type: "confirm",
|
||||
title: "Confirm",
|
||||
text: "Do you personally confirm that this is true?",
|
||||
onYes: async () => {
|
||||
await this.confirmClaim();
|
||||
},
|
||||
},
|
||||
-1,
|
||||
);
|
||||
}
|
||||
|
||||
// similar code is found in ProjectViewView
|
||||
async confirmClaim() {
|
||||
// similar logic is found in endorser-mobile
|
||||
const goodClaim = serverUtil.removeSchemaContext(
|
||||
serverUtil.removeVisibleToDids(
|
||||
serverUtil.addLastClaimOrHandleAsIdIfMissing(
|
||||
this.veriClaim.claim,
|
||||
this.veriClaim.id,
|
||||
this.veriClaim.handleId,
|
||||
),
|
||||
),
|
||||
);
|
||||
const confirmationClaim: serverUtil.GenericVerifiableCredential = {
|
||||
"@context": "https://schema.org",
|
||||
"@type": "AgreeAction",
|
||||
object: goodClaim,
|
||||
};
|
||||
const result = await serverUtil.createAndSubmitClaim(
|
||||
confirmationClaim,
|
||||
await this.getIdentity(this.activeDid),
|
||||
this.apiServer,
|
||||
this.axios,
|
||||
);
|
||||
if (result.type === "success") {
|
||||
this.$notify(
|
||||
{
|
||||
group: "alert",
|
||||
type: "success",
|
||||
title: "Success",
|
||||
text: "Confirmation submitted.",
|
||||
},
|
||||
5000,
|
||||
);
|
||||
} else {
|
||||
console.error("Got error submitting the confirmation:", result);
|
||||
this.$notify(
|
||||
{
|
||||
group: "alert",
|
||||
type: "danger",
|
||||
title: "Error",
|
||||
text: "There was a problem submitting the confirmation. See logs for more info.",
|
||||
},
|
||||
5000,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
showClaimPage(claimId: string) {
|
||||
const route = {
|
||||
path: "/claim/" + encodeURIComponent(claimId),
|
||||
};
|
||||
this.$router.push(route).then(async () => {
|
||||
this.resetThisValues();
|
||||
await this.loadClaim(claimId, JSON.parse(this.accountIdentityStr));
|
||||
});
|
||||
}
|
||||
|
||||
openFulfillGiftDialog() {
|
||||
const giver: GiverReceiverInputInfo = {
|
||||
did: libsUtil.offerGiverDid(this.veriClaim),
|
||||
};
|
||||
(this.$refs.customGiveDialog as GiftedDialog).open(
|
||||
giver,
|
||||
undefined,
|
||||
this.veriClaim.handleId,
|
||||
"Offer fulfilled by " + (giver?.name || "someone not named"),
|
||||
);
|
||||
}
|
||||
|
||||
copyToClipboard(name: string, text: string) {
|
||||
useClipboard()
|
||||
.copy(text)
|
||||
.then(() => {
|
||||
this.$notify(
|
||||
{
|
||||
group: "alert",
|
||||
type: "toast",
|
||||
title: "Copied",
|
||||
text: (name || "That") + " was copied to the clipboard.",
|
||||
},
|
||||
2000,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
notifyWhyCannotConfirm() {
|
||||
if (!isGiveAction(this.veriClaim)) {
|
||||
this.$notify(
|
||||
{
|
||||
group: "alert",
|
||||
type: "info",
|
||||
title: "Not A Give",
|
||||
text: "This is not a giving action to confirm.",
|
||||
},
|
||||
3000,
|
||||
);
|
||||
} else if (this.confirmerIdList.includes(this.activeDid)) {
|
||||
this.$notify(
|
||||
{
|
||||
group: "alert",
|
||||
type: "info",
|
||||
title: "Already Confirmed",
|
||||
text: "You have already confirmed this claim.",
|
||||
},
|
||||
3000,
|
||||
);
|
||||
} else if (this.veriClaim.issuer == this.activeDid) {
|
||||
this.$notify(
|
||||
{
|
||||
group: "alert",
|
||||
type: "info",
|
||||
title: "Cannot Confirm",
|
||||
text: "You cannot confirm this because you issued this claim.",
|
||||
},
|
||||
3000,
|
||||
);
|
||||
} else if (serverUtil.containsHiddenDid(this.veriClaim.claim)) {
|
||||
this.$notify(
|
||||
{
|
||||
group: "alert",
|
||||
type: "info",
|
||||
title: "Cannot Confirm",
|
||||
text: "You cannot confirm this because it contains hidden identifiers.",
|
||||
},
|
||||
3000,
|
||||
);
|
||||
} else {
|
||||
this.$notify(
|
||||
{
|
||||
group: "alert",
|
||||
type: "info",
|
||||
title: "Cannot Confirm",
|
||||
text: "You cannot confirm this claim.",
|
||||
},
|
||||
3000,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
onClickShareClaim() {
|
||||
window.navigator.share({
|
||||
title: "Help Connect Me",
|
||||
text: "I'm trying to find the full details of this claim. Can you help me?",
|
||||
url: this.windowLocation.href,
|
||||
});
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -100,7 +100,7 @@
|
||||
>
|
||||
<a
|
||||
@click="onClickLoadProject(project.handleId)"
|
||||
class="block py-4 flex gap-4"
|
||||
class="block py-4 flex gap-4 cursor-pointer"
|
||||
>
|
||||
<div>
|
||||
<ProjectIcon
|
||||
|
||||
@@ -233,7 +233,7 @@ export default class GiftedDetails extends Vue {
|
||||
}
|
||||
|
||||
if (this.projectId) {
|
||||
console.log("Getting project name from cache", this.projectId);
|
||||
// console.log("Getting project name from cache", this.projectId);
|
||||
const identity = await libsUtil.getIdentity(this.activeDid);
|
||||
const project = await getPlanFromCache(
|
||||
this.projectId,
|
||||
@@ -241,7 +241,7 @@ export default class GiftedDetails extends Vue {
|
||||
this.axios,
|
||||
this.apiServer,
|
||||
);
|
||||
console.log("Got project name from cache", project);
|
||||
// console.log("Got project name from cache", project);
|
||||
this.projectName = project?.name
|
||||
? "the project: " + project.name
|
||||
: "a project";
|
||||
|
||||
@@ -72,7 +72,7 @@
|
||||
<div class="mb-8">
|
||||
<div v-if="isCreatingIdentifier">
|
||||
<p class="text-slate-500 text-center italic mt-4 mb-4">
|
||||
<fa icon="spinner" class="fa-spin-pulse"></fa> Loading…
|
||||
<fa icon="spinner" class="fa-spin-pulse" /> Loading…
|
||||
</p>
|
||||
</div>
|
||||
<div
|
||||
@@ -132,7 +132,7 @@
|
||||
<EntityIcon
|
||||
:contact="contact"
|
||||
:iconSize="64"
|
||||
class="mx-auto border border-slate-300 rounded-md mb-1"
|
||||
class="mx-auto border border-slate-300 rounded-md mb-1 cursor-pointer"
|
||||
/>
|
||||
<h3
|
||||
class="text-xs font-medium text-ellipsis whitespace-nowrap overflow-hidden"
|
||||
@@ -145,7 +145,7 @@
|
||||
<div class="flex justify-between">
|
||||
<router-link
|
||||
v-if="allContacts.length >= 7"
|
||||
:to="{ name: 'contact-gives' }"
|
||||
:to="{ name: 'contact-gift' }"
|
||||
class="block text-center text-md font-bold bg-gradient-to-b from-slate-400 to-slate-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-2 py-3 rounded-md"
|
||||
>
|
||||
Choose From All Contacts
|
||||
@@ -251,7 +251,7 @@
|
||||
<fa
|
||||
icon="file-lines"
|
||||
class="pl-2 text-blue-500 cursor-pointer"
|
||||
></fa>
|
||||
/>
|
||||
</a>
|
||||
</span>
|
||||
<span class="col-span-1 justify-self-end">
|
||||
@@ -262,7 +262,7 @@
|
||||
encodeURIComponent(record.fulfillsPlanHandleId)
|
||||
"
|
||||
>
|
||||
<fa icon="hammer" class="text-blue-500"></fa>
|
||||
<fa icon="hammer" class="text-blue-500" />
|
||||
</router-link>
|
||||
</span>
|
||||
</div>
|
||||
@@ -276,7 +276,7 @@
|
||||
</InfiniteScroll>
|
||||
<div v-if="isFeedLoading">
|
||||
<p class="text-slate-500 text-center italic mt-4 mb-4">
|
||||
<fa icon="spinner" class="fa-spin-pulse"></fa> Loading…
|
||||
<fa icon="spinner" class="fa-spin-pulse" /> Loading…
|
||||
</p>
|
||||
</div>
|
||||
<div v-if="!isFeedLoading && feedData.length === 0">
|
||||
|
||||
@@ -112,10 +112,15 @@ export default class IdentitySwitcherView extends Vue {
|
||||
await accountsDB.open();
|
||||
const accounts = await accountsDB.accounts.toArray();
|
||||
for (let n = 0; n < accounts.length; n++) {
|
||||
const did = JSON.parse(accounts[n].identity)["did"];
|
||||
this.otherIdentities.push({ did: did });
|
||||
if (did && this.activeDid === did) {
|
||||
this.activeDidInIdentities = true;
|
||||
try {
|
||||
const did = JSON.parse(accounts[n].identity)["did"];
|
||||
this.otherIdentities.push({ did: did });
|
||||
if (did && this.activeDid === did) {
|
||||
this.activeDidInIdentities = true;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Error parsing identity:", err);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
|
||||
@@ -161,7 +161,7 @@
|
||||
<EntityIcon
|
||||
:contact="contact"
|
||||
:iconSize="64"
|
||||
class="mx-auto border border-slate-300 rounded-md mb-1"
|
||||
class="mx-auto border border-slate-300 rounded-md mb-1 cursor-pointer"
|
||||
/>
|
||||
<h3
|
||||
class="text-xs font-medium text-ellipsis whitespace-nowrap overflow-hidden"
|
||||
@@ -795,7 +795,7 @@ export default class ProjectViewView extends Vue {
|
||||
onClickAllContactsGifting() {
|
||||
localStorage.setItem("projectId", this.projectId);
|
||||
const route = {
|
||||
name: "contact-gives",
|
||||
name: "contact-gift",
|
||||
};
|
||||
this.$router.push(route);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user