7 changed files with 374 additions and 48 deletions
			
			
		@ -0,0 +1,150 @@ | 
				
			|||
<template> | 
				
			|||
  <QuickNav selected="Home"></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 --> | 
				
			|||
        <fa | 
				
			|||
          icon="chevron-left" | 
				
			|||
          @click="$router.back()" | 
				
			|||
          class="fa-fw text-lg text-center px-2 py-1 absolute -left-2 -top-1" | 
				
			|||
        /> | 
				
			|||
        Offers to Your Projects | 
				
			|||
      </h1> | 
				
			|||
    </div> | 
				
			|||
 | 
				
			|||
    <InfiniteScroll @reached-bottom="loadMoreOffersToUserProjects"> | 
				
			|||
      <ul id="listLatestActivity" class="border-t border-slate-300"> | 
				
			|||
        <li | 
				
			|||
          v-for="offer in newOffersToUserProjects" | 
				
			|||
          :key="offer.jwtId" | 
				
			|||
          class="mt-4 relative group" | 
				
			|||
        > | 
				
			|||
          <div | 
				
			|||
            class="border-b border-slate-300 text-orange-400 pb-2 mb-2 font-bold text-sm" | 
				
			|||
            v-if="offer.jwtId == lastAckedOfferToUserProjectsJwtId" | 
				
			|||
          > | 
				
			|||
            You've already seen all the following | 
				
			|||
          </div> | 
				
			|||
 | 
				
			|||
          <span>{{ | 
				
			|||
            didInfo(offer.offeredByDid, activeDid, allMyDids, allContacts) | 
				
			|||
          }}</span> | 
				
			|||
          offered | 
				
			|||
          <span v-if="offer.objectDescription">{{ | 
				
			|||
            offer.objectDescription | 
				
			|||
          }}</span | 
				
			|||
          >{{ offer.objectDescription && offer.amount ? ", and " : "" }} | 
				
			|||
          <span v-if="offer.amount">{{ | 
				
			|||
            displayAmount(offer.unit, offer.amount) | 
				
			|||
          }}</span> | 
				
			|||
          to | 
				
			|||
          <span>{{ offer.planName }}</span> | 
				
			|||
          <router-link | 
				
			|||
            :to="{ path: '/claim/' + encodeURIComponent(offer.jwtId) }" | 
				
			|||
            class="text-blue-500" | 
				
			|||
          > | 
				
			|||
            <fa icon="file-lines" class="pl-2 text-blue-500 cursor-pointer" /> | 
				
			|||
          </router-link> | 
				
			|||
        </li> | 
				
			|||
      </ul> | 
				
			|||
    </InfiniteScroll> | 
				
			|||
  </section> | 
				
			|||
</template> | 
				
			|||
 | 
				
			|||
<script lang="ts"> | 
				
			|||
import { Component, Vue } from "vue-facing-decorator"; | 
				
			|||
 | 
				
			|||
import EntityIcon from "@/components/EntityIcon.vue"; | 
				
			|||
import GiftedDialog from "@/components/GiftedDialog.vue"; | 
				
			|||
import InfiniteScroll from "@/components/InfiniteScroll.vue"; | 
				
			|||
import QuickNav from "@/components/QuickNav.vue"; | 
				
			|||
import { NotificationIface } from "@/constants/app"; | 
				
			|||
import { accountsDB, db, retrieveSettingsForActiveAccount } from "@/db/index"; | 
				
			|||
import { Contact } from "@/db/tables/contacts"; | 
				
			|||
import { | 
				
			|||
  didInfo, | 
				
			|||
  displayAmount, | 
				
			|||
  getNewOffersToUserProjects, | 
				
			|||
  OfferToPlanSummaryRecord, | 
				
			|||
} from "@/libs/endorserServer"; | 
				
			|||
 | 
				
			|||
