From 3c790dceb7523007bfa310f0915ce7703e36759a Mon Sep 17 00:00:00 2001 From: Trent Larson Date: Sun, 3 Nov 2024 10:39:28 -0700 Subject: [PATCH] add large notice when user has a new offer to them --- src/components/OfferDialog.vue | 6 +- src/db/tables/settings.ts | 7 +- src/libs/endorserServer.ts | 11 +++ src/router/index.ts | 5 ++ src/views/ContactGiftingView.vue | 2 +- src/views/ContactsView.vue | 38 +++++------ src/views/HomeView.vue | 50 ++++++++++++-- src/views/NewActivityView.vue | 111 +++++++++++++++++++++++++++++++ 8 files changed, 199 insertions(+), 31 deletions(-) create mode 100644 src/views/NewActivityView.vue diff --git a/src/components/OfferDialog.vue b/src/components/OfferDialog.vue index 47064a938..c62595250 100644 --- a/src/components/OfferDialog.vue +++ b/src/components/OfferDialog.vue @@ -207,9 +207,9 @@ export default class OfferDialog extends Vue { group: "alert", type: "danger", title: "Error", - text: "You must select an identifier before you can record an offer.", + text: "You must select an identity before you can record an offer.", }, - -1, + 7000, ); return; } @@ -264,7 +264,7 @@ export default class OfferDialog extends Vue { title: "Success", text: "That offer was recorded.", }, - 10000, + 5000, ); } // eslint-disable-next-line @typescript-eslint/no-explicit-any diff --git a/src/db/tables/settings.ts b/src/db/tables/settings.ts index 517a4d06b..22832b6bf 100644 --- a/src/db/tables/settings.ts +++ b/src/db/tables/settings.ts @@ -31,8 +31,13 @@ export type Settings = { isRegistered?: boolean; imageServer?: string; lastName?: string; // deprecated - put all names in firstName + + lastAckedOfferToUserJwtId?: string; // the last JWT ID for offer-to-user that they've acknowledged + + // The claim list has a most recent one used in notifications that's separate from the last viewed lastNotifiedClaimId?: string; lastViewedClaimId?: string; + passkeyExpirationMinutes?: number; // passkey access token time-to-live in minutes profileImageUrl?: string; // may be null if unwanted for a particular account reminderTime?: number; // Time in milliseconds since UNIX epoch for reminders @@ -53,7 +58,7 @@ export type Settings = { webPushServer?: string; // Web Push server URL }; -export function isAnyFeedFilterOn(settings: Settings): boolean { +export function checkIsAnyFeedFilterOn(settings: Settings): boolean { return !!(settings?.filterFeedByNearby || settings?.filterFeedByVisible); } diff --git a/src/libs/endorserServer.ts b/src/libs/endorserServer.ts index 767245b03..3dfb81560 100644 --- a/src/libs/endorserServer.ts +++ b/src/libs/endorserServer.ts @@ -587,6 +587,17 @@ export async function setPlanInCache( planCache.set(handleId, planSummary); } +export async function getNewOffersToUser(axios: Axios, apiServer: string, activeDid: string, lastAckedOfferToUserJwtId?: string) { + let url = `${apiServer}/api/v2/report/offers?recipientDid=${activeDid}`; + if (lastAckedOfferToUserJwtId) { + url += "&afterId=" + lastAckedOfferToUserJwtId; + } + const headers = await getHeaders(activeDid); + const response = await axios.get(url, { headers }); + const offers = response.data.data; + return offers; +} + /** * Construct GiveAction VC for submission to server * diff --git a/src/router/index.ts b/src/router/index.ts index 3ceda6a6d..9b81a1421 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -133,6 +133,11 @@ const routes: Array = [ name: "invite-one", component: () => import("../views/InviteOneView.vue"), }, + { + path: "/new-activity", + name: "new-activity", + component: () => import("../views/NewActivityView.vue"), + }, { path: "/new-edit-account", name: "new-edit-account", diff --git a/src/views/ContactGiftingView.vue b/src/views/ContactGiftingView.vue index 2a6424977..07a00ac20 100644 --- a/src/views/ContactGiftingView.vue +++ b/src/views/ContactGiftingView.vue @@ -123,7 +123,7 @@ export default class ContactGiftingView extends Vue { err.message || "There was an error retrieving your settings or contacts.", }, - -1, + 5000, ); } } diff --git a/src/views/ContactsView.vue b/src/views/ContactsView.vue index 5fc815d65..838a19e95 100644 --- a/src/views/ContactsView.vue +++ b/src/views/ContactsView.vue @@ -88,7 +88,7 @@ @click="toggleShowContactAmounts()" > {{ - showGiveNumbers ? "Hide Given Hours etc" : "Show Given Hours etc" + showGiveNumbers ? "Hide Given Hours, etc" : "Show Given Hours, etc" }} @@ -182,44 +182,40 @@ > + + +
  • You've already seen all the following @@ -345,7 +371,7 @@ import { import { Contact } from "@/db/tables/contacts"; import { BoundingBox, - isAnyFeedFilterOn, + checkIsAnyFeedFilterOn, MASTER_SETTINGS_KEY, } from "@/db/tables/settings"; import { @@ -354,6 +380,7 @@ import { didInfoForContact, fetchEndorserRateLimits, getHeaders, + getNewOffersToUser, getPlanFromCache, GiveSummaryRecord, } from "@/libs/endorserServer"; @@ -418,6 +445,8 @@ export default class HomeView extends Vue { isFeedFilteredByNearby = false; isFeedLoading = true; isRegistered = false; + lastAckedOfferToUserJwtId?: string; // the last JWT ID for offer-to-user that they've acknowledged + numNewOffersToUser: number = 0; // number of new offers-to-user searchBoxes: Array<{ name: string; bbox: BoundingBox; @@ -447,10 +476,11 @@ export default class HomeView extends Vue { this.isFeedFilteredByVisible = !!settings.filterFeedByVisible; this.isFeedFilteredByNearby = !!settings.filterFeedByNearby; this.isRegistered = !!settings.isRegistered; + this.lastAckedOfferToUserJwtId = settings.lastAckedOfferToUserJwtId; this.searchBoxes = settings.searchBoxes || []; this.showShortcutBvc = !!settings.showShortcutBvc; - this.isAnyFeedFilterOn = isAnyFeedFilterOn(settings); + this.isAnyFeedFilterOn = checkIsAnyFeedFilterOn(settings); if (!settings.finishedOnboarding) { (this.$refs.onboardingDialog as OnboardingDialog).open( @@ -480,6 +510,12 @@ export default class HomeView extends Vue { // this returns a Promise but we don't need to wait for it this.updateAllFeed(); + if (this.activeDid) { + this.numNewOffersToUser = + (await getNewOffersToUser(this.axios, this.apiServer, this.activeDid, this.lastAckedOfferToUserJwtId)) + .length; + } + // eslint-disable-next-line @typescript-eslint/no-explicit-any } catch (err: any) { console.error("Error retrieving settings or feed.", err); @@ -519,7 +555,7 @@ export default class HomeView extends Vue { const settings = await retrieveSettingsForActiveAccount(); this.isFeedFilteredByVisible = !!settings.filterFeedByVisible; this.isFeedFilteredByNearby = !!settings.filterFeedByNearby; - this.isAnyFeedFilterOn = isAnyFeedFilterOn(settings); + this.isAnyFeedFilterOn = checkIsAnyFeedFilterOn(settings); this.feedData = []; this.feedPreviousOldestId = undefined; @@ -782,6 +818,10 @@ export default class HomeView extends Vue { } } + goToActivityToUserPage() { + (this.$router as Router).push({ name: "new-activity" }); + } + onClickLoadClaim(jwtId: string) { const route = { path: "/claim/" + encodeURIComponent(jwtId), @@ -820,7 +860,7 @@ export default class HomeView extends Vue { (this.$refs.feedFilters as FeedFilters).open(this.reloadFeedOnChange); } - toastUser(message) { + toastUser(message: string) { this.$notify( { group: "alert", diff --git a/src/views/NewActivityView.vue b/src/views/NewActivityView.vue new file mode 100644 index 000000000..807374f2c --- /dev/null +++ b/src/views/NewActivityView.vue @@ -0,0 +1,111 @@ + + +