From 3ecae0be0f127f19b91a46888edd56d7490579cf Mon Sep 17 00:00:00 2001 From: Jose Olarte III Date: Thu, 13 Nov 2025 19:21:22 +0800 Subject: [PATCH] refactor(OnboardMeetingSetupView): fix selected project display after refresh Refactor selectedProject computation to use separate storage instead of relying on allProjects array. This fixes a bug where the selected project wouldn't display after page refresh if it wasn't in the initial allProjects batch. Changes: - Add selectedProjectData property to store selected project independently - Simplify selectedProject computed to return selectedProjectData directly - Add fetchProjectByHandleId() to fetch single project by handleId - Add ensureSelectedProjectLoaded() to check allProjects first, then fetch - Update handleProjectLinkAssigned() to store directly in selectedProjectData - Remove band-aid solution of adding selected projects to allProjects array - Update startEditing() and cancelEditing() to ensure selected project loads - Call ensureSelectedProjectLoaded() in created() lifecycle hook This ensures the selected project always displays correctly, even when: - Selected from search results (not in allProjects) - Page is refreshed (allProjects reloads without selected project) - Project is in a later pagination batch --- src/views/OnboardMeetingSetupView.vue | 93 +++++++++++++++++++++++---- 1 file changed, 82 insertions(+), 11 deletions(-) diff --git a/src/views/OnboardMeetingSetupView.vue b/src/views/OnboardMeetingSetupView.vue index 79f9c4db..ea2cf832 100644 --- a/src/views/OnboardMeetingSetupView.vue +++ b/src/views/OnboardMeetingSetupView.vue @@ -421,6 +421,7 @@ export default class OnboardMeetingView extends Vue { allProjects: PlanData[] = []; allContacts: Contact[] = []; allMyDids: string[] = []; + selectedProjectData: PlanData | null = null; get minDateTime() { const now = new Date(); now.setMinutes(now.getMinutes() + 5); // Set minimum 5 minutes in the future @@ -447,6 +448,10 @@ export default class OnboardMeetingView extends Vue { await this.loadProjects(); await this.fetchCurrentMeeting(); + + // Ensure selected project is loaded if projectLink exists + await this.ensureSelectedProjectLoaded(); + this.isLoading = false; } @@ -518,6 +523,65 @@ export default class OnboardMeetingView extends Vue { } } + /** + * Ensure the selected project is loaded if projectLink exists + * Checks allProjects first, then fetches if not found + */ + async ensureSelectedProjectLoaded(): Promise { + const projectLink = + this.currentMeeting?.projectLink || + this.newOrUpdatedMeetingInputs?.projectLink; + + if (!projectLink) { + this.selectedProjectData = null; + return; + } + + // Check if already loaded in allProjects + const existingProject = this.allProjects.find( + (p) => p.handleId === projectLink, + ); + if (existingProject) { + this.selectedProjectData = existingProject; + return; + } + + // Not in allProjects, fetch it + await this.fetchProjectByHandleId(projectLink); + } + + /** + * Fetch a single project by handleId + * @param handleId - The project handleId to fetch + */ + async fetchProjectByHandleId(handleId: string): Promise { + try { + const headers = await getHeaders(this.activeDid); + const url = `${this.apiServer}/api/v2/report/plans?handleId=${encodeURIComponent(handleId)}`; + const resp = await this.axios.get(url, { headers }); + + if (resp.status === 200 && resp.data.data && resp.data.data.length > 0) { + const project = resp.data.data[0]; + this.selectedProjectData = { + name: project.name, + description: project.description, + image: project.image, + handleId: project.handleId, + issuerDid: project.issuerDid, + rowId: project.rowId, + }; + } else { + this.selectedProjectData = null; + } + } catch (error) { + this.$logAndConsole( + "Error fetching project by handleId: " + errorStringForLog(error), + true, + ); + this.selectedProjectData = null; + } + } + async createMeeting() { this.isLoading = true; @@ -652,7 +716,7 @@ export default class OnboardMeetingView extends Vue { } } - startEditing() { + async startEditing() { // Populate form with existing meeting data if (this.currentMeeting) { const localExpiresAt = new Date(this.currentMeeting.expiresAt); @@ -663,6 +727,10 @@ export default class OnboardMeetingView extends Vue { password: this.currentMeeting.password || "", projectLink: this.currentMeeting.projectLink || "", }; + // Ensure selected project is loaded if projectLink exists + if (this.currentMeeting.projectLink) { + await this.ensureSelectedProjectLoaded(); + } } else { this.$logError( "There is no current meeting to edit. We should never get here.", @@ -670,9 +738,15 @@ export default class OnboardMeetingView extends Vue { } } - cancelEditing() { + async cancelEditing() { // Reset form data this.newOrUpdatedMeetingInputs = null; + // Restore selected project from currentMeeting if it exists + if (this.currentMeeting?.projectLink) { + await this.ensureSelectedProjectLoaded(); + } else { + this.selectedProjectData = null; + } } async updateMeeting() { @@ -865,17 +939,10 @@ export default class OnboardMeetingView extends Vue { /** * Computed property for selected project - * Derives the project from projectLink by finding it in allProjects + * Returns the separately stored selected project data */ get selectedProject(): PlanData | null { - if (!this.newOrUpdatedMeetingInputs?.projectLink) { - return null; - } - return ( - this.allProjects.find( - (p) => p.handleId === this.newOrUpdatedMeetingInputs?.projectLink, - ) || null - ); + return this.selectedProjectData; } /** @@ -905,6 +972,9 @@ export default class OnboardMeetingView extends Vue { * Handle project assignment from dialog */ handleProjectLinkAssigned(project: PlanData): void { + // Store the selected project directly + this.selectedProjectData = project; + if (this.newOrUpdatedMeetingInputs) { this.newOrUpdatedMeetingInputs.projectLink = project.handleId; } @@ -914,6 +984,7 @@ export default class OnboardMeetingView extends Vue { * Unset the project link and revert to initial state */ unsetProjectLink(): void { + this.selectedProjectData = null; if (this.newOrUpdatedMeetingInputs) { this.newOrUpdatedMeetingInputs.projectLink = ""; }