Browse Source

feat: add a page to see all the starred projects

pull/193/head
Trent Larson 6 days ago
parent
commit
855448d07a
  1. 126
      src/views/DiscoverView.vue
  2. 2
      src/views/ProjectViewView.vue

126
src/views/DiscoverView.vue

@ -51,6 +51,23 @@
<!-- Secondary Tabs --> <!-- Secondary Tabs -->
<div class="text-center text-slate-500 border-b border-slate-300"> <div class="text-center text-slate-500 border-b border-slate-300">
<ul class="flex flex-wrap justify-center gap-4 -mb-px"> <ul class="flex flex-wrap justify-center gap-4 -mb-px">
<li v-if="isProjectsActive">
<a
href="#"
:class="computedStarredTabStyleClassNames()"
@click="
isLocalActive = false;
isMappedActive = false;
isAnywhereActive = false;
isStarredActive = true;
isSearchVisible = false;
tempSearchBox = null;
loadStarred();
"
>
Starred
</a>
</li>
<li> <li>
<a <a
href="#" href="#"
@ -61,6 +78,7 @@
isLocalActive = true; isLocalActive = true;
isMappedActive = false; isMappedActive = false;
isAnywhereActive = false; isAnywhereActive = false;
isStarredActive = false;
isSearchVisible = true; isSearchVisible = true;
tempSearchBox = null; tempSearchBox = null;
searchLocal(); searchLocal();
@ -87,6 +105,7 @@
isLocalActive = false; isLocalActive = false;
isMappedActive = true; isMappedActive = true;
isAnywhereActive = false; isAnywhereActive = false;
isStarredActive = false;
isSearchVisible = false; isSearchVisible = false;
searchTerms = ''; searchTerms = '';
tempSearchBox = null; tempSearchBox = null;
@ -106,6 +125,7 @@
isLocalActive = false; isLocalActive = false;
isMappedActive = false; isMappedActive = false;
isAnywhereActive = true; isAnywhereActive = true;
isStarredActive = false;
isSearchVisible = true; isSearchVisible = true;
tempSearchBox = null; tempSearchBox = null;
searchAll(); searchAll();
@ -201,6 +221,13 @@
>No {{ isProjectsActive ? "projects" : "people" }} were found with >No {{ isProjectsActive ? "projects" : "people" }} were found with
that search.</span that search.</span
> >
<span v-else-if="isStarredActive">
<p>You have no starred projects. Star some projects to see them here.</p>
<p class="mt-4">
When you star projects, you will get a notice on the front page when
they change.
</p>
</span>
</p> </p>
</div> </div>
@ -329,8 +356,14 @@ import {
import { Contact } from "../db/tables/contacts"; import { Contact } from "../db/tables/contacts";
import { BoundingBox } from "../db/tables/settings"; import { BoundingBox } from "../db/tables/settings";
import { PlanData } from "../interfaces"; 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 { OnboardPage, retrieveAccountDids } from "../libs/util";
import { parseJsonField } from "../db/databaseUtil";
import { logger } from "../utils/logger"; import { logger } from "../utils/logger";
import { UserProfile } from "@/libs/partnerServer"; import { UserProfile } from "@/libs/partnerServer";
import { PlatformServiceMixin } from "@/utils/PlatformServiceMixin"; import { PlatformServiceMixin } from "@/utils/PlatformServiceMixin";
@ -386,6 +419,7 @@ export default class DiscoverView extends Vue {
isLocalActive = false; isLocalActive = false;
isMappedActive = false; isMappedActive = false;
isAnywhereActive = true; isAnywhereActive = true;
isStarredActive = false;
isProjectsActive = true; isProjectsActive = true;
isPeopleActive = false; isPeopleActive = false;
isSearchVisible = true; isSearchVisible = true;
@ -470,6 +504,8 @@ export default class DiscoverView extends Vue {
leafletObject: L.Map; leafletObject: L.Map;
}; };
this.requestTiles(mapRef.leafletObject); // not ideal because I found this from experimentation, not documentation this.requestTiles(mapRef.leafletObject); // not ideal because I found this from experimentation, not documentation
} else if (this.isStarredActive) {
await this.loadStarred();
} else { } else {
await this.searchAll(); 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) { public async searchLocal(beforeId?: string) {
this.resetCounts(); this.resetCounts();
@ -636,6 +741,7 @@ export default class DiscoverView extends Vue {
} else if (this.isAnywhereActive) { } else if (this.isAnywhereActive) {
this.searchAll(latestProject.rowId); 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) { } else if (this.isPeopleActive && this.userProfiles.length > 0) {
const latestProfile = this.userProfiles[this.userProfiles.length - 1]; const latestProfile = this.userProfiles[this.userProfiles.length - 1];
if (this.isLocalActive || this.isMappedActive) { 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() { public computedProjectsTabStyleClassNames() {
return { return {
"inline-block": true, "inline-block": true,

2
src/views/ProjectViewView.vue

@ -912,7 +912,7 @@ export default class ProjectViewView extends Vue {
); );
this.issuerVisibleToDids = resp.data.issuerVisibleToDids || []; this.issuerVisibleToDids = resp.data.issuerVisibleToDids || [];
this.name = resp.data.claim?.name || "(no name)"; 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.truncatedDesc = this.description.slice(0, this.truncateLength);
this.latitude = resp.data.claim?.location?.geo?.latitude || 0; this.latitude = resp.data.claim?.location?.geo?.latitude || 0;
this.longitude = resp.data.claim?.location?.geo?.longitude || 0; this.longitude = resp.data.claim?.location?.geo?.longitude || 0;

Loading…
Cancel
Save