From 9bdd66b9c93168cd5aa845e15986ce6659f86f33 Mon Sep 17 00:00:00 2001
From: Jose Olarte III
Date: Wed, 10 Sep 2025 18:19:17 +0800
Subject: [PATCH 1/3] feat(NewActivityView): enhance "See all" links to mark
offers as read before navigation
- Replace router-links with click handlers for both "See all" offers links
- Add handleSeeAllOffersToUser and handleSeeAllOffersToUserProjects methods
- Modify expandOffersToUserAndMarkRead to accept fromSeeAll parameter for contextual notifications
- Modify expandOffersToUserProjectsAndMarkRead to accept fromSeeAll parameter for contextual notifications
- Show shorter notification messages when called from "See all" vs chevron expand buttons
- Add safety checks to prevent errors when offers arrays are empty
- Standardize notification message text consistency
- TypeScript and formatting lint fixes
Both "See all" links now properly mark offers as viewed before navigation,
preventing users from seeing unread offers in the detailed views.
---
src/libs/util.ts | 17 +++++++++-----
src/views/ClaimView.vue | 2 +-
src/views/ConfirmGiftView.vue | 2 +-
src/views/NewActivityView.vue | 42 ++++++++++++++++++++++-------------
4 files changed, 40 insertions(+), 23 deletions(-)
diff --git a/src/libs/util.ts b/src/libs/util.ts
index c64916cc..432d8f72 100644
--- a/src/libs/util.ts
+++ b/src/libs/util.ts
@@ -165,18 +165,25 @@ export interface OfferFulfillment {
offerType: string;
}
+interface FulfillmentObject {
+ "@type": string;
+ identifier?: string;
+}
+
/**
* Extract offer fulfillment information from the fulfills field
* Handles both array and single object cases
*/
-export const extractOfferFulfillment = (fulfills: any): OfferFulfillment | null => {
+export const extractOfferFulfillment = (
+ fulfills: FulfillmentObject | FulfillmentObject[] | null | undefined,
+): OfferFulfillment | null => {
if (!fulfills) {
return null;
}
-
+
// Handle both array and single object cases
let offerFulfill = null;
-
+
if (Array.isArray(fulfills)) {
// Find the Offer in the fulfills array
offerFulfill = fulfills.find((item) => item["@type"] === "Offer");
@@ -184,14 +191,14 @@ export const extractOfferFulfillment = (fulfills: any): OfferFulfillment | null
// fulfills is a single Offer object
offerFulfill = fulfills;
}
-
+
if (offerFulfill) {
return {
offerHandleId: offerFulfill.identifier,
offerType: offerFulfill["@type"],
};
}
-
+
return null;
};
diff --git a/src/views/ClaimView.vue b/src/views/ClaimView.vue
index 2c441687..05ba7e07 100644
--- a/src/views/ClaimView.vue
+++ b/src/views/ClaimView.vue
@@ -734,7 +734,7 @@ export default class ClaimView extends Vue {
*/
extractOfferFulfillment() {
this.detailsForGiveOfferFulfillment = libsUtil.extractOfferFulfillment(
- this.detailsForGive?.fullClaim?.fulfills
+ this.detailsForGive?.fullClaim?.fulfills,
);
}
diff --git a/src/views/ConfirmGiftView.vue b/src/views/ConfirmGiftView.vue
index 95632bb7..5dc9fe0c 100644
--- a/src/views/ConfirmGiftView.vue
+++ b/src/views/ConfirmGiftView.vue
@@ -719,7 +719,7 @@ export default class ConfirmGiftView extends Vue {
*/
private extractOfferFulfillment() {
this.giveDetailsOfferFulfillment = libsUtil.extractOfferFulfillment(
- this.giveDetails?.fullClaim?.fulfills
+ this.giveDetails?.fullClaim?.fulfills,
);
}
diff --git a/src/views/NewActivityView.vue b/src/views/NewActivityView.vue
index fbcd7423..854d19ab 100644
--- a/src/views/NewActivityView.vue
+++ b/src/views/NewActivityView.vue
@@ -32,9 +32,9 @@
@click="expandOffersToUserAndMarkRead()"
/>
-
+
See all
-
+
@@ -99,9 +99,9 @@
@click="expandOffersToUserProjectsAndMarkRead()"
/>
-
+
See all
-
+
@@ -239,18 +239,18 @@ export default class NewActivityView extends Vue {
}
}
- async expandOffersToUserAndMarkRead() {
+ async expandOffersToUserAndMarkRead(fromSeeAll: boolean = false) {
this.showOffersDetails = !this.showOffersDetails;
- if (this.showOffersDetails) {
+ if (this.showOffersDetails && this.newOffersToUser.length > 0) {
await this.$updateSettings({
lastAckedOfferToUserJwtId: this.newOffersToUser[0].jwtId,
});
// note that we don't update this.lastAckedOfferToUserJwtId in case they
// later choose the last one to keep the offers as new
- this.notify.info(
- "The offers are marked as viewed. Click in the list to keep them as new.",
- TIMEOUTS.LONG,
- );
+ const message = fromSeeAll
+ ? "The offers are marked as viewed."
+ : "The offers are marked as viewed. Click in the list to keep them as new.";
+ this.notify.info(message, TIMEOUTS.LONG);
}
}
@@ -275,20 +275,20 @@ export default class NewActivityView extends Vue {
);
}
- async expandOffersToUserProjectsAndMarkRead() {
+ async expandOffersToUserProjectsAndMarkRead(fromSeeAll: boolean = false) {
this.showOffersToUserProjectsDetails =
!this.showOffersToUserProjectsDetails;
- if (this.showOffersToUserProjectsDetails) {
+ if (this.showOffersToUserProjectsDetails && this.newOffersToUserProjects.length > 0) {
await this.$updateSettings({
lastAckedOfferToUserProjectsJwtId:
this.newOffersToUserProjects[0].jwtId,
});
// note that we don't update this.lastAckedOfferToUserProjectsJwtId in case
// they later choose the last one to keep the offers as new
- this.notify.info(
- "The offers are now marked as viewed. Click in the list to keep them as new.",
- TIMEOUTS.LONG,
- );
+ const message = fromSeeAll
+ ? "The offers are marked as viewed."
+ : "The offers are marked as viewed. Click in the list to keep them as new.";
+ this.notify.info(message, TIMEOUTS.LONG);
}
}
@@ -314,5 +314,15 @@ export default class NewActivityView extends Vue {
TIMEOUTS.STANDARD,
);
}
+
+ async handleSeeAllOffersToUser() {
+ await this.expandOffersToUserAndMarkRead(true);
+ this.$router.push("/recent-offers-to-user");
+ }
+
+ async handleSeeAllOffersToUserProjects() {
+ await this.expandOffersToUserProjectsAndMarkRead(true);
+ this.$router.push("/recent-offers-to-user-projects");
+ }
}
--
2.30.2
From ac603f66e2bf6b4db8dbe64a290560cf71065eb5 Mon Sep 17 00:00:00 2001
From: Jose Olarte III
Date: Wed, 10 Sep 2025 18:19:40 +0800
Subject: [PATCH 2/3] Lint fix
---
src/views/NewActivityView.vue | 16 +++++++++++-----
1 file changed, 11 insertions(+), 5 deletions(-)
diff --git a/src/views/NewActivityView.vue b/src/views/NewActivityView.vue
index 854d19ab..a37ca36a 100644
--- a/src/views/NewActivityView.vue
+++ b/src/views/NewActivityView.vue
@@ -32,7 +32,7 @@
@click="expandOffersToUserAndMarkRead()"
/>
-
+
See all
@@ -99,7 +99,10 @@
@click="expandOffersToUserProjectsAndMarkRead()"
/>
-
+
See all
@@ -247,7 +250,7 @@ export default class NewActivityView extends Vue {
});
// note that we don't update this.lastAckedOfferToUserJwtId in case they
// later choose the last one to keep the offers as new
- const message = fromSeeAll
+ const message = fromSeeAll
? "The offers are marked as viewed."
: "The offers are marked as viewed. Click in the list to keep them as new.";
this.notify.info(message, TIMEOUTS.LONG);
@@ -278,14 +281,17 @@ export default class NewActivityView extends Vue {
async expandOffersToUserProjectsAndMarkRead(fromSeeAll: boolean = false) {
this.showOffersToUserProjectsDetails =
!this.showOffersToUserProjectsDetails;
- if (this.showOffersToUserProjectsDetails && this.newOffersToUserProjects.length > 0) {
+ if (
+ this.showOffersToUserProjectsDetails &&
+ this.newOffersToUserProjects.length > 0
+ ) {
await this.$updateSettings({
lastAckedOfferToUserProjectsJwtId:
this.newOffersToUserProjects[0].jwtId,
});
// note that we don't update this.lastAckedOfferToUserProjectsJwtId in case
// they later choose the last one to keep the offers as new
- const message = fromSeeAll
+ const message = fromSeeAll
? "The offers are marked as viewed."
: "The offers are marked as viewed. Click in the list to keep them as new.";
this.notify.info(message, TIMEOUTS.LONG);
--
2.30.2
From 5d9f455fc8744ddb3c325d899d8b0f664c2dabc0 Mon Sep 17 00:00:00 2001
From: Jose Olarte III
Date: Tue, 16 Sep 2025 18:10:17 +0800
Subject: [PATCH 3/3] feat: move mark-as-read logic from navigation to view
loading
- Remove mark-as-read logic from NewActivityView navigation handlers
- Add mark-as-read logic to RecentOffersToUserView and RecentOffersToUserProjectsView after data loading
- Improve "You've already seen all the following" marker positioning
- Update marker styling with dashed border and centered text
This ensures the marker appears at the correct position in the list
instead of always at the top, providing better UX when viewing offers.
---
src/views/NewActivityView.vue | 2 --
src/views/RecentOffersToUserProjectsView.vue | 21 ++++++++++++++------
src/views/RecentOffersToUserView.vue | 20 +++++++++++++------
3 files changed, 29 insertions(+), 14 deletions(-)
diff --git a/src/views/NewActivityView.vue b/src/views/NewActivityView.vue
index a37ca36a..233a8f4d 100644
--- a/src/views/NewActivityView.vue
+++ b/src/views/NewActivityView.vue
@@ -322,12 +322,10 @@ export default class NewActivityView extends Vue {
}
async handleSeeAllOffersToUser() {
- await this.expandOffersToUserAndMarkRead(true);
this.$router.push("/recent-offers-to-user");
}
async handleSeeAllOffersToUserProjects() {
- await this.expandOffersToUserProjectsAndMarkRead(true);
this.$router.push("/recent-offers-to-user-projects");
}
}
diff --git a/src/views/RecentOffersToUserProjectsView.vue b/src/views/RecentOffersToUserProjectsView.vue
index c294d053..4125f983 100644
--- a/src/views/RecentOffersToUserProjectsView.vue
+++ b/src/views/RecentOffersToUserProjectsView.vue
@@ -32,20 +32,20 @@
-
-