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 {} | 
					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> | 
					</script> | 
				
			||||
 | 
				
			|||||
					Loading…
					
					
				
		Reference in new issue