diff --git a/src/views/DiscoverView.vue b/src/views/DiscoverView.vue index 2a8879e0..31ab4e51 100644 --- a/src/views/DiscoverView.vue +++ b/src/views/DiscoverView.vue @@ -51,6 +51,23 @@
@@ -329,8 +356,14 @@ import { import { Contact } from "../db/tables/contacts"; import { BoundingBox } from "../db/tables/settings"; import { PlanData } from "../interfaces"; -import { didInfo, errorStringForLog, getHeaders } from "../libs/endorserServer"; +import { + didInfo, + errorStringForLog, + getHeaders, + getPlanFromCache, +} from "../libs/endorserServer"; import { OnboardPage, retrieveAccountDids } from "../libs/util"; +import { parseJsonField } from "../db/databaseUtil"; import { logger } from "../utils/logger"; import { UserProfile } from "@/libs/partnerServer"; import { PlatformServiceMixin } from "@/utils/PlatformServiceMixin"; @@ -386,6 +419,7 @@ export default class DiscoverView extends Vue { isLocalActive = false; isMappedActive = false; isAnywhereActive = true; + isStarredActive = false; isProjectsActive = true; isPeopleActive = false; isSearchVisible = true; @@ -470,6 +504,8 @@ export default class DiscoverView extends Vue { leafletObject: L.Map; }; this.requestTiles(mapRef.leafletObject); // not ideal because I found this from experimentation, not documentation + } else if (this.isStarredActive) { + await this.loadStarred(); } else { await this.searchAll(); } @@ -540,6 +576,75 @@ export default class DiscoverView extends Vue { } } + public async loadStarred() { + this.resetCounts(); + + // Clear any previous results + this.projects = []; + this.userProfiles = []; + + try { + this.isLoading = true; + + // Get starred project IDs from settings + const settings = await this.$accountSettings(); + const starredIds: string[] = parseJsonField( + settings.starredProjectIds, + [], + ); + + if (starredIds.length === 0) { + // No starred projects + return; + } + + // Load each starred project using getPlanFromCache + const projectPromises = starredIds.map(async (handleId) => { + try { + const project = await getPlanFromCache( + handleId, + this.axios, + this.apiServer, + this.activeDid, + ); + if (project) { + // Convert PlanSummaryRecord to PlanData + return { + description: project.description, + handleId: project.handleId, + image: project.image, + issuerDid: project.issuerDid, + name: project.name || UNNAMED_PROJECT, + rowId: project.jwtId, + } as PlanData; + } + return null; + } catch (error) { + logger.warn(`Failed to load starred project ${handleId}:`, error); + return null; + } + }); + + const projects = await Promise.all(projectPromises); + + // Filter out null results and add to projects array + const validProjects = projects.filter( + (project): project is PlanData => + project !== null && project !== undefined, + ); + + this.projects = validProjects; + } catch (error: unknown) { + logger.error("Error loading starred projects:", error); + this.notify.error( + "Failed to load starred projects. Please try again.", + TIMEOUTS.LONG, + ); + } finally { + this.isLoading = false; + } + } + public async searchLocal(beforeId?: string) { this.resetCounts(); @@ -636,6 +741,7 @@ export default class DiscoverView extends Vue { } else if (this.isAnywhereActive) { this.searchAll(latestProject.rowId); } + // Note: Starred tab doesn't support pagination since we load all starred projects at once } else if (this.isPeopleActive && this.userProfiles.length > 0) { const latestProfile = this.userProfiles[this.userProfiles.length - 1]; if (this.isLocalActive || this.isMappedActive) { @@ -829,6 +935,24 @@ export default class DiscoverView extends Vue { }; } + public computedStarredTabStyleClassNames() { + return { + "inline-block": true, + "py-3": true, + "rounded-t-lg": true, + "border-b-2": true, + + active: this.isStarredActive, + "text-black": this.isStarredActive, + "border-black": this.isStarredActive, + "font-semibold": this.isStarredActive, + + "text-blue-600": !this.isStarredActive, + "border-transparent": !this.isStarredActive, + "hover:border-slate-400": !this.isStarredActive, + }; + } + public computedProjectsTabStyleClassNames() { return { "inline-block": true, diff --git a/src/views/ProjectViewView.vue b/src/views/ProjectViewView.vue index 73cdc7fa..afb483f5 100644 --- a/src/views/ProjectViewView.vue +++ b/src/views/ProjectViewView.vue @@ -912,7 +912,7 @@ export default class ProjectViewView extends Vue { ); this.issuerVisibleToDids = resp.data.issuerVisibleToDids || []; this.name = resp.data.claim?.name || "(no name)"; - this.description = resp.data.claim?.description || "(no description)"; + this.description = resp.data.claim?.description || ""; this.truncatedDesc = this.description.slice(0, this.truncateLength); this.latitude = resp.data.claim?.location?.geo?.latitude || 0; this.longitude = resp.data.claim?.location?.geo?.longitude || 0;