forked from trent_larson/crowd-funder-for-time-pwa
feat: add starred project list in search, refactor variable names
This commit is contained in:
@@ -125,10 +125,10 @@ const MIGRATIONS = [
|
|||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "003_add_starredProjectIds_to_settings",
|
name: "005_add_starredPlanHandleIds_to_settings",
|
||||||
sql: `
|
sql: `
|
||||||
ALTER TABLE settings ADD COLUMN starredProjectIds TEXT;
|
ALTER TABLE settings ADD COLUMN starredPlanHandleIds TEXT DEFAULT '[]'; -- JSON string
|
||||||
ALTER TABLE settings ADD COLUMN lastAckedStarredProjectChangesJwtId TEXT;
|
ALTER TABLE settings ADD COLUMN lastAckedStarredPlanChangesJwtId TEXT;
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -158,7 +158,10 @@ export async function retrieveSettingsForDefaultAccount(): Promise<Settings> {
|
|||||||
result.values,
|
result.values,
|
||||||
)[0] as Settings;
|
)[0] as Settings;
|
||||||
settings.searchBoxes = parseJsonField(settings.searchBoxes, []);
|
settings.searchBoxes = parseJsonField(settings.searchBoxes, []);
|
||||||
settings.starredProjectIds = parseJsonField(settings.starredProjectIds, []);
|
settings.starredPlanHandleIds = parseJsonField(
|
||||||
|
settings.starredPlanHandleIds,
|
||||||
|
[],
|
||||||
|
);
|
||||||
return settings;
|
return settings;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -225,8 +228,8 @@ export async function retrieveSettingsForActiveAccount(): Promise<Settings> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
settings.searchBoxes = parseJsonField(settings.searchBoxes, []);
|
settings.searchBoxes = parseJsonField(settings.searchBoxes, []);
|
||||||
settings.starredProjectIds = parseJsonField(
|
settings.starredPlanHandleIds = parseJsonField(
|
||||||
settings.starredProjectIds,
|
settings.starredPlanHandleIds,
|
||||||
[],
|
[],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ export type Settings = {
|
|||||||
|
|
||||||
lastAckedOfferToUserJwtId?: string; // the last JWT ID for offer-to-user that they've acknowledged seeing
|
lastAckedOfferToUserJwtId?: string; // the last JWT ID for offer-to-user that they've acknowledged seeing
|
||||||
lastAckedOfferToUserProjectsJwtId?: string; // the last JWT ID for offers-to-user's-projects that they've acknowledged seeing
|
lastAckedOfferToUserProjectsJwtId?: string; // the last JWT ID for offers-to-user's-projects that they've acknowledged seeing
|
||||||
lastAckedStarredProjectChangesJwtId?: string; // the last JWT ID for starred project changes that they've acknowledged seeing
|
lastAckedStarredPlanChangesJwtId?: string; // the last JWT ID for starred plan changes that they've acknowledged seeing
|
||||||
|
|
||||||
// The claim list has a most recent one used in notifications that's separate from the last viewed
|
// The claim list has a most recent one used in notifications that's separate from the last viewed
|
||||||
lastNotifiedClaimId?: string;
|
lastNotifiedClaimId?: string;
|
||||||
@@ -62,19 +62,17 @@ export type Settings = {
|
|||||||
showGeneralAdvanced?: boolean; // Show advanced features which don't have their own flag
|
showGeneralAdvanced?: boolean; // Show advanced features which don't have their own flag
|
||||||
showShortcutBvc?: boolean; // Show shortcut for Bountiful Voluntaryist Community actions
|
showShortcutBvc?: boolean; // Show shortcut for Bountiful Voluntaryist Community actions
|
||||||
|
|
||||||
// List of starred project handleIds
|
starredPlanHandleIds?: string[]; // Array of starred plan handle IDs
|
||||||
starredProjectIds?: Array<string>;
|
|
||||||
|
|
||||||
vapid?: string; // VAPID (Voluntary Application Server Identification) field for web push
|
vapid?: string; // VAPID (Voluntary Application Server Identification) field for web push
|
||||||
warnIfProdServer?: boolean; // Warn if using a production server
|
warnIfProdServer?: boolean; // Warn if using a production server
|
||||||
warnIfTestServer?: boolean; // Warn if using a testing server
|
warnIfTestServer?: boolean; // Warn if using a testing server
|
||||||
webPushServer?: string; // Web Push server URL
|
webPushServer?: string; // Web Push server URL
|
||||||
};
|
};
|
||||||
|
|
||||||
// type of settings where the searchBoxes are JSON strings instead of objects
|
// type of settings where the values are JSON strings instead of objects
|
||||||
export type SettingsWithJsonStrings = Settings & {
|
export type SettingsWithJsonStrings = Settings & {
|
||||||
searchBoxes: string;
|
searchBoxes: string;
|
||||||
starredProjectIds: string;
|
starredPlanHandleIds: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function checkIsAnyFeedFilterOn(settings: Settings): boolean {
|
export function checkIsAnyFeedFilterOn(settings: Settings): boolean {
|
||||||
@@ -91,6 +89,11 @@ export const SettingsSchema = {
|
|||||||
/**
|
/**
|
||||||
* Constants.
|
* Constants.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is deprecated.
|
||||||
|
* It only remains for those with a PWA who have not migrated, but we'll soon remove it.
|
||||||
|
*/
|
||||||
export const MASTER_SETTINGS_KEY = "1";
|
export const MASTER_SETTINGS_KEY = "1";
|
||||||
|
|
||||||
export const DEFAULT_PASSKEY_EXPIRATION_MINUTES = 15;
|
export const DEFAULT_PASSKEY_EXPIRATION_MINUTES = 15;
|
||||||
|
|||||||
@@ -93,7 +93,10 @@ export interface PlanData {
|
|||||||
name: string;
|
name: string;
|
||||||
/**
|
/**
|
||||||
* The identifier of the project record -- different from jwtId
|
* The identifier of the project record -- different from jwtId
|
||||||
* (Maybe we should use the jwtId to iterate through the records instead.)
|
*
|
||||||
|
* This has been used to iterate through plan records, because jwtId ordering doesn't match
|
||||||
|
* chronological create ordering, though it does match most recent edit order (in reverse order).
|
||||||
|
* (It may be worthwhile to order by jwtId instead. It is an indexed field.)
|
||||||
**/
|
**/
|
||||||
rowId?: string;
|
rowId?: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -793,18 +793,18 @@ export async function getNewOffersToUserProjects(
|
|||||||
* @param axios - axios instance
|
* @param axios - axios instance
|
||||||
* @param apiServer - endorser API server URL
|
* @param apiServer - endorser API server URL
|
||||||
* @param activeDid - user's DID for authentication
|
* @param activeDid - user's DID for authentication
|
||||||
* @param starredProjectIds - array of starred project handle IDs
|
* @param starredPlanHandleIds - array of starred project handle IDs
|
||||||
* @param afterId - JWT ID to check for changes after (from lastAckedStarredProjectChangesJwtId)
|
* @param afterId - JWT ID to check for changes after (from lastAckedStarredPlanChangesJwtId)
|
||||||
* @returns { data: Array<PlanSummaryAndPreviousClaim>, hitLimit: boolean }
|
* @returns { data: Array<PlanSummaryAndPreviousClaim>, hitLimit: boolean }
|
||||||
*/
|
*/
|
||||||
export async function getStarredProjectsWithChanges(
|
export async function getStarredProjectsWithChanges(
|
||||||
axios: Axios,
|
axios: Axios,
|
||||||
apiServer: string,
|
apiServer: string,
|
||||||
activeDid: string,
|
activeDid: string,
|
||||||
starredProjectIds: string[],
|
starredPlanHandleIds: string[],
|
||||||
afterId?: string,
|
afterId?: string,
|
||||||
): Promise<{ data: Array<PlanSummaryAndPreviousClaim>; hitLimit: boolean }> {
|
): Promise<{ data: Array<PlanSummaryAndPreviousClaim>; hitLimit: boolean }> {
|
||||||
if (!starredProjectIds || starredProjectIds.length === 0) {
|
if (!starredPlanHandleIds || starredPlanHandleIds.length === 0) {
|
||||||
return { data: [], hitLimit: false };
|
return { data: [], hitLimit: false };
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -817,7 +817,7 @@ export async function getStarredProjectsWithChanges(
|
|||||||
const headers = await getHeaders(activeDid);
|
const headers = await getHeaders(activeDid);
|
||||||
|
|
||||||
const requestBody = {
|
const requestBody = {
|
||||||
planIds: starredProjectIds,
|
planIds: starredPlanHandleIds,
|
||||||
afterId: afterId,
|
afterId: afterId,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -85,7 +85,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Component, Vue } from "vue-facing-decorator";
|
import { Component, Vue } from "vue-facing-decorator";
|
||||||
import { PlatformServiceMixin } from "@/utils/PlatformServiceMixin";
|
import { PlatformServiceMixin } from "@/utils/PlatformServiceMixin";
|
||||||
import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
mixins: [PlatformServiceMixin],
|
mixins: [PlatformServiceMixin],
|
||||||
@@ -197,10 +196,10 @@ This tests the helper method only - no database interaction`;
|
|||||||
const success = await this.$saveSettings(testSettings);
|
const success = await this.$saveSettings(testSettings);
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
// Now query the raw database to see how it's actually stored
|
// Now query the raw database to see how it's actually stored.
|
||||||
|
// Note that new users probably have settings with ID of 1 but old migrated users might skip to 2.
|
||||||
const rawResult = await this.$dbQuery(
|
const rawResult = await this.$dbQuery(
|
||||||
"SELECT searchBoxes FROM settings WHERE id = ?",
|
"SELECT searchBoxes FROM settings limit 1",
|
||||||
[MASTER_SETTINGS_KEY],
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (rawResult?.values?.length) {
|
if (rawResult?.values?.length) {
|
||||||
|
|||||||
@@ -249,13 +249,13 @@ export const PlatformServiceMixin = {
|
|||||||
// Keep null values as null
|
// Keep null values as null
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle JSON fields like contactMethods
|
// Convert SQLite JSON strings to objects/arrays
|
||||||
if (column === "contactMethods" && typeof value === "string") {
|
if (
|
||||||
try {
|
column === "contactMethods" ||
|
||||||
value = JSON.parse(value);
|
column === "searchBoxes" ||
|
||||||
} catch {
|
column === "starredPlanHandleIds"
|
||||||
value = [];
|
) {
|
||||||
}
|
value = this._parseJsonField(value, []);
|
||||||
}
|
}
|
||||||
|
|
||||||
obj[column] = value;
|
obj[column] = value;
|
||||||
|
|||||||
@@ -56,16 +56,26 @@
|
|||||||
href="#"
|
href="#"
|
||||||
:class="computedStarredTabStyleClassNames()"
|
:class="computedStarredTabStyleClassNames()"
|
||||||
@click="
|
@click="
|
||||||
|
projects = [];
|
||||||
|
userProfiles = [];
|
||||||
|
isStarredActive = true;
|
||||||
isLocalActive = false;
|
isLocalActive = false;
|
||||||
isMappedActive = false;
|
isMappedActive = false;
|
||||||
isAnywhereActive = false;
|
isAnywhereActive = false;
|
||||||
isStarredActive = true;
|
|
||||||
isSearchVisible = false;
|
isSearchVisible = false;
|
||||||
tempSearchBox = null;
|
tempSearchBox = null;
|
||||||
loadStarred();
|
searchStarred();
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
Starred
|
Starred
|
||||||
|
<!-- restore when the links don't jump around for different numbers
|
||||||
|
<span
|
||||||
|
class="font-semibold text-sm bg-slate-200 px-1.5 py-0.5 rounded-md"
|
||||||
|
v-if="isLocalActive"
|
||||||
|
>
|
||||||
|
{{ localCount > -1 ? localCount : "?" }}
|
||||||
|
</span>
|
||||||
|
-->
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
@@ -75,6 +85,7 @@
|
|||||||
@click="
|
@click="
|
||||||
projects = [];
|
projects = [];
|
||||||
userProfiles = [];
|
userProfiles = [];
|
||||||
|
isStarredActive = false;
|
||||||
isLocalActive = true;
|
isLocalActive = true;
|
||||||
isMappedActive = false;
|
isMappedActive = false;
|
||||||
isAnywhereActive = false;
|
isAnywhereActive = false;
|
||||||
@@ -102,6 +113,7 @@
|
|||||||
@click="
|
@click="
|
||||||
projects = [];
|
projects = [];
|
||||||
userProfiles = [];
|
userProfiles = [];
|
||||||
|
isStarredActive = false;
|
||||||
isLocalActive = false;
|
isLocalActive = false;
|
||||||
isMappedActive = true;
|
isMappedActive = true;
|
||||||
isAnywhereActive = false;
|
isAnywhereActive = false;
|
||||||
@@ -122,6 +134,7 @@
|
|||||||
@click="
|
@click="
|
||||||
projects = [];
|
projects = [];
|
||||||
userProfiles = [];
|
userProfiles = [];
|
||||||
|
isStarredActive = false;
|
||||||
isLocalActive = false;
|
isLocalActive = false;
|
||||||
isMappedActive = false;
|
isMappedActive = false;
|
||||||
isAnywhereActive = true;
|
isAnywhereActive = true;
|
||||||
@@ -222,7 +235,9 @@
|
|||||||
that search.</span
|
that search.</span
|
||||||
>
|
>
|
||||||
<span v-else-if="isStarredActive">
|
<span v-else-if="isStarredActive">
|
||||||
<p>You have no starred projects. Star some projects to see them here.</p>
|
<p>
|
||||||
|
You have no starred projects. Star some projects to see them here.
|
||||||
|
</p>
|
||||||
<p class="mt-4">
|
<p class="mt-4">
|
||||||
When you star projects, you will get a notice on the front page when
|
When you star projects, you will get a notice on the front page when
|
||||||
they change.
|
they change.
|
||||||
@@ -360,10 +375,8 @@ import {
|
|||||||
didInfo,
|
didInfo,
|
||||||
errorStringForLog,
|
errorStringForLog,
|
||||||
getHeaders,
|
getHeaders,
|
||||||
getPlanFromCache,
|
|
||||||
} from "../libs/endorserServer";
|
} 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";
|
||||||
@@ -416,10 +429,12 @@ export default class DiscoverView extends Vue {
|
|||||||
allMyDids: Array<string> = [];
|
allMyDids: Array<string> = [];
|
||||||
apiServer = "";
|
apiServer = "";
|
||||||
isLoading = false;
|
isLoading = false;
|
||||||
|
|
||||||
isLocalActive = false;
|
isLocalActive = false;
|
||||||
isMappedActive = false;
|
isMappedActive = false;
|
||||||
isAnywhereActive = true;
|
isAnywhereActive = true;
|
||||||
isStarredActive = false;
|
isStarredActive = false;
|
||||||
|
|
||||||
isProjectsActive = true;
|
isProjectsActive = true;
|
||||||
isPeopleActive = false;
|
isPeopleActive = false;
|
||||||
isSearchVisible = true;
|
isSearchVisible = true;
|
||||||
@@ -505,7 +520,7 @@ export default class DiscoverView extends Vue {
|
|||||||
};
|
};
|
||||||
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) {
|
} else if (this.isStarredActive) {
|
||||||
await this.loadStarred();
|
await this.searchStarred();
|
||||||
} else {
|
} else {
|
||||||
await this.searchAll();
|
await this.searchAll();
|
||||||
}
|
}
|
||||||
@@ -576,7 +591,7 @@ export default class DiscoverView extends Vue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async loadStarred() {
|
public async searchStarred() {
|
||||||
this.resetCounts();
|
this.resetCounts();
|
||||||
|
|
||||||
// Clear any previous results
|
// Clear any previous results
|
||||||
@@ -588,52 +603,37 @@ export default class DiscoverView extends Vue {
|
|||||||
|
|
||||||
// Get starred project IDs from settings
|
// Get starred project IDs from settings
|
||||||
const settings = await this.$accountSettings();
|
const settings = await this.$accountSettings();
|
||||||
const starredIds: string[] = parseJsonField(
|
|
||||||
settings.starredProjectIds,
|
|
||||||
[],
|
|
||||||
);
|
|
||||||
|
|
||||||
|
const starredIds = settings.starredPlanHandleIds || [];
|
||||||
if (starredIds.length === 0) {
|
if (starredIds.length === 0) {
|
||||||
// No starred projects
|
// No starred projects
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load each starred project using getPlanFromCache
|
// This could be optimized to only pull those not already in the cache (endorserServer.ts)
|
||||||
const projectPromises = starredIds.map(async (handleId) => {
|
|
||||||
try {
|
const planHandleIdsJson = JSON.stringify(starredIds);
|
||||||
const project = await getPlanFromCache(
|
const endpoint =
|
||||||
handleId,
|
this.apiServer +
|
||||||
this.axios,
|
"/api/v2/report/plans?planHandleIds=" +
|
||||||
this.apiServer,
|
encodeURIComponent(planHandleIdsJson);
|
||||||
this.activeDid,
|
const response = await this.axios.get(endpoint, {
|
||||||
);
|
headers: await getHeaders(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;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
if (response.status !== 200) {
|
||||||
|
this.notify.error("Failed to load starred projects", TIMEOUTS.SHORT);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const starredPlans: PlanData[] = response.data.data;
|
||||||
|
if (response.data.hitLimit) {
|
||||||
|
// someday we'll have to let them incrementally load the rest
|
||||||
|
this.notify.warning(
|
||||||
|
"Beware: you have so many starred projects that we cannot load them all.",
|
||||||
|
TIMEOUTS.SHORT,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const projects = await Promise.all(projectPromises);
|
this.projects = starredPlans;
|
||||||
|
|
||||||
// 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) {
|
} catch (error: unknown) {
|
||||||
logger.error("Error loading starred projects:", error);
|
logger.error("Error loading starred projects:", error);
|
||||||
this.notify.error(
|
this.notify.error(
|
||||||
@@ -738,6 +738,8 @@ export default class DiscoverView extends Vue {
|
|||||||
const latestProject = this.projects[this.projects.length - 1];
|
const latestProject = this.projects[this.projects.length - 1];
|
||||||
if (this.isLocalActive || this.isMappedActive) {
|
if (this.isLocalActive || this.isMappedActive) {
|
||||||
this.searchLocal(latestProject.rowId);
|
this.searchLocal(latestProject.rowId);
|
||||||
|
} else if (this.isStarredActive) {
|
||||||
|
this.searchStarred();
|
||||||
} else if (this.isAnywhereActive) {
|
} else if (this.isAnywhereActive) {
|
||||||
this.searchAll(latestProject.rowId);
|
this.searchAll(latestProject.rowId);
|
||||||
}
|
}
|
||||||
@@ -881,6 +883,24 @@ export default class DiscoverView extends Vue {
|
|||||||
this.$router.push(route);
|
this.$router.push(route);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 computedLocalTabStyleClassNames() {
|
public computedLocalTabStyleClassNames() {
|
||||||
return {
|
return {
|
||||||
"inline-block": true,
|
"inline-block": true,
|
||||||
@@ -935,24 +955,6 @@ 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,
|
||||||
|
|||||||
@@ -413,14 +413,14 @@ export default class HomeView extends Vue {
|
|||||||
isRegistered = false;
|
isRegistered = false;
|
||||||
lastAckedOfferToUserJwtId?: string; // the last JWT ID for offer-to-user that they've acknowledged seeing
|
lastAckedOfferToUserJwtId?: string; // the last JWT ID for offer-to-user that they've acknowledged seeing
|
||||||
lastAckedOfferToUserProjectsJwtId?: string; // the last JWT ID for offers-to-user's-projects that they've acknowledged seeing
|
lastAckedOfferToUserProjectsJwtId?: string; // the last JWT ID for offers-to-user's-projects that they've acknowledged seeing
|
||||||
lastAckedStarredProjectChangesJwtId?: string; // the last JWT ID for starred project changes that they've acknowledged seeing
|
lastAckedStarredPlanChangesJwtId?: string; // the last JWT ID for starred project changes that they've acknowledged seeing
|
||||||
newOffersToUserHitLimit: boolean = false;
|
newOffersToUserHitLimit: boolean = false;
|
||||||
newOffersToUserProjectsHitLimit: boolean = false;
|
newOffersToUserProjectsHitLimit: boolean = false;
|
||||||
newStarredProjectChangesHitLimit: boolean = false;
|
newStarredProjectChangesHitLimit: boolean = false;
|
||||||
numNewOffersToUser: number = 0; // number of new offers-to-user
|
numNewOffersToUser: number = 0; // number of new offers-to-user
|
||||||
numNewOffersToUserProjects: number = 0; // number of new offers-to-user's-projects
|
numNewOffersToUserProjects: number = 0; // number of new offers-to-user's-projects
|
||||||
numNewStarredProjectChanges: number = 0; // number of new starred project changes
|
numNewStarredProjectChanges: number = 0; // number of new starred project changes
|
||||||
starredProjectIds: Array<string> = []; // list of starred project IDs
|
starredPlanHandleIds: Array<string> = []; // list of starred project IDs
|
||||||
searchBoxes: Array<{
|
searchBoxes: Array<{
|
||||||
name: string;
|
name: string;
|
||||||
bbox: BoundingBox;
|
bbox: BoundingBox;
|
||||||
@@ -565,12 +565,12 @@ export default class HomeView extends Vue {
|
|||||||
this.lastAckedOfferToUserJwtId = settings.lastAckedOfferToUserJwtId;
|
this.lastAckedOfferToUserJwtId = settings.lastAckedOfferToUserJwtId;
|
||||||
this.lastAckedOfferToUserProjectsJwtId =
|
this.lastAckedOfferToUserProjectsJwtId =
|
||||||
settings.lastAckedOfferToUserProjectsJwtId;
|
settings.lastAckedOfferToUserProjectsJwtId;
|
||||||
this.lastAckedStarredProjectChangesJwtId =
|
this.lastAckedStarredPlanChangesJwtId =
|
||||||
settings.lastAckedStarredProjectChangesJwtId;
|
settings.lastAckedStarredPlanChangesJwtId;
|
||||||
this.searchBoxes = settings.searchBoxes || [];
|
this.searchBoxes = settings.searchBoxes || [];
|
||||||
this.showShortcutBvc = !!settings.showShortcutBvc;
|
this.showShortcutBvc = !!settings.showShortcutBvc;
|
||||||
this.starredProjectIds = databaseUtil.parseJsonField(
|
this.starredPlanHandleIds = databaseUtil.parseJsonField(
|
||||||
settings.starredProjectIds,
|
settings.starredPlanHandleIds,
|
||||||
[],
|
[],
|
||||||
);
|
);
|
||||||
this.isAnyFeedFilterOn = checkIsAnyFeedFilterOn(settings);
|
this.isAnyFeedFilterOn = checkIsAnyFeedFilterOn(settings);
|
||||||
@@ -715,14 +715,14 @@ export default class HomeView extends Vue {
|
|||||||
* @requires Active DID
|
* @requires Active DID
|
||||||
*/
|
*/
|
||||||
private async loadNewStarredProjectChanges() {
|
private async loadNewStarredProjectChanges() {
|
||||||
if (this.activeDid && this.starredProjectIds.length > 0) {
|
if (this.activeDid && this.starredPlanHandleIds.length > 0) {
|
||||||
try {
|
try {
|
||||||
const starredProjectChanges = await getStarredProjectsWithChanges(
|
const starredProjectChanges = await getStarredProjectsWithChanges(
|
||||||
this.axios,
|
this.axios,
|
||||||
this.apiServer,
|
this.apiServer,
|
||||||
this.activeDid,
|
this.activeDid,
|
||||||
this.starredProjectIds,
|
this.starredPlanHandleIds,
|
||||||
this.lastAckedStarredProjectChangesJwtId,
|
this.lastAckedStarredPlanChangesJwtId,
|
||||||
);
|
);
|
||||||
this.numNewStarredProjectChanges = starredProjectChanges.data.length;
|
this.numNewStarredProjectChanges = starredProjectChanges.data.length;
|
||||||
this.newStarredProjectChangesHitLimit = starredProjectChanges.hitLimit;
|
this.newStarredProjectChangesHitLimit = starredProjectChanges.hitLimit;
|
||||||
|
|||||||
@@ -338,14 +338,14 @@ export default class NewActivityView extends Vue {
|
|||||||
apiServer = "";
|
apiServer = "";
|
||||||
lastAckedOfferToUserJwtId = "";
|
lastAckedOfferToUserJwtId = "";
|
||||||
lastAckedOfferToUserProjectsJwtId = "";
|
lastAckedOfferToUserProjectsJwtId = "";
|
||||||
lastAckedStarredProjectChangesJwtId = "";
|
lastAckedStarredPlanChangesJwtId = "";
|
||||||
newOffersToUser: Array<OfferSummaryRecord> = [];
|
newOffersToUser: Array<OfferSummaryRecord> = [];
|
||||||
newOffersToUserHitLimit = false;
|
newOffersToUserHitLimit = false;
|
||||||
newOffersToUserProjects: Array<OfferToPlanSummaryRecord> = [];
|
newOffersToUserProjects: Array<OfferToPlanSummaryRecord> = [];
|
||||||
newOffersToUserProjectsHitLimit = false;
|
newOffersToUserProjectsHitLimit = false;
|
||||||
newStarredProjectChanges: Array<PlanSummaryAndPreviousClaim> = [];
|
newStarredProjectChanges: Array<PlanSummaryAndPreviousClaim> = [];
|
||||||
newStarredProjectChangesHitLimit = false;
|
newStarredProjectChangesHitLimit = false;
|
||||||
starredProjectIds: Array<string> = [];
|
starredPlanHandleIds: Array<string> = [];
|
||||||
planDifferences: Record<
|
planDifferences: Record<
|
||||||
string,
|
string,
|
||||||
Record<string, { old: unknown; new: unknown }>
|
Record<string, { old: unknown; new: unknown }>
|
||||||
@@ -367,10 +367,10 @@ export default class NewActivityView extends Vue {
|
|||||||
this.lastAckedOfferToUserJwtId = settings.lastAckedOfferToUserJwtId || "";
|
this.lastAckedOfferToUserJwtId = settings.lastAckedOfferToUserJwtId || "";
|
||||||
this.lastAckedOfferToUserProjectsJwtId =
|
this.lastAckedOfferToUserProjectsJwtId =
|
||||||
settings.lastAckedOfferToUserProjectsJwtId || "";
|
settings.lastAckedOfferToUserProjectsJwtId || "";
|
||||||
this.lastAckedStarredProjectChangesJwtId =
|
this.lastAckedStarredPlanChangesJwtId =
|
||||||
settings.lastAckedStarredProjectChangesJwtId || "";
|
settings.lastAckedStarredPlanChangesJwtId || "";
|
||||||
this.starredProjectIds = databaseUtil.parseJsonField(
|
this.starredPlanHandleIds = databaseUtil.parseJsonField(
|
||||||
settings.starredProjectIds,
|
settings.starredPlanHandleIds,
|
||||||
[],
|
[],
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -397,14 +397,14 @@ export default class NewActivityView extends Vue {
|
|||||||
this.newOffersToUserProjectsHitLimit = offersToUserProjectsData.hitLimit;
|
this.newOffersToUserProjectsHitLimit = offersToUserProjectsData.hitLimit;
|
||||||
|
|
||||||
// Load starred project changes if user has starred projects
|
// Load starred project changes if user has starred projects
|
||||||
if (this.starredProjectIds.length > 0) {
|
if (this.starredPlanHandleIds.length > 0) {
|
||||||
try {
|
try {
|
||||||
const starredProjectChangesData = await getStarredProjectsWithChanges(
|
const starredProjectChangesData = await getStarredProjectsWithChanges(
|
||||||
this.axios,
|
this.axios,
|
||||||
this.apiServer,
|
this.apiServer,
|
||||||
this.activeDid,
|
this.activeDid,
|
||||||
this.starredProjectIds,
|
this.starredPlanHandleIds,
|
||||||
this.lastAckedStarredProjectChangesJwtId,
|
this.lastAckedStarredPlanChangesJwtId,
|
||||||
);
|
);
|
||||||
this.newStarredProjectChanges = starredProjectChangesData.data;
|
this.newStarredProjectChanges = starredProjectChangesData.data;
|
||||||
this.newStarredProjectChangesHitLimit =
|
this.newStarredProjectChangesHitLimit =
|
||||||
@@ -513,7 +513,7 @@ export default class NewActivityView extends Vue {
|
|||||||
this.newStarredProjectChanges.length > 0
|
this.newStarredProjectChanges.length > 0
|
||||||
) {
|
) {
|
||||||
await this.$saveUserSettings(this.activeDid, {
|
await this.$saveUserSettings(this.activeDid, {
|
||||||
lastAckedStarredProjectChangesJwtId:
|
lastAckedStarredPlanChangesJwtId:
|
||||||
this.newStarredProjectChanges[0].plan.jwtId,
|
this.newStarredProjectChanges[0].plan.jwtId,
|
||||||
});
|
});
|
||||||
this.notify.info(
|
this.notify.info(
|
||||||
@@ -530,14 +530,14 @@ export default class NewActivityView extends Vue {
|
|||||||
if (index !== -1 && index < this.newStarredProjectChanges.length - 1) {
|
if (index !== -1 && index < this.newStarredProjectChanges.length - 1) {
|
||||||
// Set to the next change's jwtId
|
// Set to the next change's jwtId
|
||||||
await this.$saveUserSettings(this.activeDid, {
|
await this.$saveUserSettings(this.activeDid, {
|
||||||
lastAckedStarredProjectChangesJwtId:
|
lastAckedStarredPlanChangesJwtId:
|
||||||
this.newStarredProjectChanges[index + 1].plan.jwtId,
|
this.newStarredProjectChanges[index + 1].plan.jwtId,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// it's the last entry (or not found), so just keep it the same
|
// it's the last entry (or not found), so just keep it the same
|
||||||
await this.$saveUserSettings(this.activeDid, {
|
await this.$saveUserSettings(this.activeDid, {
|
||||||
lastAckedStarredProjectChangesJwtId:
|
lastAckedStarredPlanChangesJwtId:
|
||||||
this.lastAckedStarredProjectChangesJwtId,
|
this.lastAckedStarredPlanChangesJwtId,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
this.notify.info(
|
this.notify.info(
|
||||||
|
|||||||
@@ -27,12 +27,6 @@
|
|||||||
>
|
>
|
||||||
<font-awesome icon="pen" class="text-sm text-blue-500 ml-2 mb-1" />
|
<font-awesome icon="pen" class="text-sm text-blue-500 ml-2 mb-1" />
|
||||||
</button>
|
</button>
|
||||||
<button title="Copy Link to Project" @click="onCopyLinkClick()">
|
|
||||||
<font-awesome
|
|
||||||
icon="link"
|
|
||||||
class="text-sm text-slate-500 ml-2 mb-1"
|
|
||||||
/>
|
|
||||||
</button>
|
|
||||||
<button
|
<button
|
||||||
:title="
|
:title="
|
||||||
isStarred
|
isStarred
|
||||||
@@ -830,11 +824,8 @@ export default class ProjectViewView extends Vue {
|
|||||||
this.loadTotals();
|
this.loadTotals();
|
||||||
|
|
||||||
// Check if this project is starred when settings are loaded
|
// Check if this project is starred when settings are loaded
|
||||||
if (this.projectId && settings.starredProjectIds) {
|
if (this.projectId && settings.starredPlanHandleIds) {
|
||||||
const starredIds: string[] = databaseUtil.parseJsonField(
|
const starredIds = settings.starredPlanHandleIds || [];
|
||||||
settings.starredProjectIds,
|
|
||||||
[],
|
|
||||||
);
|
|
||||||
this.isStarred = starredIds.includes(this.projectId);
|
this.isStarred = starredIds.includes(this.projectId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1513,10 +1504,7 @@ export default class ProjectViewView extends Vue {
|
|||||||
if (!this.isStarred) {
|
if (!this.isStarred) {
|
||||||
// Add to starred projects
|
// Add to starred projects
|
||||||
const settings = await databaseUtil.retrieveSettingsForActiveAccount();
|
const settings = await databaseUtil.retrieveSettingsForActiveAccount();
|
||||||
const starredIds: string[] = databaseUtil.parseJsonField(
|
const starredIds = settings.starredPlanHandleIds || [];
|
||||||
settings.starredProjectIds,
|
|
||||||
[],
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!starredIds.includes(this.projectId)) {
|
if (!starredIds.includes(this.projectId)) {
|
||||||
const newStarredIds = [...starredIds, this.projectId];
|
const newStarredIds = [...starredIds, this.projectId];
|
||||||
@@ -1524,43 +1512,42 @@ export default class ProjectViewView extends Vue {
|
|||||||
const result = await databaseUtil.updateDidSpecificSettings(
|
const result = await databaseUtil.updateDidSpecificSettings(
|
||||||
this.activeDid,
|
this.activeDid,
|
||||||
// @ts-expect-error until we use SettingsWithJsonString properly
|
// @ts-expect-error until we use SettingsWithJsonString properly
|
||||||
{ starredProjectIds: newIdsParam },
|
{ starredPlanHandleIds: newIdsParam },
|
||||||
);
|
);
|
||||||
if (!result) {
|
if (result) {
|
||||||
|
this.isStarred = true;
|
||||||
|
} else {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.log(
|
console.log(
|
||||||
"Still getting a bad result from SQL update to star a project.",
|
"Still getting a bad result from SQL update to star a project.",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!settings.lastAckedStarredProjectChangesJwtId) {
|
if (!settings.lastAckedStarredPlanChangesJwtId) {
|
||||||
await databaseUtil.updateDidSpecificSettings(this.activeDid, {
|
await databaseUtil.updateDidSpecificSettings(this.activeDid, {
|
||||||
lastAckedStarredProjectChangesJwtId: settings.lastViewedClaimId,
|
lastAckedStarredPlanChangesJwtId: settings.lastViewedClaimId,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
this.isStarred = true;
|
|
||||||
} else {
|
} else {
|
||||||
// Remove from starred projects
|
// Remove from starred projects
|
||||||
const settings = await databaseUtil.retrieveSettingsForActiveAccount();
|
const settings = await databaseUtil.retrieveSettingsForActiveAccount();
|
||||||
const starredIds: string[] = databaseUtil.parseJsonField(
|
const starredIds = settings.starredPlanHandleIds || [];
|
||||||
settings.starredProjectIds,
|
|
||||||
[],
|
|
||||||
);
|
|
||||||
|
|
||||||
const updatedIds = starredIds.filter((id) => id !== this.projectId);
|
const updatedIds = starredIds.filter((id) => id !== this.projectId);
|
||||||
const newIdsParam = JSON.stringify(updatedIds);
|
const newIdsParam = JSON.stringify(updatedIds);
|
||||||
const result = await databaseUtil.updateDidSpecificSettings(
|
const result = await databaseUtil.updateDidSpecificSettings(
|
||||||
this.activeDid,
|
this.activeDid,
|
||||||
// @ts-expect-error until we use SettingsWithJsonString properly
|
// @ts-expect-error until we use SettingsWithJsonString properly
|
||||||
{ starredProjectIds: newIdsParam },
|
{ starredPlanHandleIds: newIdsParam },
|
||||||
);
|
);
|
||||||
if (!result) {
|
if (result) {
|
||||||
|
this.isStarred = false;
|
||||||
|
} else {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.log(
|
logger.error(
|
||||||
"Still getting a bad result from SQL update to unstar a project.",
|
"Got a bad result from SQL update to unstar a project.",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
this.isStarred = false;
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error("Error toggling star status:", error);
|
logger.error("Error toggling star status:", error);
|
||||||
|
|||||||
Reference in New Issue
Block a user