@Component({ | 
				
			|||
  components: { EntityIcon, GiftedDialog, InfiniteScroll, QuickNav }, | 
				
			|||
}) | 
				
			|||
export default class RecentOffersToUserView extends Vue { | 
				
			|||
  $notify!: (notification: NotificationIface, timeout?: number) => void; | 
				
			|||
 | 
				
			|||
  activeDid = ""; | 
				
			|||
  allContacts: Array<Contact> = []; | 
				
			|||
  allMyDids: string[] = []; | 
				
			|||
  apiServer = ""; | 
				
			|||
  lastAckedOfferToUserProjectsJwtId = ""; | 
				
			|||
  newOffersToUserProjects: Array<OfferToPlanSummaryRecord> = []; | 
				
			|||
  newOffersToUserProjectsAtEnd = false; | 
				
			|||
 | 
				
			|||
  showOffersDetails = false; | 
				
			|||
  showOffersToUserProjectsDetails = false; | 
				
			|||
  didInfo = didInfo; | 
				
			|||
  displayAmount = displayAmount; | 
				
			|||
 | 
				
			|||
  async created() { | 
				
			|||
    try { | 
				
			|||
      const settings = await retrieveSettingsForActiveAccount(); | 
				
			|||
      this.apiServer = settings.apiServer || ""; | 
				
			|||
      this.activeDid = settings.activeDid || ""; | 
				
			|||
      this.lastAckedOfferToUserProjectsJwtId = | 
				
			|||
        settings.lastAckedOfferToUserProjectsJwtId || ""; | 
				
			|||
 | 
				
			|||
      this.allContacts = await db.contacts.toArray(); | 
				
			|||
 | 
				
			|||
      await accountsDB.open(); | 
				
			|||
      const allAccounts = await accountsDB.accounts.toArray(); | 
				
			|||
      if (allAccounts.length > 0) { | 
				
			|||
        this.allMyDids = allAccounts.map((acc) => acc.did); | 
				
			|||
      } | 
				
			|||
 | 
				
			|||
      const offersToUserProjectsData = await getNewOffersToUserProjects( | 
				
			|||
        this.axios, | 
				
			|||
        this.apiServer, | 
				
			|||
        this.activeDid, | 
				
			|||
        undefined, | 
				
			|||
        undefined, | 
				
			|||
      ); | 
				
			|||
      this.newOffersToUserProjects = offersToUserProjectsData.data; | 
				
			|||
      this.newOffersToUserProjectsAtEnd = !offersToUserProjectsData.hitLimit; | 
				
			|||
 | 
				
			|||
      // eslint-disable-next-line @typescript-eslint/no-explicit-any | 
				
			|||
    } catch (err: any) { | 
				
			|||
      console.error("Error retrieving settings & contacts:", err); | 
				
			|||
      this.$notify( | 
				
			|||
        { | 
				
			|||
          group: "alert", | 
				
			|||
          type: "danger", | 
				
			|||
          title: "Error", | 
				
			|||
          text: err.message || "There was an error retrieving your activity.", | 
				
			|||
        }, | 
				
			|||
        5000, | 
				
			|||
      ); | 
				
			|||
    } | 
				
			|||
  } | 
				
			|||
 | 
				
			|||
  async loadMoreOffersToUserProjects() { | 
				
			|||
    if (this.newOffersToUserProjectsAtEnd) { | 
				
			|||
      return; | 
				
			|||
    } | 
				
			|||
    const offersToUserProjectsData = await getNewOffersToUserProjects( | 
				
			|||
      this.axios, | 
				
			|||
      this.apiServer, | 
				
			|||
      this.activeDid, | 
				
			|||
      undefined, | 
				
			|||
      this.newOffersToUserProjects[this.newOffersToUserProjects.length - 1] | 
				
			|||
        .jwtId, | 
				
			|||
    ); | 
				
			|||
    this.newOffersToUserProjects.push(...offersToUserProjectsData.data); | 
				
			|||
    this.newOffersToUserProjectsAtEnd = !offersToUserProjectsData.hitLimit; | 
				
			|||
  } | 
				
