9 changed files with 285 additions and 23 deletions
			
			
		| @ -1,15 +1,231 @@ | |||
| <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> | |||
| 
 | |||
| <script lang="ts"> | |||
| 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({ | |||
|   components: { | |||
|     HelloWorld, | |||
|   }, | |||
|   components: {}, | |||
| }) | |||
| export default class HomeView extends Vue {} | |||
| 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, | |||
|       }, | |||
|     }) | |||
|       .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> | |||
|  | |||
					Loading…
					
					
				
		Reference in new issue