Merge branch 'master' into passkey
This commit is contained in:
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
|
|
||||||
## [0.3.14]
|
## [0.3.14]
|
||||||
|
### Added
|
||||||
|
- Clearer give-confirmation screen
|
||||||
|
- BX currency https://thebx.medium.com/
|
||||||
|
- Deselection of project on gifted details page
|
||||||
|
### Fixed
|
||||||
|
- Don't show registration pop-up for a new contact that is registered
|
||||||
### Changed in DB or environment
|
### Changed in DB or environment
|
||||||
- Nothing
|
- Nothing
|
||||||
|
|
||||||
|
|||||||
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "TimeSafari",
|
"name": "TimeSafari",
|
||||||
"version": "0.3.14-beta",
|
"version": "0.3.15-beta",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "TimeSafari",
|
"name": "TimeSafari",
|
||||||
"version": "0.3.14-beta",
|
"version": "0.3.15-beta",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@dicebear/collection": "^5.4.1",
|
"@dicebear/collection": "^5.4.1",
|
||||||
"@dicebear/core": "^5.4.1",
|
"@dicebear/core": "^5.4.1",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "TimeSafari",
|
"name": "TimeSafari",
|
||||||
"version": "0.3.14-beta",
|
"version": "0.3.15-beta",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
"serve": "vite preview",
|
"serve": "vite preview",
|
||||||
|
|||||||
@@ -54,7 +54,7 @@
|
|||||||
}"
|
}"
|
||||||
class="text-blue-500"
|
class="text-blue-500"
|
||||||
>
|
>
|
||||||
Photo, ...
|
Photo & Details ...
|
||||||
</router-link>
|
</router-link>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ export const PRIVACY_MESSAGE =
|
|||||||
|
|
||||||
/* eslint-disable prettier/prettier */
|
/* eslint-disable prettier/prettier */
|
||||||
export const UNIT_SHORT: Record<string, string> = {
|
export const UNIT_SHORT: Record<string, string> = {
|
||||||
|
"BX": "BX",
|
||||||
"BTC": "BTC",
|
"BTC": "BTC",
|
||||||
"ETH": "ETH",
|
"ETH": "ETH",
|
||||||
"HUR": "Hours",
|
"HUR": "Hours",
|
||||||
@@ -26,6 +27,7 @@ export const UNIT_SHORT: Record<string, string> = {
|
|||||||
|
|
||||||
/* eslint-disable prettier/prettier */
|
/* eslint-disable prettier/prettier */
|
||||||
export const UNIT_LONG: Record<string, string> = {
|
export const UNIT_LONG: Record<string, string> = {
|
||||||
|
"BX": "Buxbe",
|
||||||
"BTC": "Bitcoin",
|
"BTC": "Bitcoin",
|
||||||
"ETH": "Ethereum",
|
"ETH": "Ethereum",
|
||||||
"HUR": "hours",
|
"HUR": "hours",
|
||||||
@@ -70,7 +72,7 @@ export const isGlobalUri = (uri: string) => {
|
|||||||
return uri && uri.match(new RegExp(/^[A-Za-z][A-Za-z0-9+.-]+:/));
|
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";
|
return veriClaim.claimType === "GiveAction";
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -91,7 +93,7 @@ export const isGiveRecordTheUserCanConfirm = (
|
|||||||
confirmerIdList: string[] = [],
|
confirmerIdList: string[] = [],
|
||||||
) => {
|
) => {
|
||||||
return (
|
return (
|
||||||
giveIsConfirmable(veriClaim) &&
|
isGiveAction(veriClaim) &&
|
||||||
!confirmerIdList.includes(activeDid) &&
|
!confirmerIdList.includes(activeDid) &&
|
||||||
veriClaim.issuer !== activeDid &&
|
veriClaim.issuer !== activeDid &&
|
||||||
!containsHiddenDid(veriClaim.claim)
|
!containsHiddenDid(veriClaim.claim)
|
||||||
|
|||||||
@@ -11,10 +11,12 @@ import "./assets/styles/tailwind.css";
|
|||||||
|
|
||||||
import { library } from "@fortawesome/fontawesome-svg-core";
|
import { library } from "@fortawesome/fontawesome-svg-core";
|
||||||
import {
|
import {
|
||||||
|
faArrowDown,
|
||||||
faArrowLeft,
|
faArrowLeft,
|
||||||
faArrowRight,
|
faArrowRight,
|
||||||
faArrowRotateBackward,
|
faArrowRotateBackward,
|
||||||
faArrowUpRightFromSquare,
|
faArrowUpRightFromSquare,
|
||||||
|
faArrowUp,
|
||||||
faBan,
|
faBan,
|
||||||
faBitcoinSign,
|
faBitcoinSign,
|
||||||
faBurst,
|
faBurst,
|
||||||
@@ -47,6 +49,7 @@ import {
|
|||||||
faGlobe,
|
faGlobe,
|
||||||
faHammer,
|
faHammer,
|
||||||
faHand,
|
faHand,
|
||||||
|
faHandHoldingDollar,
|
||||||
faHandHoldingHeart,
|
faHandHoldingHeart,
|
||||||
faHouseChimney,
|
faHouseChimney,
|
||||||
faImagePortrait,
|
faImagePortrait,
|
||||||
@@ -66,6 +69,7 @@ import {
|
|||||||
faRotate,
|
faRotate,
|
||||||
faShareNodes,
|
faShareNodes,
|
||||||
faSpinner,
|
faSpinner,
|
||||||
|
faSquare,
|
||||||
faSquareCaretDown,
|
faSquareCaretDown,
|
||||||
faSquareCaretUp,
|
faSquareCaretUp,
|
||||||
faSquarePlus,
|
faSquarePlus,
|
||||||
@@ -77,10 +81,12 @@ import {
|
|||||||
} from "@fortawesome/free-solid-svg-icons";
|
} from "@fortawesome/free-solid-svg-icons";
|
||||||
|
|
||||||
library.add(
|
library.add(
|
||||||
|
faArrowDown,
|
||||||
faArrowLeft,
|
faArrowLeft,
|
||||||
faArrowRight,
|
faArrowRight,
|
||||||
faArrowRotateBackward,
|
faArrowRotateBackward,
|
||||||
faArrowUpRightFromSquare,
|
faArrowUpRightFromSquare,
|
||||||
|
faArrowUp,
|
||||||
faBan,
|
faBan,
|
||||||
faBitcoinSign,
|
faBitcoinSign,
|
||||||
faBurst,
|
faBurst,
|
||||||
@@ -113,6 +119,7 @@ library.add(
|
|||||||
faGlobe,
|
faGlobe,
|
||||||
faHammer,
|
faHammer,
|
||||||
faHand,
|
faHand,
|
||||||
|
faHandHoldingDollar,
|
||||||
faHandHoldingHeart,
|
faHandHoldingHeart,
|
||||||
faHouseChimney,
|
faHouseChimney,
|
||||||
faImagePortrait,
|
faImagePortrait,
|
||||||
@@ -132,6 +139,7 @@ library.add(
|
|||||||
faRotate,
|
faRotate,
|
||||||
faShareNodes,
|
faShareNodes,
|
||||||
faSpinner,
|
faSpinner,
|
||||||
|
faSquare,
|
||||||
faSquareCaretDown,
|
faSquareCaretDown,
|
||||||
faSquareCaretUp,
|
faSquareCaretUp,
|
||||||
faSquarePlus,
|
faSquarePlus,
|
||||||
|
|||||||
@@ -43,14 +43,19 @@ const routes: Array<RouteRecordRaw> = [
|
|||||||
name: "confirm-contact",
|
name: "confirm-contact",
|
||||||
component: () => import("../views/ConfirmContactView.vue"),
|
component: () => import("../views/ConfirmContactView.vue"),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: "/confirm-gift/:id?",
|
||||||
|
name: "confirm-gift",
|
||||||
|
component: () => import("@/views/ConfirmGiftView.vue"),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: "/contact-amounts",
|
path: "/contact-amounts",
|
||||||
name: "contact-amounts",
|
name: "contact-amounts",
|
||||||
component: () => import("../views/ContactAmountsView.vue"),
|
component: () => import("../views/ContactAmountsView.vue"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "/contact-gives",
|
path: "/contact-gift",
|
||||||
name: "contact-gives",
|
name: "contact-gift",
|
||||||
component: () => import("../views/ContactGiftingView.vue"),
|
component: () => import("../views/ContactGiftingView.vue"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -57,7 +57,7 @@
|
|||||||
<h2 class="text-xl font-semibold mb-2">
|
<h2 class="text-xl font-semibold mb-2">
|
||||||
{{ givenName }}
|
{{ givenName }}
|
||||||
<router-link :to="{ name: 'new-edit-account' }">
|
<router-link :to="{ name: 'new-edit-account' }">
|
||||||
<fa icon="pen" class="text-xs text-blue-500 mb-1"></fa>
|
<fa icon="pen" class="text-xs text-blue-500 ml-2 mb-1"></fa>
|
||||||
</router-link>
|
</router-link>
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
@@ -103,9 +103,9 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="mt-6">
|
<div class="mt-6">
|
||||||
<div class="flex justify-center text-center">
|
<div class="flex justify-center text-center">
|
||||||
People {{ profileImageUrl ? "without your image" : "" }} see this:
|
People {{ profileImageUrl ? "without your image" : "" }} see this
|
||||||
<br />
|
<br />
|
||||||
(if you've let them see your activity)
|
(if you've let them see your activity):
|
||||||
</div>
|
</div>
|
||||||
<div class="flex justify-center">
|
<div class="flex justify-center">
|
||||||
<EntityIcon
|
<EntityIcon
|
||||||
@@ -149,6 +149,12 @@
|
|||||||
</button>
|
</button>
|
||||||
<span v-show="showDidCopy">Copied</span>
|
<span v-show="showDidCopy">Copied</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="text-blue-500 text-sm font-bold">
|
||||||
|
<router-link :to="{ path: '/did/' + encodeURIComponent(activeDid) }">
|
||||||
|
Activity
|
||||||
|
</router-link>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Registration notice -->
|
<!-- Registration notice -->
|
||||||
@@ -387,7 +393,7 @@
|
|||||||
>
|
>
|
||||||
<!-- label -->
|
<!-- label -->
|
||||||
<span class="text-slate-500 text-sm font-bold">Contacts Display</span>
|
<span class="text-slate-500 text-sm font-bold">Contacts Display</span>
|
||||||
<span class="ml-2">Show amounts given</span>
|
<span class="ml-2">Show hours given & received</span>
|
||||||
<!-- toggle -->
|
<!-- toggle -->
|
||||||
<div class="relative ml-2">
|
<div class="relative ml-2">
|
||||||
<!-- input -->
|
<!-- input -->
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
@click="$router.go(-1)"
|
@click="$router.go(-1)"
|
||||||
class="text-lg text-center px-2 py-1 absolute -left-2 -top-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>
|
</button>
|
||||||
Verifiable Claim Details
|
Verifiable Claim Details
|
||||||
</h1>
|
</h1>
|
||||||
@@ -35,16 +35,16 @@
|
|||||||
"
|
"
|
||||||
class="ml-2 mr-2"
|
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>
|
</button>
|
||||||
<span v-show="showIdCopy">Copied ID</span>
|
<span v-show="showIdCopy">Copied ID</span>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<fa icon="message" class="fa-fw text-slate-400"></fa>
|
<fa icon="message" class="fa-fw text-slate-400" />
|
||||||
{{ veriClaim.claim?.description }}
|
{{ veriClaim.claim?.description }}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<fa icon="user" class="fa-fw text-slate-400"></fa>
|
<fa icon="user" class="fa-fw text-slate-400" />
|
||||||
{{ veriClaim.issuer }}
|
{{ veriClaim.issuer }}
|
||||||
<span v-if="!serverUtil.isEmptyOrHiddenDid(veriClaim.issuer)">
|
<span v-if="!serverUtil.isEmptyOrHiddenDid(veriClaim.issuer)">
|
||||||
<button
|
<button
|
||||||
@@ -56,13 +56,13 @@
|
|||||||
"
|
"
|
||||||
class="ml-2 mr-2"
|
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>
|
</button>
|
||||||
<span v-show="showDidCopy">Copied DID</span>
|
<span v-show="showDidCopy">Copied DID</span>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<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") }}
|
{{ veriClaim.issuedAt?.replace(/T/, " ").replace(/Z/, " UTC") }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -121,7 +121,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="columns-3">
|
<div class="flex columns-3">
|
||||||
<button
|
<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"
|
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="
|
v-if="
|
||||||
@@ -137,6 +137,16 @@
|
|||||||
<fa icon="circle-check" class="ml-2 text-white cursor-pointer" />
|
<fa icon="circle-check" class="ml-2 text-white cursor-pointer" />
|
||||||
</button>
|
</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
|
<button
|
||||||
v-if="libsUtil.canFulfillOffer(veriClaim)"
|
v-if="libsUtil.canFulfillOffer(veriClaim)"
|
||||||
@click="openFulfillGiftDialog()"
|
@click="openFulfillGiftDialog()"
|
||||||
@@ -148,7 +158,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<GiftedDialog ref="customGiveDialog" />
|
<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>
|
<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-if="totalConfirmers() === 0">Nobody has confirmed this.</span>
|
||||||
@@ -319,7 +329,7 @@
|
|||||||
class="list-disc p-4"
|
class="list-disc p-4"
|
||||||
>
|
>
|
||||||
<div class="text-sm">
|
<div class="text-sm">
|
||||||
<fa icon="minus" class="fa-fw"></fa>
|
<fa icon="minus" class="fa-fw" />
|
||||||
The {{ visibleDidPath }} is visible to:
|
The {{ visibleDidPath }} is visible to:
|
||||||
</div>
|
</div>
|
||||||
<div class="ml-12 p-1">
|
<div class="ml-12 p-1">
|
||||||
@@ -341,8 +351,7 @@
|
|||||||
</span>
|
</span>
|
||||||
<span v-if="veriClaim.publicUrls?.[visDid]"
|
<span v-if="veriClaim.publicUrls?.[visDid]"
|
||||||
>, found at
|
>, found at
|
||||||
<fa icon="globe" class="fa-fw text-slate-400"></fa
|
<fa icon="globe" class="fa-fw text-slate-400" /> <a
|
||||||
> <a
|
|
||||||
:href="veriClaim.publicUrls?.[visDid]"
|
:href="veriClaim.publicUrls?.[visDid]"
|
||||||
class="text-blue-500"
|
class="text-blue-500"
|
||||||
>{{
|
>{{
|
||||||
@@ -474,10 +483,10 @@ export default class ClaimView extends Vue {
|
|||||||
|
|
||||||
await accountsDB.open();
|
await accountsDB.open();
|
||||||
const accounts = accountsDB.accounts;
|
const accounts = accountsDB.accounts;
|
||||||
const accountsArr = await accounts?.toArray();
|
const accountsArr: Array<Account> = await accounts?.toArray();
|
||||||
this.allMyDids = accountsArr.map((acc) => acc.did);
|
this.allMyDids = accountsArr.map((acc) => acc.did);
|
||||||
const account = accountsArr.find((acc) => acc.did === this.activeDid);
|
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 identity = JSON.parse(this.accountIdentityStr);
|
||||||
|
|
||||||
const pathParam = window.location.pathname.substring("/claim/".length);
|
const pathParam = window.location.pathname.substring("/claim/".length);
|
||||||
@@ -666,7 +675,7 @@ export default class ClaimView extends Vue {
|
|||||||
const accounts = accountsDB.accounts;
|
const accounts = accountsDB.accounts;
|
||||||
const accountsArr: Account[] = await accounts?.toArray();
|
const accountsArr: Account[] = await accounts?.toArray();
|
||||||
const account = accountsArr.find((acc) => acc.did === this.activeDid);
|
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 =
|
const url =
|
||||||
this.apiServer + "/api/claim/full/" + encodeURIComponent(claimId);
|
this.apiServer + "/api/claim/full/" + encodeURIComponent(claimId);
|
||||||
|
|||||||
878
src/views/ConfirmGiftView.vue
Normal file
878
src/views/ConfirmGiftView.vue
Normal file
@@ -0,0 +1,878 @@
|
|||||||
|
<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="giveDetails">
|
||||||
|
<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 a Similar One
|
||||||
|
</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="giveDetails.amount">
|
||||||
|
<fa icon="hand-holding-dollar" class="fa-fw text-slate-400" />
|
||||||
|
{{ displayAmount(giveDetails.unit, giveDetails.amount) }}
|
||||||
|
</div>
|
||||||
|
<div v-if="giveDetails.description">
|
||||||
|
<fa icon="message" class="fa-fw text-slate-400" />
|
||||||
|
{{ giveDetails.amount ? "and:" : "" }}
|
||||||
|
{{ giveDetails.description }}
|
||||||
|
</div>
|
||||||
|
<div class="ml-6">to</div>
|
||||||
|
<div>
|
||||||
|
<fa icon="arrow-up" class="fa-fw text-slate-400" />
|
||||||
|
{{ recipientName }}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<fa icon="calendar" class="fa-fw text-slate-400" />
|
||||||
|
on
|
||||||
|
{{ giveDetails.issuedAt.substring(0, 10) }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Fullfills Links -->
|
||||||
|
|
||||||
|
<!-- fullfills links for a give -->
|
||||||
|
<div class="mt-2" v-if="giveDetails?.fulfillsPlanHandleId">
|
||||||
|
<router-link
|
||||||
|
:to="
|
||||||
|
'/project/' +
|
||||||
|
encodeURIComponent(giveDetails?.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="
|
||||||
|
giveDetails?.fulfillsType &&
|
||||||
|
giveDetails?.fulfillsType !== 'PlanAction' &&
|
||||||
|
giveDetails?.fulfillsHandleId
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<!-- router-link to /claim/ only changes URL path -->
|
||||||
|
<router-link
|
||||||
|
:to="
|
||||||
|
'/claim/' +
|
||||||
|
encodeURIComponent(giveDetails?.fulfillsHandleId)
|
||||||
|
"
|
||||||
|
class="text-blue-500 mt-2 cursor-pointer"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
This fulfills
|
||||||
|
{{
|
||||||
|
capitalizeAndInsertSpacesBeforeCapsWithAPrefix(
|
||||||
|
giveDetails.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="text-slate-400" />
|
||||||
|
{{ issuerName }} posted that.
|
||||||
|
</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="giveDetails.agentDid == 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"><fa icon="chevron-down" /></span>
|
||||||
|
<span v-else><fa icon="chevron-up" /></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
|
||||||
|
giveDetails = 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.giveDetails = 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);
|
||||||
|
|
||||||
|
// use give record when possible since it may include edits
|
||||||
|
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.giveDetails = 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,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.urlForNewGive = "/gifted-details?";
|
||||||
|
if (this.giveDetails.amount) {
|
||||||
|
this.urlForNewGive +=
|
||||||
|
"&amountInput=" + encodeURIComponent(String(this.giveDetails.amount));
|
||||||
|
}
|
||||||
|
if (this.giveDetails.unit) {
|
||||||
|
this.urlForNewGive +=
|
||||||
|
"&unitCode=" + encodeURIComponent(this.giveDetails.unit);
|
||||||
|
}
|
||||||
|
if (this.giveDetails.description) {
|
||||||
|
this.urlForNewGive +=
|
||||||
|
"&description=" + encodeURIComponent(this.giveDetails.description);
|
||||||
|
}
|
||||||
|
this.giverName = this.didInfo(this.giveDetails.agentDid);
|
||||||
|
if (this.giveDetails.agentDid) {
|
||||||
|
this.urlForNewGive +=
|
||||||
|
"&giverDid=" +
|
||||||
|
encodeURIComponent(this.giveDetails.agentDid) +
|
||||||
|
"&giverName=" +
|
||||||
|
encodeURIComponent(this.giverName);
|
||||||
|
}
|
||||||
|
this.recipientName = this.didInfo(this.giveDetails.recipientDid);
|
||||||
|
if (this.giveDetails.recipientDid) {
|
||||||
|
this.urlForNewGive +=
|
||||||
|
"&recipientDid=" +
|
||||||
|
encodeURIComponent(this.giveDetails.recipientDid) +
|
||||||
|
"&recipientName=" +
|
||||||
|
encodeURIComponent(this.recipientName);
|
||||||
|
}
|
||||||
|
if (this.giveDetails.fullClaim.image) {
|
||||||
|
this.urlForNewGive +=
|
||||||
|
"&image=" + encodeURIComponent(this.giveDetails.fullClaim.image);
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
this.giveDetails.type == "Offer" &&
|
||||||
|
this.giveDetails.fulfillsHandleId
|
||||||
|
) {
|
||||||
|
this.urlForNewGive +=
|
||||||
|
"&offerId=" + encodeURIComponent(this.giveDetails.fulfillsHandleId);
|
||||||
|
}
|
||||||
|
if (this.giveDetails.fulfillsPlanHandleId) {
|
||||||
|
this.urlForNewGive +=
|
||||||
|
"&projectId=" +
|
||||||
|
encodeURIComponent(this.giveDetails.fulfillsPlanHandleId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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.giveDetails.agentDid,
|
||||||
|
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,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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.",
|
||||||
|
},
|
||||||
|
3000,
|
||||||
|
);
|
||||||
|
} 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.giveDetails.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.giveDetails.agentDid == 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.giveDetails.fullClaim)) {
|
||||||
|
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>
|
||||||
@@ -47,7 +47,7 @@
|
|||||||
class="text-md 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-1 py-1 rounded-md"
|
class="text-md 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-1 py-1 rounded-md"
|
||||||
@click="toggleShowContactAmounts()"
|
@click="toggleShowContactAmounts()"
|
||||||
>
|
>
|
||||||
{{ showGiveNumbers ? "Hide Given Numbers" : "Show Given Numbers" }}
|
{{ showGiveNumbers ? "Hide Given Hours" : "Show Given Hours" }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex justify-between mt-1" v-if="showGiveNumbers">
|
<div class="flex justify-between mt-1" v-if="showGiveNumbers">
|
||||||
@@ -90,20 +90,27 @@
|
|||||||
<EntityIcon
|
<EntityIcon
|
||||||
:contact="contact"
|
:contact="contact"
|
||||||
:iconSize="24"
|
:iconSize="24"
|
||||||
class="inline-block align-text-bottom border border-slate-300 rounded"
|
class="inline-block align-text-bottom border border-slate-300 rounded cursor-pointer"
|
||||||
@click="showLargeIdenticon = contact"
|
@click="showLargeIdenticon = contact"
|
||||||
/>
|
/>
|
||||||
{{ contact.name || AppString.NO_CONTACT_NAME }}
|
{{ contact.name || AppString.NO_CONTACT_NAME }}
|
||||||
<button
|
<button
|
||||||
class="text-sm uppercase 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-1 rounded-md"
|
|
||||||
@click="
|
@click="
|
||||||
contactEdit = contact;
|
contactEdit = contact;
|
||||||
contactNewName = contact.name || '';
|
contactNewName = contact.name || '';
|
||||||
"
|
"
|
||||||
title="Edit"
|
title="Edit"
|
||||||
>
|
>
|
||||||
<fa icon="pen" class="fa-fw" />
|
<fa icon="pen" class="text-sm text-blue-500 ml-2 mb-1"></fa>
|
||||||
</button>
|
</button>
|
||||||
|
<router-link
|
||||||
|
:to="{
|
||||||
|
path: '/did/' + encodeURIComponent(contact.did),
|
||||||
|
}"
|
||||||
|
title="See more about this DID"
|
||||||
|
>
|
||||||
|
<fa icon="circle-info" class="text-blue-500 ml-6" />
|
||||||
|
</router-link>
|
||||||
</h2>
|
</h2>
|
||||||
<div class="text-sm truncate">
|
<div class="text-sm truncate">
|
||||||
{{ contact.did }}
|
{{ contact.did }}
|
||||||
@@ -118,14 +125,6 @@
|
|||||||
>
|
>
|
||||||
<fa icon="copy" class="text-slate-400 fa-fw"></fa>
|
<fa icon="copy" class="text-slate-400 fa-fw"></fa>
|
||||||
</button>
|
</button>
|
||||||
<router-link
|
|
||||||
:to="{
|
|
||||||
path: '/did/' + encodeURIComponent(contact.did),
|
|
||||||
}"
|
|
||||||
title="See more about this DID"
|
|
||||||
>
|
|
||||||
<fa icon="circle-info" class="fa-fw ml-2 text-blue-500 rounded" />
|
|
||||||
</router-link>
|
|
||||||
<span v-show="showDidCopy">Copied DID</span>
|
<span v-show="showDidCopy">Copied DID</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-sm truncate" v-if="contact.publicKeyBase64">
|
<div class="text-sm truncate" v-if="contact.publicKeyBase64">
|
||||||
@@ -680,7 +679,7 @@ export default class ContactsView extends Vue {
|
|||||||
nextPubKeyHashB64: payload.own.nextPublicEncKeyHash,
|
nextPubKeyHashB64: payload.own.nextPublicEncKeyHash,
|
||||||
profileImageUrl: payload.own.profileImageUrl,
|
profileImageUrl: payload.own.profileImageUrl,
|
||||||
publicKeyBase64: payload.own.publicEncKey,
|
publicKeyBase64: payload.own.publicEncKey,
|
||||||
isRegistered: payload.own.isRegistered,
|
registered: payload.own.registered,
|
||||||
} as Contact);
|
} as Contact);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,7 +74,7 @@
|
|||||||
<div v-if="isLocalActive">
|
<div v-if="isLocalActive">
|
||||||
<div>
|
<div>
|
||||||
<button
|
<button
|
||||||
class="ml-2 px-4 py-2 rounded-md bg-blue-200 text-blue-500"
|
class="ml-2 mt-2 px-4 py-2 rounded-md bg-blue-200 text-blue-500"
|
||||||
@click="$router.push({ name: 'search-area' })"
|
@click="$router.push({ name: 'search-area' })"
|
||||||
>
|
>
|
||||||
Select a {{ searchBox ? "Different" : "" }} Location for Nearby Search
|
Select a {{ searchBox ? "Different" : "" }} Location for Nearby Search
|
||||||
@@ -100,7 +100,7 @@
|
|||||||
>
|
>
|
||||||
<a
|
<a
|
||||||
@click="onClickLoadProject(project.handleId)"
|
@click="onClickLoadProject(project.handleId)"
|
||||||
class="block py-4 flex gap-4"
|
class="block py-4 flex gap-4 cursor-pointer"
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<ProjectIcon
|
<ProjectIcon
|
||||||
|
|||||||
@@ -76,22 +76,49 @@
|
|||||||
</div>
|
</div>
|
||||||
<ImageMethodDialog ref="imageDialog" />
|
<ImageMethodDialog ref="imageDialog" />
|
||||||
|
|
||||||
<div v-if="projectId" class="mt-4">
|
<div class="h-7 mt-4 flex">
|
||||||
<fa
|
<input
|
||||||
icon="check"
|
v-if="projectId && !givenToUser"
|
||||||
class="bg-slate-500 text-white h-5 w-5 px-0.5 py-0.5 mr-2 rounded"
|
type="checkbox"
|
||||||
|
class="h-6 w-6 mr-2"
|
||||||
|
v-model="givenToProject"
|
||||||
/>
|
/>
|
||||||
<label class="text-sm">This is given to {{ projectName }}</label>
|
<fa
|
||||||
|
v-else
|
||||||
|
icon="square"
|
||||||
|
class="bg-slate-500 text-slate-500 h-5 w-5 px-0.5 py-0.5 mr-2 rounded"
|
||||||
|
@click="notifyUserOfProject()"
|
||||||
|
/>
|
||||||
|
<label class="text-sm mt-1">
|
||||||
|
{{
|
||||||
|
projectId
|
||||||
|
? "This was given to " + projectName
|
||||||
|
: "No project was chosen"
|
||||||
|
}}
|
||||||
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="showGivenToUser" class="mt-4">
|
<div class="h-7 mt-4 flex">
|
||||||
<input type="checkbox" class="h-6 w-6 mr-2" v-model="givenToUser" />
|
<input
|
||||||
<label class="text-sm">Given to you</label>
|
v-if="!givenToProject"
|
||||||
|
type="checkbox"
|
||||||
|
class="h-6 w-6 mr-2"
|
||||||
|
v-model="givenToUser"
|
||||||
|
/>
|
||||||
|
<fa
|
||||||
|
v-else
|
||||||
|
icon="square"
|
||||||
|
class="bg-slate-500 text-slate-500 h-5 w-5 px-0.5 py-0.5 mr-2 rounded"
|
||||||
|
@click="
|
||||||
|
notifyUser('You cannot assign this both a project and also to you.')
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
<label class="text-sm mt-1">This was given to you</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mt-4">
|
<div class="mt-4 flex">
|
||||||
<input type="checkbox" class="h-6 w-6 mr-2" v-model="isTrade" />
|
<input type="checkbox" class="h-6 w-6 mr-2" v-model="isTrade" />
|
||||||
<label class="text-sm">Trade (not a gift)</label>
|
<label class="text-sm mt-1">This was a trade (not a gift)</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p class="text-center mb-2 mt-6 italic">
|
<p class="text-center mb-2 mt-6 italic">
|
||||||
@@ -148,6 +175,7 @@ export default class GiftedDetails extends Vue {
|
|||||||
amountInput = "0";
|
amountInput = "0";
|
||||||
description = "";
|
description = "";
|
||||||
destinationNameAfter = "";
|
destinationNameAfter = "";
|
||||||
|
givenToProject = false;
|
||||||
givenToUser = false;
|
givenToUser = false;
|
||||||
giverDid: string | undefined;
|
giverDid: string | undefined;
|
||||||
giverName = "";
|
giverName = "";
|
||||||
@@ -215,7 +243,8 @@ export default class GiftedDetails extends Vue {
|
|||||||
this.recipientName =
|
this.recipientName =
|
||||||
this.recipientDid === this.activeDid ? "you" : "someone not named";
|
this.recipientDid === this.activeDid ? "you" : "someone not named";
|
||||||
}
|
}
|
||||||
this.showGivenToUser =
|
this.givenToProject = !!this.projectId;
|
||||||
|
this.givenToUser =
|
||||||
!this.projectId && this.recipientDid === this.activeDid;
|
!this.projectId && this.recipientDid === this.activeDid;
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
@@ -233,7 +262,7 @@ export default class GiftedDetails extends Vue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this.projectId) {
|
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 identity = await libsUtil.getIdentity(this.activeDid);
|
||||||
const project = await getPlanFromCache(
|
const project = await getPlanFromCache(
|
||||||
this.projectId,
|
this.projectId,
|
||||||
@@ -413,6 +442,43 @@ export default class GiftedDetails extends Vue {
|
|||||||
await this.recordGive();
|
await this.recordGive();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
notifyUser(message: string) {
|
||||||
|
this.$notify(
|
||||||
|
{
|
||||||
|
group: "alert",
|
||||||
|
type: "warning",
|
||||||
|
title: "Error",
|
||||||
|
text: message,
|
||||||
|
},
|
||||||
|
3000,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
notifyUserOfProject() {
|
||||||
|
if (!this.projectId) {
|
||||||
|
this.$notify(
|
||||||
|
{
|
||||||
|
group: "alert",
|
||||||
|
type: "warning",
|
||||||
|
title: "Error",
|
||||||
|
text: "To assign to a project, you must open this dialog through a project.",
|
||||||
|
},
|
||||||
|
3000,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// must be because givenToUser is true
|
||||||
|
this.$notify(
|
||||||
|
{
|
||||||
|
group: "alert",
|
||||||
|
type: "warning",
|
||||||
|
title: "Error",
|
||||||
|
text: "You cannot assign both to a project and to yourself.",
|
||||||
|
},
|
||||||
|
3000,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param giverDid may be null
|
* @param giverDid may be null
|
||||||
@@ -429,6 +495,7 @@ export default class GiftedDetails extends Vue {
|
|||||||
? this.activeDid
|
? this.activeDid
|
||||||
: undefined
|
: undefined
|
||||||
: this.recipientDid;
|
: this.recipientDid;
|
||||||
|
const projectId = this.givenToProject ? this.projectId : undefined;
|
||||||
const result = await createAndSubmitGive(
|
const result = await createAndSubmitGive(
|
||||||
this.axios,
|
this.axios,
|
||||||
this.apiServer,
|
this.apiServer,
|
||||||
@@ -438,7 +505,7 @@ export default class GiftedDetails extends Vue {
|
|||||||
this.description,
|
this.description,
|
||||||
parseFloat(this.amountInput),
|
parseFloat(this.amountInput),
|
||||||
this.unitCode,
|
this.unitCode,
|
||||||
this.projectId,
|
projectId,
|
||||||
this.offerId,
|
this.offerId,
|
||||||
this.isTrade,
|
this.isTrade,
|
||||||
this.imageUrl,
|
this.imageUrl,
|
||||||
|
|||||||
@@ -72,7 +72,7 @@
|
|||||||
<div class="mb-8">
|
<div class="mb-8">
|
||||||
<div v-if="isCreatingIdentifier">
|
<div v-if="isCreatingIdentifier">
|
||||||
<p class="text-slate-500 text-center italic mt-4 mb-4">
|
<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>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
@@ -132,7 +132,7 @@
|
|||||||
<EntityIcon
|
<EntityIcon
|
||||||
:contact="contact"
|
:contact="contact"
|
||||||
:iconSize="64"
|
: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
|
<h3
|
||||||
class="text-xs font-medium text-ellipsis whitespace-nowrap overflow-hidden"
|
class="text-xs font-medium text-ellipsis whitespace-nowrap overflow-hidden"
|
||||||
@@ -145,7 +145,7 @@
|
|||||||
<div class="flex justify-between">
|
<div class="flex justify-between">
|
||||||
<router-link
|
<router-link
|
||||||
v-if="allContacts.length >= 7"
|
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"
|
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
|
Choose From All Contacts
|
||||||
@@ -251,7 +251,7 @@
|
|||||||
<fa
|
<fa
|
||||||
icon="file-lines"
|
icon="file-lines"
|
||||||
class="pl-2 text-blue-500 cursor-pointer"
|
class="pl-2 text-blue-500 cursor-pointer"
|
||||||
></fa>
|
/>
|
||||||
</a>
|
</a>
|
||||||
</span>
|
</span>
|
||||||
<span class="col-span-1 justify-self-end">
|
<span class="col-span-1 justify-self-end">
|
||||||
@@ -262,7 +262,7 @@
|
|||||||
encodeURIComponent(record.fulfillsPlanHandleId)
|
encodeURIComponent(record.fulfillsPlanHandleId)
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<fa icon="hammer" class="text-blue-500"></fa>
|
<fa icon="hammer" class="text-blue-500" />
|
||||||
</router-link>
|
</router-link>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -276,7 +276,7 @@
|
|||||||
</InfiniteScroll>
|
</InfiniteScroll>
|
||||||
<div v-if="isFeedLoading">
|
<div v-if="isFeedLoading">
|
||||||
<p class="text-slate-500 text-center italic mt-4 mb-4">
|
<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>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="!isFeedLoading && feedData.length === 0">
|
<div v-if="!isFeedLoading && feedData.length === 0">
|
||||||
|
|||||||
@@ -112,10 +112,15 @@ export default class IdentitySwitcherView extends Vue {
|
|||||||
await accountsDB.open();
|
await accountsDB.open();
|
||||||
const accounts = await accountsDB.accounts.toArray();
|
const accounts = await accountsDB.accounts.toArray();
|
||||||
for (let n = 0; n < accounts.length; n++) {
|
for (let n = 0; n < accounts.length; n++) {
|
||||||
const did = accounts[n]["did"];
|
try {
|
||||||
this.otherIdentities.push({ did: did });
|
const did = accounts[n]["did"];
|
||||||
if (did && this.activeDid === did) {
|
this.otherIdentities.push({ did: did });
|
||||||
this.activeDidInIdentities = true;
|
if (did && this.activeDid === did) {
|
||||||
|
this.activeDidInIdentities = true;
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Error parsing identity:", err);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|||||||
@@ -161,7 +161,7 @@
|
|||||||
<EntityIcon
|
<EntityIcon
|
||||||
:contact="contact"
|
:contact="contact"
|
||||||
:iconSize="64"
|
: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
|
<h3
|
||||||
class="text-xs font-medium text-ellipsis whitespace-nowrap overflow-hidden"
|
class="text-xs font-medium text-ellipsis whitespace-nowrap overflow-hidden"
|
||||||
@@ -795,7 +795,7 @@ export default class ProjectViewView extends Vue {
|
|||||||
onClickAllContactsGifting() {
|
onClickAllContactsGifting() {
|
||||||
localStorage.setItem("projectId", this.projectId);
|
localStorage.setItem("projectId", this.projectId);
|
||||||
const route = {
|
const route = {
|
||||||
name: "contact-gives",
|
name: "contact-gift",
|
||||||
};
|
};
|
||||||
this.$router.push(route);
|
this.$router.push(route);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,7 +63,7 @@
|
|||||||
<!-- New Project -->
|
<!-- New Project -->
|
||||||
<button
|
<button
|
||||||
v-if="isRegistered && showProjects"
|
v-if="isRegistered && showProjects"
|
||||||
class="fixed right-6 bottom-24 text-center text-4xl leading-none bg-blue-600 text-white w-14 py-2.5 rounded-full"
|
class="fixed right-6 top-24 text-center text-4xl leading-none bg-blue-600 text-white w-14 py-2.5 rounded-full"
|
||||||
@click="onClickNewProject()"
|
@click="onClickNewProject()"
|
||||||
>
|
>
|
||||||
<fa icon="plus" class="fa-fw"></fa>
|
<fa icon="plus" class="fa-fw"></fa>
|
||||||
@@ -79,6 +79,13 @@
|
|||||||
|
|
||||||
<!-- Offer Results List -->
|
<!-- Offer Results List -->
|
||||||
<InfiniteScroll v-if="showOffers" @reached-bottom="loadMoreOfferData">
|
<InfiniteScroll v-if="showOffers" @reached-bottom="loadMoreOfferData">
|
||||||
|
<div v-if="offers.length === 0" class="text-center py-4">
|
||||||
|
You have not offered anything.
|
||||||
|
<br />
|
||||||
|
<router-link to="/discover" class="text-blue-600">
|
||||||
|
Look for projects worth some of your time.
|
||||||
|
</router-link>
|
||||||
|
</div>
|
||||||
<ul class="border-t border-slate-300">
|
<ul class="border-t border-slate-300">
|
||||||
<li
|
<li
|
||||||
class="border-b border-slate-300"
|
class="border-b border-slate-300"
|
||||||
@@ -177,8 +184,16 @@
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</InfiniteScroll>
|
</InfiniteScroll>
|
||||||
|
|
||||||
<!-- Project Results List -->
|
<!-- Project Results List -->
|
||||||
<InfiniteScroll v-if="showProjects" @reached-bottom="loadMoreProjectData">
|
<InfiniteScroll v-if="showProjects" @reached-bottom="loadMoreProjectData">
|
||||||
|
<div v-if="projects.length === 0" class="text-center py-4">
|
||||||
|
You have not announced any projects.
|
||||||
|
<br />
|
||||||
|
Hit the big
|
||||||
|
<fa icon="plus" class="bg-blue-600 text-white px-1 py-1 rounded-full" />
|
||||||
|
button. You'll never know until you try.
|
||||||
|
</div>
|
||||||
<ul class="border-t border-slate-300">
|
<ul class="border-t border-slate-300">
|
||||||
<li
|
<li
|
||||||
class="border-b border-slate-300"
|
class="border-b border-slate-300"
|
||||||
|
|||||||
Reference in New Issue
Block a user