diff --git a/src/components/ActivityListItem.vue b/src/components/ActivityListItem.vue
new file mode 100644
index 000000000..43dbfdb49
--- /dev/null
+++ b/src/components/ActivityListItem.vue
@@ -0,0 +1,334 @@
+
+
+
+
+
+ You've already seen all the following
+
+
+
+
+
+

+
+
+
+ {{
+ record.giver.known ? record.giver.displayName : "Anonymous Giver"
+ }}
+
+
+ {{ friendlyDate }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ record.giver.displayName }}
+
+
+
+
+
+
+ {{ fetchAmount }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ record.receiver.displayName }}
+
+
+
+
+
+
+
+ {{ description }}
+
+
+
{{ subDescription }}
+
+
+
+
+
+
+
diff --git a/src/main.ts b/src/main.ts
index af6b30703..1b21524a4 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -7,7 +7,171 @@ import axios from "axios";
import VueAxios from "vue-axios";
import Notifications from "notiwind";
import "./assets/styles/tailwind.css";
-import { FontAwesomeIcon } from "./lib/fontawesome";
+
+import { library } from "@fortawesome/fontawesome-svg-core";
+import {
+ faArrowDown,
+ faArrowLeft,
+ faArrowRight,
+ faArrowRotateBackward,
+ faArrowUpRightFromSquare,
+ faArrowUp,
+ faBan,
+ faBitcoinSign,
+ faBurst,
+ faCalendar,
+ faCamera,
+ faCaretDown,
+ faChair,
+ faCheck,
+ faChevronDown,
+ faChevronLeft,
+ faChevronRight,
+ faChevronUp,
+ faCircle,
+ faCircleCheck,
+ faCircleInfo,
+ faCircleQuestion,
+ faCircleUser,
+ faClock,
+ faCoins,
+ faComment,
+ faCopy,
+ faDollar,
+ faEllipsis,
+ faEllipsisVertical,
+ faEnvelopeOpenText,
+ faEraser,
+ faEye,
+ faEyeSlash,
+ faFileContract,
+ faFileLines,
+ faFilter,
+ faFloppyDisk,
+ faFolderOpen,
+ faForward,
+ faGift,
+ faGlobe,
+ faHammer,
+ faHand,
+ faHandHoldingDollar,
+ faHandHoldingHeart,
+ faHouseChimney,
+ faImage,
+ faImagePortrait,
+ faLeftRight,
+ faLightbulb,
+ faLink,
+ faLocationDot,
+ faLongArrowAltLeft,
+ faLongArrowAltRight,
+ faMagnifyingGlass,
+ faMessage,
+ faMinus,
+ faPen,
+ faPersonCircleCheck,
+ faPersonCircleQuestion,
+ faPlus,
+ faQuestion,
+ faQrcode,
+ faRightFromBracket,
+ faRotate,
+ faShareNodes,
+ faSpinner,
+ faSquare,
+ faSquareCaretDown,
+ faSquareCaretUp,
+ faSquarePlus,
+ faTrashCan,
+ faTriangleExclamation,
+ faUser,
+ faUsers,
+ faXmark,
+ faBuilding,
+} from "@fortawesome/free-solid-svg-icons";
+
+library.add(
+ faArrowDown,
+ faArrowLeft,
+ faArrowRight,
+ faArrowRotateBackward,
+ faArrowUpRightFromSquare,
+ faArrowUp,
+ faBan,
+ faBitcoinSign,
+ faBurst,
+ faCalendar,
+ faCamera,
+ faCaretDown,
+ faChair,
+ faCheck,
+ faChevronDown,
+ faChevronLeft,
+ faChevronRight,
+ faChevronUp,
+ faCircle,
+ faCircleCheck,
+ faCircleInfo,
+ faCircleQuestion,
+ faCircleUser,
+ faClock,
+ faCoins,
+ faComment,
+ faCopy,
+ faDollar,
+ faEllipsis,
+ faEllipsisVertical,
+ faEnvelopeOpenText,
+ faEraser,
+ faEye,
+ faEyeSlash,
+ faFileContract,
+ faFileLines,
+ faFilter,
+ faFloppyDisk,
+ faFolderOpen,
+ faForward,
+ faGift,
+ faGlobe,
+ faHammer,
+ faHand,
+ faHandHoldingDollar,
+ faHandHoldingHeart,
+ faHouseChimney,
+ faImage,
+ faImagePortrait,
+ faLeftRight,
+ faLightbulb,
+ faLink,
+ faLocationDot,
+ faLongArrowAltLeft,
+ faLongArrowAltRight,
+ faMagnifyingGlass,
+ faMessage,
+ faMinus,
+ faPen,
+ faPersonCircleCheck,
+ faPersonCircleQuestion,
+ faPlus,
+ faQrcode,
+ faQuestion,
+ faRotate,
+ faRightFromBracket,
+ faShareNodes,
+ faSpinner,
+ faSquare,
+ faSquareCaretDown,
+ faSquareCaretUp,
+ faSquarePlus,
+ faTrashCan,
+ faTriangleExclamation,
+ faUser,
+ faUsers,
+ faXmark,
+ faBuilding,
+);
+
+import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
import Camera from "simple-vue-camera";
import { logger } from "./utils/logger";
diff --git a/src/types/index.ts b/src/types/index.ts
new file mode 100644
index 000000000..4eb29df99
--- /dev/null
+++ b/src/types/index.ts
@@ -0,0 +1,20 @@
+export interface GiveRecordWithContactInfo {
+ jwtId: string;
+ fullClaim: unknown; // Replace with proper type
+ giver: {
+ known: boolean;
+ displayName: string;
+ profileImageUrl?: string;
+ };
+ receiver: {
+ known: boolean;
+ displayName: string;
+ profileImageUrl?: string;
+ };
+ providerPlanName?: string;
+ recipientProjectName?: string;
+ description?: string;
+ subDescription?: string;
+ image?: string;
+ timestamp: string;
+}
diff --git a/src/views/HomeView.vue b/src/views/HomeView.vue
index 6e91732c7..57a3e6416 100644
--- a/src/views/HomeView.vue
+++ b/src/views/HomeView.vue
@@ -187,23 +187,23 @@
-
+
-
+
Latest Activity
-
@@ -250,84 +250,20 @@
-
- -
+
-
- You've already seen all the following
-
-
-
-
-
-
-
-
-
-
-
- {{ giveDescription(record) }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
![shared content]()
-
-
-
+ :record="record"
+ :last-viewed-claim-id="feedLastViewedClaimId"
+ :is-registered="isRegistered"
+ :active-did="activeDid"
+ :confirmer-id-list="record.confirmerIdList"
+ @load-claim="onClickLoadClaim"
+ @view-image="openImageViewer"
+ @cache-image="cacheImageData"
+ @confirm-claim="confirmClaim"
+ />
@@ -369,6 +305,7 @@ import TopMessage from "../components/TopMessage.vue";
import UserNameDialog from "../components/UserNameDialog.vue";
import ChoiceButtonDialog from "../components/ChoiceButtonDialog.vue";
import ImageViewer from "../components/ImageViewer.vue";
+import ActivityListItem from "../components/ActivityListItem.vue";
import {
AppString,
NotificationIface,
@@ -403,6 +340,9 @@ import {
OnboardPage,
} from "../libs/util";
import { GiveSummaryRecord } from "../interfaces";
+import * as serverUtil from "../libs/endorserServer";
+// import { fa0 } from "@fortawesome/free-solid-svg-icons";
+
interface GiveRecordWithContactInfo extends GiveSummaryRecord {
jwtId: string;
giver: {
@@ -442,6 +382,7 @@ import { logger } from "../utils/logger";
TopMessage,
UserNameDialog,
ImageViewer,
+ ActivityListItem,
},
})
export default class HomeView extends Vue {
@@ -522,10 +463,88 @@ export default class HomeView extends Vue {
this.isCreatingIdentifier = false;
this.allMyDids = [newDid];
}
- } catch (error) {
- logConsoleAndDb(
- "Error retrieving all account DIDs on home page:" + error,
- true,
+
+ const settings = await retrieveSettingsForActiveAccount();
+ this.apiServer = settings.apiServer || "";
+ this.activeDid = settings.activeDid || "";
+ this.allContacts = await db.contacts.toArray();
+ this.feedLastViewedClaimId = settings.lastViewedClaimId;
+ this.givenName = settings.firstName || "";
+ this.isFeedFilteredByVisible = !!settings.filterFeedByVisible;
+ this.isFeedFilteredByNearby = !!settings.filterFeedByNearby;
+ this.isRegistered = !!settings.isRegistered;
+ this.lastAckedOfferToUserJwtId = settings.lastAckedOfferToUserJwtId;
+ this.lastAckedOfferToUserProjectsJwtId =
+ settings.lastAckedOfferToUserProjectsJwtId;
+ this.searchBoxes = settings.searchBoxes || [];
+ this.showShortcutBvc = !!settings.showShortcutBvc;
+
+ this.isAnyFeedFilterOn = checkIsAnyFeedFilterOn(settings);
+
+ if (!settings.finishedOnboarding) {
+ (this.$refs.onboardingDialog as OnboardingDialog).open(
+ OnboardPage.Home,
+ );
+ }
+
+ // someone may have have registered after sharing contact info, so recheck
+ if (!this.isRegistered && this.activeDid) {
+ try {
+ const resp = await fetchEndorserRateLimits(
+ this.apiServer,
+ this.axios,
+ this.activeDid,
+ );
+ if (resp.status === 200) {
+ await updateAccountSettings(this.activeDid, {
+ isRegistered: true,
+ ...(await retrieveSettingsForActiveAccount()),
+ });
+ this.isRegistered = true;
+ }
+ } catch (e) {
+ // ignore the error... just keep us unregistered
+ }
+ }
+
+ // this returns a Promise but we don't need to wait for it
+ this.updateAllFeed();
+
+ if (this.activeDid) {
+ const offersToUserData = await getNewOffersToUser(
+ this.axios,
+ this.apiServer,
+ this.activeDid,
+ this.lastAckedOfferToUserJwtId,
+ );
+ this.numNewOffersToUser = offersToUserData.data.length;
+ this.newOffersToUserHitLimit = offersToUserData.hitLimit;
+ }
+
+ if (this.activeDid) {
+ const offersToUserProjects = await getNewOffersToUserProjects(
+ this.axios,
+ this.apiServer,
+ this.activeDid,
+ this.lastAckedOfferToUserProjectsJwtId,
+ );
+ this.numNewOffersToUserProjects = offersToUserProjects.data.length;
+ this.newOffersToUserProjectsHitLimit = offersToUserProjects.hitLimit;
+ }
+
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ } catch (err: any) {
+ logConsoleAndDb("Error retrieving settings or feed: " + err, true);
+ this.$notify(
+ {
+ group: "alert",
+ type: "danger",
+ title: "Error",
+ text:
+ err.userMessage ||
+ "There was an error retrieving your settings or the latest activity.",
+ },
+ 5000,
);
}
}
@@ -1079,5 +1098,67 @@ export default class HomeView extends Vue {
this.selectedImage = imageUrl;
this.isImageViewerOpen = true;
}
+
+ async confirmClaim(record: GiveRecordWithContactInfo) {
+ this.$notify(
+ {
+ group: "modal",
+ type: "confirm",
+ title: "Confirm",
+ text: "Do you personally confirm that this is true?",
+ onYes: async () => {
+ const goodClaim = serverUtil.removeSchemaContext(
+ serverUtil.removeVisibleToDids(
+ serverUtil.addLastClaimOrHandleAsIdIfMissing(
+ record.fullClaim,
+ record.jwtId,
+ record.handleId,
+ ),
+ ),
+ );
+
+ const confirmationClaim = {
+ "@context": "https://schema.org",
+ "@type": "AgreeAction",
+ object: goodClaim,
+ };
+
+ const result = await serverUtil.createAndSubmitClaim(
+ confirmationClaim,
+ this.activeDid,
+ this.apiServer,
+ this.axios,
+ );
+
+ if (result.type === "success") {
+ this.$notify(
+ {
+ group: "alert",
+ type: "success",
+ title: "Success",
+ text: "Confirmation submitted.",
+ },
+ 3000,
+ );
+
+ // Refresh the feed to show updated confirmation status
+ await this.updateAllFeed();
+ } else {
+ logger.error("Error submitting confirmation:", result);
+ this.$notify(
+ {
+ group: "alert",
+ type: "danger",
+ title: "Error",
+ text: "There was a problem submitting the confirmation.",
+ },
+ 5000,
+ );
+ }
+ },
+ },
+ -1,
+ );
+ }
}