			|||
} | 
				
			|||
</script> | 
				
			|||
@ -0,0 +1,146 @@ | 
				
			|||
<template> | 
				
			|||
  <QuickNav selected="Home"></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 --> | 
				
			|||
        <fa | 
				
			|||
          icon="chevron-left" | 
				
			|||
          @click="$router.back()" | 
				
			|||
          class="fa-fw text-lg text-center px-2 py-1 absolute -left-2 -top-1" | 
				
			|||
        /> | 
				
			|||
        Offers to You | 
				
			|||
      </h1> | 
				
			|||
    </div> | 
				
			|||
 | 
				
			|||
    <InfiniteScroll @reached-bottom="loadMoreOffersToUser"> | 
				
			|||
      <ul id="listLatestActivity" class="border-t border-slate-300"> | 
				
			|||
        <li | 
				
			|||
          v-for="offer in newOffersToUser" | 
				
			|||
          :key="offer.jwtId" | 
				
			|||
          class="mt-4 relative group" | 
				
			|||
        > | 
				
			|||
          <div | 
				
			|||
            class="border-b border-slate-300 text-orange-400 pb-2 mb-2 font-bold text-sm" | 
				
			|||
            v-if="offer.jwtId == lastAckedOfferToUserJwtId" | 
				
			|||
          > | 
				
			|||
            You've already seen all the following | 
				
			|||
          </div> | 
				
			|||
 | 
				
			|||
          <span>{{ | 
				
			|||
            didInfo(offer.offeredByDid, activeDid, allMyDids, allContacts) | 
				
			|||
          }}</span> | 
				
			|||
          offered | 
				
			|||
          <span v-if="offer.objectDescription">{{ | 
				
			|||
            offer.objectDescription | 
				
			|||
          }}</span | 
				
			|||
          >{{ offer.objectDescription && offer.amount ? ", and " : "" }} | 
				
			|||
          <span v-if="offer.amount">{{ | 
				
			|||
            displayAmount(offer.unit, offer.amount) | 
				
			|||
          }}</span> | 
				
			|||
          <router-link | 
				
			|||
            :to="{ path: '/claim/' + encodeURIComponent(offer.jwtId) }" | 
				
			|||
            class="text-blue-500" | 
				
			|||
          > | 
				
			|||
            <fa icon="file-lines" class="pl-2 text-blue-500 cursor-pointer" /> | 
				
			|||
          </router-link> | 
				
			|||
        </li> | 
				
			|||
      </ul> | 
				
			|||
    </InfiniteScroll> | 
				
			|||
  </section> | 
				
			|||
</template> | 
				
			|||
 | 
				
			|||
<script lang="ts"> | 
				
			|||
import { Component, Vue } from "vue-facing-decorator"; | 
				
			|||
 | 
				
			|||
import GiftedDialog from "@/components/GiftedDialog.vue"; | 
				
			|||
import EntityIcon from "@/components/EntityIcon.vue"; | 
				
			|||
import InfiniteScroll from "@/components/InfiniteScroll.vue"; | 
				
			|||
import QuickNav from "@/components/QuickNav.vue"; | 
				
			|||
import { NotificationIface } from "@/constants/app"; | 
				
			|||
import { accountsDB, db, retrieveSettingsForActiveAccount } from "@/db/index"; | 
				
			|||
import { Contact } from "@/db/tables/contacts"; | 
				
			|||
import { | 
				
			|||
  didInfo, | 
				
			|||
  displayAmount, | 
				
			|||
  getNewOffersToUser, | 
				
			|||
  OfferSummaryRecord, | 
				
			|||
} from "@/libs/endorserServer"; | 
				
			|||
 | 
				
			|||
