Browse Source

show more succinct info in feed, targeted toward user's visibility

pull/103/head
Trent Larson 7 months ago
parent
commit
3eda5f6b5d
  1. 63
      src/libs/endorserServer.ts
  2. 12
      src/router/index.ts
  3. 2
      src/views/AccountViewView.vue
  4. 4
      src/views/ContactsView.vue
  5. 171
      src/views/HomeView.vue
  6. 2
      src/views/SeedBackupView.vue

63
src/libs/endorserServer.ts

@ -352,32 +352,65 @@ export function removeVisibleToDids(input: any): any {
} }
} }
/** export function contactForDid(
always returns text, maybe UNNAMED_VISIBLE or UNKNOWN_ENTITY
Similar logic is found in endorser-mobile.
**/
export function didInfo(
did: string | undefined, did: string | undefined,
activeDid: string | undefined,
allMyDids: string[],
contacts: Contact[], contacts: Contact[],
): string { ): Contact | undefined {
if (!did) return "Someone Anonymous"; return isEmptyOrHiddenDid(did)
? undefined
: R.find((c) => c.did === did, contacts);
}
const contact = R.find((c) => c.did === did, contacts); /**
*
* Similar logic is found in endorser-mobile.
*
* @param did
* @param activeDid
* @param contact
* @param allMyDids
* @return { known: boolean, displayName: string } where known is true if the display name is some easily-recogizable name, false if it's a generic name like "Someone Anonymous"
*/
export function didInfoForContact(
did: string | undefined,
activeDid: string | undefined,
contact?: Contact,
allMyDids: string[] = [],
// eslint-disable-next-line @typescript-eslint/no-explicit-any
): { known: boolean; displayName: string } {
if (!did) return { displayName: "Someone Anonymous", known: false };
if (contact) { if (contact) {
return contact.name || "Contact With No Name"; return {
displayName: contact.name || "Contact With No Name",
known: !!contact.name,
};
} else if (did === activeDid) {
return { displayName: "You", known: true };
} else { } else {
const myId = R.find(R.equals(did), allMyDids); const myId = R.find(R.equals(did), allMyDids);
return myId return myId
? `You${myId !== activeDid ? " (Alt ID)" : ""}` ? { displayName: "You (Alt ID)", known: true }
: isHiddenDid(did) : isHiddenDid(did)
? "Someone Outside Your Network" ? { displayName: "Someone Outside Your Network", known: false }
: "Someone Outside Contacts"; : { displayName: "Someone Outside Contacts", known: false };
} }
} }
/**
always returns text, maybe something like "unnamed" or "unknown"
Now that we're using more informational didInfoForContact under the covers, we might want to consolidate.
**/
export function didInfo(
did: string | undefined,
activeDid: string | undefined,
allMyDids: string[],
contacts: Contact[],
): string {
const contact = contactForDid(did, contacts);
return didInfoForContact(did, activeDid, contact, allMyDids).displayName;
}
/** /**
* For result, see https://api.endorser.ch/api-docs/#/claims/post_api_v2_claim * For result, see https://api.endorser.ch/api-docs/#/claims/post_api_v2_claim
* *

12
src/router/index.ts

@ -28,12 +28,6 @@ const enterOrStart = async (
}; };
const routes: Array<RouteRecordRaw> = [ const routes: Array<RouteRecordRaw> = [
{
path: "/",
name: "home",
component: () =>
import(/* webpackChunkName: "home" */ "../views/HomeView.vue"),
},
{ {
path: "/account", path: "/account",
name: "account", name: "account",
@ -96,6 +90,12 @@ const routes: Array<RouteRecordRaw> = [
component: () => component: () =>
import(/* webpackChunkName: "help" */ "../views/HelpView.vue"), import(/* webpackChunkName: "help" */ "../views/HelpView.vue"),
}, },
{
path: "/",
name: "home",
component: () =>
import(/* webpackChunkName: "home" */ "../views/HomeView.vue"),
},
{ {
path: "/help-notifications", path: "/help-notifications",
name: "help-notifications", name: "help-notifications",

2
src/views/AccountViewView.vue

@ -1,5 +1,5 @@
<template> <template>
<QuickNav selected="Profile"></QuickNav> <QuickNav selected="Profile" />
<TopMessage /> <TopMessage />
<!-- CONTENT --> <!-- CONTENT -->

4
src/views/ContactsView.vue

@ -868,7 +868,7 @@ export default class ContactsView extends Vue {
(contact.name || "That unnamed person") + (contact.name || "That unnamed person") +
" has been registered.", " has been registered.",
}, },
-1, 5000,
); );
} }
} catch (error) { } catch (error) {
@ -1190,7 +1190,7 @@ export default class ContactsView extends Vue {
title: "Done", title: "Done",
text: "Successfully logged time to the server.", text: "Successfully logged time to the server.",
}, },
-1, 5000,
); );
if (fromDid === identity.did) { if (fromDid === identity.did) {

171
src/views/HomeView.vue

@ -1,5 +1,5 @@
<template> <template>
<QuickNav selected="Home"></QuickNav> <QuickNav selected="Home" />
<TopMessage /> <TopMessage />
<!-- CONTENT --> <!-- CONTENT -->
@ -30,7 +30,7 @@
and go click on that new app. and go click on that new app.
</span> </span>
<span <span
v-else-if="userAgentInfo.getBrowser().name.startsWith('Chrome')" v-else-if="userAgentInfo.getBrowser()?.name?.startsWith('Chrome')"
> >
You should see a prompt to install, or you can click on the You should see a prompt to install, or you can click on the
top-right dots top-right dots
@ -105,14 +105,8 @@
<div v-else> <div v-else>
<!-- activeDid && isRegistered --> <!-- activeDid && isRegistered -->
<div class="flex justify-between mb-4"> <div class="mb-4">
<h2 class="text-xl font-bold">Record Something Given</h2> <h2 class="text-xl font-bold">Record Something Given By:</h2>
<button
@click="openGiftedPrompts()"
class="block text-center text-md font-bold bg-blue-500 text-white px-2 py-3 rounded-md"
>
Ideas...
</button>
</div> </div>
<ul class="grid grid-cols-4 gap-x-3 gap-y-5 text-center mb-5"> <ul class="grid grid-cols-4 gap-x-3 gap-y-5 text-center mb-5">
@ -145,21 +139,20 @@
</li> </li>
</ul> </ul>
<!-- Ideally, this button should only be visible when the active account has more than 7 or 11 contacts in their list (we want to limit the grid count above to 8 or 12 accounts to keep it compact) --> <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-gives' }"
class="block text-center text-md font-bold uppercase bg-slate-500 text-white px-2 py-3 rounded-md" class="block text-center text-md font-bold uppercase bg-slate-500 text-white px-2 py-3 rounded-md"
> >
Show More Contacts&hellip; Choose From All Contacts
</router-link> </router-link>
<button
<!-- If there are no contacts, show this instead: --> @click="openGiftedPrompts()"
<div class="block text-center text-md font-bold bg-slate-500 text-white px-2 py-3 rounded-md"
class="rounded border border-dashed border-slate-300 bg-slate-100 px-4 py-3 text-center italic text-slate-500" >
v-if="allContacts.length === 0" Ideas...
> </button>
(No contacts to show.)
</div> </div>
</div> </div>
</div> </div>
@ -185,16 +178,24 @@
class="border-b border-dashed border-slate-400 text-orange-400 pb-2 mb-2 font-bold uppercase text-sm" class="border-b border-dashed border-slate-400 text-orange-400 pb-2 mb-2 font-bold uppercase text-sm"
v-if="record.jwtId == feedLastViewedClaimId" v-if="record.jwtId == feedLastViewedClaimId"
> >
You've seen all the following before You've already seen all the following
</div> </div>
<div class="grid grid-cols-12"> <div class="grid grid-cols-12">
<span class="col-span-11 justify-self-start"> <span class="col-span-11 justify-self-start">
<fa <span>
icon="gift" <fa
class="col-span-1 pt-1 pr-2 text-slate-500" v-if="record.giver.known || record.receiver.known"
></fa> icon="circle-user"
{{ this.giveDescription(record) }} class="col-span-1 pt-1 pl-0 pr-3 text-slate-500"
/>
<fa
v-else
icon="gift"
class="col-span-1 pt-1 pl-3 pr-0 text-slate-500"
/>
</span>
{{ giveDescription(record) }}
<a @click="onClickLoadClaim(record.jwtId)"> <a @click="onClickLoadClaim(record.jwtId)">
<fa <fa
icon="circle-info" icon="circle-info"
@ -243,7 +244,8 @@ import { Contact } from "@/db/tables/contacts";
import { MASTER_SETTINGS_KEY, Settings } from "@/db/tables/settings"; import { MASTER_SETTINGS_KEY, Settings } from "@/db/tables/settings";
import { accessToken } from "@/libs/crypto"; import { accessToken } from "@/libs/crypto";
import { import {
didInfo, contactForDid,
didInfoForContact,
GiverInputInfo, GiverInputInfo,
GiveServerRecord, GiveServerRecord,
} from "@/libs/endorserServer"; } from "@/libs/endorserServer";
@ -257,6 +259,17 @@ interface Notification {
text: string; text: string;
} }
interface GiveRecordWithContactInfo extends GiveServerRecord {
giver: {
displayName: string;
known: boolean;
};
receiver: {
displayName: string;
known: boolean;
};
}
@Component({ @Component({
components: { components: {
GiftedDialog, GiftedDialog,
@ -274,7 +287,7 @@ export default class HomeView extends Vue {
allContacts: Array<Contact> = []; allContacts: Array<Contact> = [];
allMyDids: Array<string> = []; allMyDids: Array<string> = [];
apiServer = ""; apiServer = "";
feedData: GiveServerRecord[] = []; feedData: GiveRecordWithContactInfo[] = [];
feedPreviousOldestId?: string; feedPreviousOldestId?: string;
feedLastViewedClaimId?: string; feedLastViewedClaimId?: string;
isCreatingIdentifier = false; isCreatingIdentifier = false;
@ -388,7 +401,37 @@ export default class HomeView extends Vue {
await this.retrieveGives(this.apiServer, this.feedPreviousOldestId) await this.retrieveGives(this.apiServer, this.feedPreviousOldestId)
.then(async (results) => { .then(async (results) => {
if (results.data.length > 0) { if (results.data.length > 0) {
this.feedData = this.feedData.concat(results.data); // include the descriptions of the giver and receiver
const newFeedData: GiveRecordWithContactInfo = results.data.map(
(record: GiveServerRecord) => {
// similar code is in endorser-mobile utility.ts
// claim.claim happen for some claims wrapped in a Verifiable Credential
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const claim = (record.fullClaim as any).claim || record.fullClaim;
// agent.did is for legacy data, before March 2023
const giverDid =
claim.agent?.identifier || (claim.agent as any)?.did; // eslint-disable-line @typescript-eslint/no-explicit-any
// recipient.did is for legacy data, before March 2023
const recipientDid =
claim.recipient?.identifier || (claim.recipient as any)?.did; // eslint-disable-line @typescript-eslint/no-explicit-any
return {
...record,
giver: didInfoForContact(
giverDid,
this.activeDid,
contactForDid(giverDid, this.allContacts),
this.allMyDids,
),
receiver: didInfoForContact(
recipientDid,
this.activeDid,
contactForDid(recipientDid, this.allContacts),
this.allMyDids,
),
};
},
);
this.feedData = this.feedData.concat(newFeedData);
this.feedPreviousOldestId = this.feedPreviousOldestId =
results.data[results.data.length - 1].jwtId; results.data[results.data.length - 1].jwtId;
// The following update is only done on the first load. // The following update is only done on the first load.
@ -449,46 +492,52 @@ export default class HomeView extends Vue {
} }
} }
giveDescription(giveRecord: GiveServerRecord) { giveDescription(giveRecord: GiveRecordWithContactInfo) {
// similar code is in endorser-mobile utility.ts // similar code is in endorser-mobile utility.ts
// claim.claim happen for some claims wrapped in a Verifiable Credential // claim.claim happen for some claims wrapped in a Verifiable Credential
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
const claim = (giveRecord.fullClaim as any).claim || giveRecord.fullClaim; const claim = (giveRecord.fullClaim as any).claim || giveRecord.fullClaim;
// agent.did is for legacy data, before March 2023
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const giverDid = claim.agent?.identifier || (claim.agent as any)?.did;
const giverInfo = didInfo(
giverDid,
this.activeDid,
this.allMyDids,
this.allContacts,
);
let gaveAmount = claim.object?.amountOfThisGood let gaveAmount = claim.object?.amountOfThisGood
? this.displayAmount(claim.object.unitCode, claim.object.amountOfThisGood) ? this.displayAmount(claim.object.unitCode, claim.object.amountOfThisGood)
: ""; : "";
if (claim.description) { if (claim.description) {
if (gaveAmount) { if (gaveAmount) {
gaveAmount = gaveAmount + ", and also: "; gaveAmount = " (and " + gaveAmount + ")";
} }
gaveAmount = gaveAmount + claim.description; gaveAmount = claim.description + gaveAmount;
} }
if (!gaveAmount) { if (!gaveAmount) {
gaveAmount = "something not described"; gaveAmount = "something not described";
} }
// recipient.did is for legacy data, before March 2023
const gaveRecipientId = /**
// eslint-disable-next-line @typescript-eslint/no-explicit-any * Only show giver and/or receiver info first if they're named.
claim.recipient?.identifier || (claim.recipient as any)?.did; * - If only giver is named, show "... gave"
const gaveRecipientInfo = gaveRecipientId * - If only receiver is named, show "... received"
? " to " + */
didInfo(
gaveRecipientId, const giverInfo = giveRecord.giver;
this.activeDid, const recipientInfo = giveRecord.receiver;
this.allMyDids, if (giverInfo.known && recipientInfo.known) {
this.allContacts, // both giver and recipient are named
) return `${giverInfo.displayName} gave to ${recipientInfo.displayName}: ${gaveAmount}`;
: ""; } else if (giverInfo.known) {
return giverInfo + " gave" + gaveRecipientInfo + ": " + gaveAmount; // giver is named but recipient is not
return `${giverInfo.displayName} gave: ${gaveAmount} (to ${recipientInfo.displayName})`;
} else if (recipientInfo.known) {
// recipient is named but giver is not
return `${recipientInfo.displayName} received: ${gaveAmount} (from ${giverInfo.displayName})`;
} else {
// neither giver nor recipient are named
let peopleInfo;
if (giverInfo.displayName === recipientInfo.displayName) {
peopleInfo = `between two who are ${giverInfo.displayName}`;
} else {
peopleInfo = `from ${giverInfo.displayName} to ${recipientInfo.displayName}`;
}
return gaveAmount + " (" + peopleInfo + ")";
}
} }
onClickLoadClaim(jwtId: string) { onClickLoadClaim(jwtId: string) {
@ -506,7 +555,7 @@ export default class HomeView extends Vue {
return unitCode === "HUR" ? (single ? "hour" : "hours") : unitCode; return unitCode === "HUR" ? (single ? "hour" : "hours") : unitCode;
} }
openDialog(giver: GiverInputInfo) { openDialog(giver?: GiverInputInfo) {
(this.$refs.customDialog as GiftedDialog).open(giver); (this.$refs.customDialog as GiftedDialog).open(giver);
} }

2
src/views/SeedBackupView.vue

@ -1,5 +1,5 @@
<template> <template>
<QuickNav selected="Profile"></QuickNav> <QuickNav selected="Profile" />
<!-- CONTENT --> <!-- CONTENT -->
<section id="Content" class="p-6 pb-24 max-w-3xl mx-auto"> <section id="Content" class="p-6 pb-24 max-w-3xl mx-auto">
<!-- Back --> <!-- Back -->

Loading…
Cancel
Save