Trent Larson
1 year ago
9 changed files with 285 additions and 23 deletions
@ -1,15 +1,231 @@ |
|||||
<template> |
<template> |
||||
<section></section> |
<!-- QUICK NAV --> |
||||
|
<nav id="QuickNav" class="fixed bottom-0 left-0 right-0 bg-slate-200 z-50"> |
||||
|
<ul class="flex text-2xl p-2 gap-2"> |
||||
|
<!-- Home Feed --> |
||||
|
<li class="basis-1/5 rounded-md bg-slate-400 text-white"> |
||||
|
<router-link :to="{ name: 'home' }" class="block text-center py-3 px-1" |
||||
|
><fa icon="house-chimney" class="fa-fw"></fa |
||||
|
></router-link> |
||||
|
</li> |
||||
|
<!-- Search --> |
||||
|
<li class="basis-1/5 rounded-md text-slate-500"> |
||||
|
<router-link |
||||
|
:to="{ name: 'discover' }" |
||||
|
class="block text-center py-3 px-1" |
||||
|
><fa icon="magnifying-glass" class="fa-fw"></fa |
||||
|
></router-link> |
||||
|
</li> |
||||
|
<!-- Projects --> |
||||
|
<li class="basis-1/5 rounded-md text-slate-500"> |
||||
|
<router-link |
||||
|
:to="{ name: 'projects' }" |
||||
|
class="block text-center py-3 px-1" |
||||
|
><fa icon="folder-open" class="fa-fw"></fa |
||||
|
></router-link> |
||||
|
</li> |
||||
|
<!-- Contacts --> |
||||
|
<li class="basis-1/5 rounded-md text-slate-500"> |
||||
|
<router-link |
||||
|
:to="{ name: 'contacts' }" |
||||
|
class="block text-center py-3 px-1" |
||||
|
><fa icon="users" class="fa-fw"></fa |
||||
|
></router-link> |
||||
|
</li> |
||||
|
<!-- Profile --> |
||||
|
<li class="basis-1/5 rounded-md text-slate-500"> |
||||
|
<router-link |
||||
|
:to="{ name: 'account' }" |
||||
|
class="block text-center py-3 px-1" |
||||
|
><fa icon="circle-user" class="fa-fw"></fa |
||||
|
></router-link> |
||||
|
</li> |
||||
|
</ul> |
||||
|
</nav> |
||||
|
|
||||
|
<!-- CONTENT --> |
||||
|
<section id="Content" class="p-6 pb-24"> |
||||
|
<h1 id="ViewHeading" class="text-4xl text-center font-light pt-4 mb-8"> |
||||
|
Feed |
||||
|
</h1> |
||||
|
<span :class="{ hidden: isHiddenSpinner }"> |
||||
|
<fa icon="spinner" class="fa-fw"></fa> |
||||
|
Loading… |
||||
|
</span> |
||||
|
<div> |
||||
|
<!-- Results List --> |
||||
|
<ul class=""> |
||||
|
<li |
||||
|
class="border-b border-slate-300" |
||||
|
v-for="record in feedData" |
||||
|
:key="record.id" |
||||
|
> |
||||
|
{{ this.giveDescription(record) }} |
||||
|
</li> |
||||
|
</ul> |
||||
|
</div> |
||||
|
</section> |
||||
|
|
||||
|
<!-- This same popup code is in many files. --> |
||||
|
<div v-bind:class="computedAlertClassNames()"> |
||||
|
<button |
||||
|
class="close-button bg-slate-200 w-8 leading-loose rounded-full absolute top-2 right-2" |
||||
|
@click="onClickClose()" |
||||
|
> |
||||
|
<fa icon="xmark"></fa> |
||||
|
</button> |
||||
|
<h4 class="font-bold pr-5">{{ alertTitle }}</h4> |
||||
|
<p>{{ alertMessage }}</p> |
||||
|
</div> |
||||
</template> |
</template> |
||||
|
|
||||
<script lang="ts"> |
<script lang="ts"> |
||||
import { Options, Vue } from "vue-class-component"; |
import { Options, Vue } from "vue-class-component"; |
||||
import HelloWorld from "@/components/HelloWorld.vue"; // @ is an alias to /src |
|
||||
|
import { db, accountsDB } from "@/db"; |
||||
|
import { MASTER_SETTINGS_KEY } from "@/db/tables/settings"; |
||||
|
import { didInfo } from "@/libs/endorserServer"; |
||||
|
import { Account } from "@/db/tables/accounts"; |
||||
|
import { Contact } from "@/db/tables/contacts"; |
||||
|
import * as R from "ramda"; |
||||
|
|
||||
@Options({ |
@Options({ |
||||
components: { |
components: {}, |
||||
HelloWorld, |
}) |
||||
|
export default class HomeView extends Vue { |
||||
|
accounts: Array<Account> = []; |
||||
|
apiServer = ""; |
||||
|
contacts: Array<Contact> = []; |
||||
|
feedAllLoaded = false; |
||||
|
feedData = []; |
||||
|
feedPreviousOldestId = null; |
||||
|
isHiddenSpinner = true; |
||||
|
|
||||
|
// 'created' hook runs when the Vue instance is first created |
||||
|
async created() { |
||||
|
await accountsDB.open(); |
||||
|
this.accounts = await accountsDB.accounts.toArray(); |
||||
|
console.log("Accounts:", this.accounts); |
||||
|
await db.open(); |
||||
|
this.contacts = await db.contacts.toArray(); |
||||
|
} |
||||
|
|
||||
|
// 'mounted' hook runs after initial render |
||||
|
async mounted() { |
||||
|
try { |
||||
|
await db.open(); |
||||
|
const settings = await db.settings.get(MASTER_SETTINGS_KEY); |
||||
|
this.apiServer = settings?.apiServer || ""; |
||||
|
this.updateAllFeed(); |
||||
|
} catch (err) { |
||||
|
console.log("Error in mounted():", err); |
||||
|
this.alertTitle = "Error"; |
||||
|
this.alertMessage = |
||||
|
err.userMessage || |
||||
|
"There was an error retrieving the latest sweet, sweet action."; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
updateAllFeed = async () => { |
||||
|
this.isHiddenSpinner = false; |
||||
|
|
||||
|
await this.retrieveClaims(this.apiServer, null, this.feedPreviousOldestId) |
||||
|
.then(async (results) => { |
||||
|
if (results.data.length > 0) { |
||||
|
this.feedData = this.feedData.concat(results.data); |
||||
|
console.log("Feed data:", this.feedData); |
||||
|
this.feedAllLoaded = results.hitLimit; |
||||
|
this.feedPreviousOldestId = results.data[results.data.length - 1].id; |
||||
|
} |
||||
|
}) |
||||
|
.catch((e) => { |
||||
|
console.log("Error with feed load:", e); |
||||
|
this.alertMessage = |
||||
|
e.userMessage || "There was an error retrieving feed data."; |
||||
|
}); |
||||
|
|
||||
|
this.isHiddenSpinner = true; |
||||
|
}; |
||||
|
|
||||
|
retrieveClaims = async (endorserApiServer, identifier, beforeId) => { |
||||
|
//const token = await accessToken(identifier) |
||||
|
//const afterQuery = afterId == null ? "" : "&afterId=" + afterId; |
||||
|
const beforeQuery = beforeId == null ? "" : "&beforeId=" + beforeId; |
||||
|
return fetch(this.apiServer + "/api/v2/report/gives?" + beforeQuery, { |
||||
|
method: "GET", |
||||
|
headers: { |
||||
|
"Content-Type": "application/json", |
||||
|
//"Uport-Push-Token": token, |
||||
}, |
}, |
||||
}) |
}) |
||||
export default class HomeView extends Vue {} |
.then(async (response) => { |
||||
|
if (response.status !== 200) { |
||||
|
const details = await response.text(); |
||||
|
throw details; |
||||
|
} |
||||
|
return response.json(); |
||||
|
}) |
||||
|
.then((results) => { |
||||
|
if (results.data) { |
||||
|
return results; |
||||
|
} else { |
||||
|
throw JSON.stringify(results); |
||||
|
} |
||||
|
}); |
||||
|
}; |
||||
|
|
||||
|
giveDescription(giveRecord) { |
||||
|
let claim = giveRecord.fullClaim; |
||||
|
if (claim.claim) { |
||||
|
// it's probably a Verified Credential |
||||
|
claim = claim.claim; |
||||
|
} |
||||
|
|
||||
|
// agent.did is for legacy data, before March 2023 |
||||
|
const giver = |
||||
|
claim.agent?.identifier || claim.agent?.did || giveRecord.issuer; |
||||
|
const giverInfo = giver; //didInfo(giver, identifiers, contacts); |
||||
|
const gaveAmount = claim.object?.amountOfThisGood |
||||
|
? this.displayAmount(claim.object.unitCode, claim.object.amountOfThisGood) |
||||
|
: claim.object; |
||||
|
// recipient.did is for legacy data, before March 2023 |
||||
|
const gaveRecipientId = claim.recipient?.identifier || claim.recipient?.did; |
||||
|
const gaveRecipientInfo = gaveRecipientId |
||||
|
? " to " + gaveRecipientId //didInfo(gaveRecipientId, identifiers, contacts) |
||||
|
: ""; |
||||
|
return giverInfo + " gave " + gaveAmount + gaveRecipientInfo; |
||||
|
} |
||||
|
|
||||
|
displayAmount(code, amt) { |
||||
|
return "" + amt + " " + this.currencyShortWordForCode(code, amt === 1); |
||||
|
} |
||||
|
|
||||
|
currencyShortWordForCode(unitCode, single) { |
||||
|
return unitCode === "HUR" ? (single ? "hour" : "hours") : unitCode; |
||||
|
} |
||||
|
|
||||
|
// This same popup code is in many files. |
||||
|
alertMessage = ""; |
||||
|
alertTitle = ""; |
||||
|
public onClickClose() { |
||||
|
this.alertTitle = ""; |
||||
|
this.alertMessage = ""; |
||||
|
} |
||||
|
public computedAlertClassNames() { |
||||
|
return { |
||||
|
hidden: !this.alertMessage, |
||||
|
"dismissable-alert": true, |
||||
|
"bg-slate-100": true, |
||||
|
"p-5": true, |
||||
|
rounded: true, |
||||
|
"drop-shadow-lg": true, |
||||
|
fixed: true, |
||||
|
"top-3": true, |
||||
|
"inset-x-3": true, |
||||
|
"transition-transform": true, |
||||
|
"ease-in": true, |
||||
|
"duration-300": true, |
||||
|
}; |
||||
|
} |
||||
|
} |
||||
</script> |
</script> |
||||
|
Loading…
Reference in new issue