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 @@ + + + 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 @@
-
@@ -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, + ); + } }