@Component({ | 
				
			|||
  components: { EntityIcon, GiftedDialog, InfiniteScroll, QuickNav }, | 
				
			|||
}) | 
				
			|||
export default class RecentOffersToUserView extends Vue { | 
				
			|||
  $notify!: (notification: NotificationIface, timeout?: number) => void; | 
				
			|||
 | 
				
			|||
  activeDid = ""; | 
				
			|||
  allContacts: Array<Contact> = []; | 
				
			|||
  allMyDids: string[] = []; | 
				
			|||
  apiServer = ""; | 
				
			|||
  lastAckedOfferToUserJwtId = ""; | 
				
			|||
  newOffersToUser: Array<OfferSummaryRecord> = []; | 
				
			|||
  newOffersToUserAtEnd = false; | 
				
			|||
 | 
				
			|||
  showOffersDetails = false; | 
				
			|||
  showOffersToUserProjectsDetails = false; | 
				
			|||
  didInfo = didInfo; | 
				
			|||
  displayAmount = displayAmount; | 
				
			|||
 | 
				
			|||
  async created() { | 
				
			|||
    try { | 
				
			|||
      const settings = await retrieveSettingsForActiveAccount(); | 
				
			|||
      this.apiServer = settings.apiServer || ""; | 
				
			|||
      this.activeDid = settings.activeDid || ""; | 
				
			|||
      this.lastAckedOfferToUserJwtId = settings.lastAckedOfferToUserJwtId || ""; | 
				
			|||
 | 
				
			|||
      this.allContacts = await db.contacts.toArray(); | 
				
			|||
 | 
				
			|||
      await accountsDB.open(); | 
				
			|||
      const allAccounts = await accountsDB.accounts.toArray(); | 
				
			|||
      if (allAccounts.length > 0) { | 
				
			|||
        this.allMyDids = allAccounts.map((acc) => acc.did); | 
				
			|||
      } | 
				
			|||
 | 
				
			|||
      const offersToUserData = await getNewOffersToUser( | 
				
			|||
        this.axios, | 
				
			|||
        this.apiServer, | 
				
			|||
        this.activeDid, | 
				
			|||
        undefined, | 
				
			|||
        undefined, | 
				
			|||
      ); | 
				
			|||
      this.newOffersToUser = offersToUserData.data; | 
				
			|||
      this.newOffersToUserAtEnd = !offersToUserData.hitLimit; | 
				
			|||
 | 
				
			|||
      // eslint-disable-next-line @typescript-eslint/no-explicit-any | 
				
			|||
    } catch (err: any) { | 
				
			|||
      console.error("Error retrieving settings & contacts:", err); | 
				
			|||
      this.$notify( | 
				
			|||
        { | 
				
			|||
          group: "alert", | 
				
			|||
          type: "danger", | 
				
			|||
          title: "Error", | 
				
			|||
          text: err.message || "There was an error retrieving your activity.", | 
				
			|||
        }, | 
				
			|||
        5000, | 
				
			|||
      ); | 
				
			|||
    } | 
				
			|||
  } | 
				
			|||
 | 
				
			|||
  async loadMoreOffersToUser() { | 
				
			|||
    if (this.newOffersToUserAtEnd) { | 
				
			|||
      return; | 
				
			|||
    } | 
				
			|||
    const offersToUserData = await getNewOffersToUser( | 
				
			|||
      this.axios, | 
				
			|||
      this.apiServer, | 
				
			|||
      this.activeDid, | 
				
			|||
      undefined, | 
				
			|||
      this.newOffersToUser[this.newOffersToUser.length - 1].jwtId, | 
				
			|||
    ); | 
				
			|||
    this.newOffersToUser.push(...offersToUserData.data); | 
				
			|||
    this.newOffersToUserAtEnd = !offersToUserData.hitLimit; | 
				
			|||
  } | 
				
			|||
} | 
				
			|||
</script> | 
				
			|||
					Loading…
					
					
				
		Reference in new issue