forked from trent_larson/crowd-funder-for-time-pwa
feat: add a page to see all the starred projects
This commit is contained in:
@@ -51,6 +51,23 @@
|
||||
<!-- Secondary Tabs -->
|
||||
<div class="text-center text-slate-500 border-b border-slate-300">
|
||||
<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>
|
||||
<a
|
||||
href="#"
|
||||
@@ -61,6 +78,7 @@
|
||||
isLocalActive = true;
|
||||
isMappedActive = false;
|
||||
isAnywhereActive = false;
|
||||
isStarredActive = false;
|
||||
isSearchVisible = true;
|
||||
tempSearchBox = null;
|
||||
searchLocal();
|
||||
@@ -87,6 +105,7 @@
|
||||
isLocalActive = false;
|
||||
isMappedActive = true;
|
||||
isAnywhereActive = false;
|
||||
isStarredActive = false;
|
||||
isSearchVisible = false;
|
||||
searchTerms = '';
|
||||
tempSearchBox = null;
|
||||
@@ -106,6 +125,7 @@
|
||||
isLocalActive = false;
|
||||
isMappedActive = false;
|
||||
isAnywhereActive = true;
|
||||
isStarredActive = false;
|
||||
isSearchVisible = true;
|
||||
tempSearchBox = null;
|
||||
searchAll();
|
||||
@@ -201,6 +221,13 @@
|
||||
>No {{ isProjectsActive ? "projects" : "people" }} were found with
|
||||
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>
|
||||
</div>
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user