diff --git a/src/components/EntityGrid.vue b/src/components/EntityGrid.vue
index b85e6d09..1a964d8c 100644
--- a/src/components/EntityGrid.vue
+++ b/src/components/EntityGrid.vue
@@ -76,7 +76,7 @@ projects, and special entities with selection. * * @author Matthew Raymer */
-
+
{{ emptyStateMessage }}
@@ -164,6 +164,10 @@ import { Contact } from "../db/tables/contacts";
import { PlanData } from "../interfaces/records";
import { NotificationIface } from "../constants/app";
import { UNNAMED_ENTITY_NAME } from "@/constants/entities";
+import { PlatformServiceMixin } from "@/utils/PlatformServiceMixin";
+import { getHeaders } from "../libs/endorserServer";
+import { logger } from "../utils/logger";
+import { TIMEOUTS } from "@/utils/notify";
/**
* Constants for infinite scroll configuration
@@ -191,6 +195,7 @@ const RECENT_CONTACTS_COUNT = 3;
ProjectCard,
SpecialEntityCard,
},
+ mixins: [PlatformServiceMixin],
})
export default class EntityGrid extends Vue {
/** Type of entities to display */
@@ -202,6 +207,16 @@ export default class EntityGrid extends Vue {
isSearching = false;
searchTimeout: NodeJS.Timeout | null = null;
filteredEntities: Contact[] | PlanData[] = [];
+ searchBeforeId: string | undefined = undefined;
+ isLoadingSearchMore = false;
+
+ // API server for project searches
+ apiServer = "";
+
+ // Internal project state (when entities prop not provided for projects)
+ allProjects: PlanData[] = [];
+ loadBeforeId: string | undefined = undefined;
+ isLoadingProjects = false;
// Infinite scroll state
displayedCount = INITIAL_BATCH_SIZE;
@@ -211,17 +226,17 @@ export default class EntityGrid extends Vue {
/**
* Array of entities to display
*
+ * For contacts (entityType === 'people'): REQUIRED - Must be a COMPLETE list from local database.
+ * Use $contactsByDateAdded() to ensure all contacts are included.
+ * Client-side filtering assumes the complete list is available.
* IMPORTANT: When passing Contact[] arrays, they must be sorted by date added
* (newest first) for the "Recently Added" section to display correctly.
- * Use $contactsByDateAdded() instead of $getAllContacts() or $contacts().
*
- * The recentContacts computed property assumes contacts are already sorted
- * by date added and simply takes the first 3. If contacts are sorted
- * alphabetically or in another order, the wrong contacts will appear in
- * "Recently Added".
+ * For projects (entityType === 'projects'): OPTIONAL - If not provided, EntityGrid loads
+ * projects internally from the API server. If provided, uses the provided list.
*/
- @Prop({ required: true })
- entities!: Contact[] | PlanData[];
+ @Prop({ required: false })
+ entities?: Contact[] | PlanData[];
/** Active user's DID */
@Prop({ required: true })
@@ -293,6 +308,33 @@ export default class EntityGrid extends Vue {
return "text-xs text-slate-500 italic col-span-full";
}
+ /**
+ * Check if there are no entities to display
+ */
+ get hasNoEntities(): boolean {
+ if (this.entityType === "projects") {
+ // For projects: check internal state if no entities prop, otherwise check prop
+ const projectsToCheck = this.entities || this.allProjects;
+ return projectsToCheck.length === 0;
+ } else {
+ // For people: entities prop is required
+ return !this.entities || this.entities.length === 0;
+ }
+ }
+
+ /**
+ * Get the entities array to use (prop or internal state)
+ */
+ get entitiesToUse(): Contact[] | PlanData[] {
+ if (this.entityType === "projects") {
+ // For projects: use prop if provided, otherwise use internal state
+ return this.entities || this.allProjects;
+ } else {
+ // For people: entities prop is required
+ return this.entities || [];
+ }
+ }
+
/**
* Computed entities to display - uses function prop if provided, otherwise uses infinite scroll
* When searching, returns filtered results with infinite scroll applied
@@ -305,12 +347,12 @@ export default class EntityGrid extends Vue {
// If custom function provided, use it (disables infinite scroll)
if (this.displayEntitiesFunction) {
- return this.displayEntitiesFunction(this.entities, this.entityType);
+ return this.displayEntitiesFunction(this.entitiesToUse, this.entityType);
}
// Default: projects use infinite scroll
if (this.entityType === "projects") {
- return (this.entities as PlanData[]).slice(0, this.displayedCount);
+ return (this.entitiesToUse as PlanData[]).slice(0, this.displayedCount);
}
// People: handled by recentContacts + alphabeticalContacts (both use displayedCount)
@@ -324,7 +366,11 @@ export default class EntityGrid extends Vue {
* See the entities prop documentation for details on using $contactsByDateAdded().
*/
get recentContacts(): Contact[] {
- if (this.entityType !== "people" || this.searchTerm.trim()) {
+ if (
+ this.entityType !== "people" ||
+ this.searchTerm.trim() ||
+ !this.entities
+ ) {
return [];
}
// Entities are already sorted by date added (newest first)
@@ -336,7 +382,11 @@ export default class EntityGrid extends Vue {
* Uses infinite scroll to control how many are displayed
*/
get alphabeticalContacts(): Contact[] {
- if (this.entityType !== "people" || this.searchTerm.trim()) {
+ if (
+ this.entityType !== "people" ||
+ this.searchTerm.trim() ||
+ !this.entities
+ ) {
return [];
}
// Skip the first few (recent contacts) and sort the rest alphabetically
@@ -457,47 +507,28 @@ export default class EntityGrid extends Vue {
/**
* Perform the actual search
+ * Routes to server-side search for projects or client-side filtering for contacts
*/
async performSearch(): Promise {
if (!this.searchTerm.trim()) {
this.filteredEntities = [];
this.displayedCount = INITIAL_BATCH_SIZE;
+ this.searchBeforeId = undefined;
this.infiniteScrollReset?.();
return;
}
this.isSearching = true;
+ this.searchBeforeId = undefined; // Reset pagination for new search
try {
- // Simulate async search (in case we need to add API calls later)
- await new Promise((resolve) => setTimeout(resolve, 100));
-
- const searchLower = this.searchTerm.toLowerCase().trim();
-
- if (this.entityType === "people") {
- this.filteredEntities = (this.entities as Contact[])
- .filter((contact: Contact) => {
- const name = contact.name?.toLowerCase() || "";
- const did = contact.did.toLowerCase();
- return name.includes(searchLower) || did.includes(searchLower);
- })
- .sort((a: Contact, b: Contact) => {
- // Sort alphabetically by name, falling back to DID if name is missing
- const nameA = (a.name || a.did).toLowerCase();
- const nameB = (b.name || b.did).toLowerCase();
- return nameA.localeCompare(nameB);
- });
+ if (this.entityType === "projects") {
+ // Server-side search for projects (initial load, no beforeId)
+ const searchLower = this.searchTerm.toLowerCase().trim();
+ await this.fetchProjects(undefined, searchLower);
} else {
- this.filteredEntities = (this.entities as PlanData[])
- .filter((project: PlanData) => {
- const name = project.name?.toLowerCase() || "";
- const handleId = project.handleId.toLowerCase();
- return name.includes(searchLower) || handleId.includes(searchLower);
- })
- .sort((a: PlanData, b: PlanData) => {
- // Sort alphabetically by name
- return a.name.toLowerCase().localeCompare(b.name.toLowerCase());
- });
+ // Client-side filtering for contacts (complete list)
+ await this.performContactSearch();
}
// Reset displayed count when search completes
@@ -508,6 +539,194 @@ export default class EntityGrid extends Vue {
}
}
+ /**
+ * Fetch projects from API server
+ * Unified method for both loading all projects and searching projects.
+ * If claimContents is provided, performs search and updates filteredEntities.
+ * If claimContents is not provided, loads all projects and updates allProjects.
+ *
+ * @param beforeId - Optional rowId for pagination (loads projects before this ID)
+ * @param claimContents - Optional search term (if provided, performs search; if not, loads all)
+ */
+ async fetchProjects(
+ beforeId?: string,
+ claimContents?: string,
+ ): Promise {
+ if (!this.apiServer) {
+ if (claimContents) {
+ this.filteredEntities = [];
+ } else {
+ this.allProjects = [];
+ }
+ if (this.notify) {
+ this.notify(
+ {
+ group: "alert",
+ type: "danger",
+ title: "Error",
+ text: "API server not configured",
+ },
+ TIMEOUTS.SHORT,
+ );
+ }
+ return;
+ }
+
+ const isSearch = !!claimContents;
+ let url = `${this.apiServer}/api/v2/report/plans`;
+
+ // Build query parameters
+ const params: string[] = [];
+ if (claimContents) {
+ params.push(
+ `claimContents=${encodeURIComponent(claimContents.toLowerCase().trim())}`,
+ );
+ }
+ if (beforeId) {
+ params.push(`beforeId=${encodeURIComponent(beforeId)}`);
+ }
+ if (params.length > 0) {
+ url += `?${params.join("&")}`;
+ }
+
+ try {
+ const response = await fetch(url, {
+ method: "GET",
+ headers: await getHeaders(this.activeDid),
+ });
+
+ if (response.status !== 200) {
+ throw new Error(
+ isSearch ? "Failed to search projects" : "Failed to load projects",
+ );
+ }
+
+ const results = await response.json();
+ if (results.data) {
+ const newProjects = results.data.map(
+ (plan: PlanData & { rowId?: string }) => ({
+ ...plan,
+ rowId: plan.rowId,
+ }),
+ );
+
+ if (isSearch) {
+ // Search mode: update filteredEntities
+ if (beforeId) {
+ // Pagination: append new projects to existing search results
+ this.filteredEntities.push(...newProjects);
+ } else {
+ // Initial search: replace array
+ this.filteredEntities = newProjects;
+ }
+
+ // Update searchBeforeId for next pagination
+ if (newProjects.length > 0) {
+ const lastProject = newProjects[newProjects.length - 1];
+ this.searchBeforeId = lastProject.rowId || undefined;
+ } else {
+ this.searchBeforeId = undefined; // No more results
+ }
+ } else {
+ // Load mode: update allProjects
+ if (beforeId) {
+ // Pagination: append new projects
+ this.allProjects.push(...newProjects);
+ } else {
+ // Initial load: replace array
+ this.allProjects = newProjects;
+ }
+
+ // Update loadBeforeId for next pagination
+ if (newProjects.length > 0) {
+ const lastProject = newProjects[newProjects.length - 1];
+ this.loadBeforeId = lastProject.rowId || undefined;
+ } else {
+ this.loadBeforeId = undefined; // No more results
+ }
+ }
+ } else {
+ // No data in response
+ if (isSearch) {
+ if (!beforeId) {
+ // Only clear on initial search, not pagination
+ this.filteredEntities = [];
+ }
+ this.searchBeforeId = undefined;
+ } else {
+ if (!beforeId) {
+ // Only clear on initial load, not pagination
+ this.allProjects = [];
+ }
+ this.loadBeforeId = undefined;
+ }
+ }
+ } catch (error) {
+ logger.error(
+ `Error ${isSearch ? "searching" : "loading"} projects:`,
+ error,
+ );
+ if (isSearch) {
+ if (!beforeId) {
+ // Only clear on initial search error, not pagination error
+ this.filteredEntities = [];
+ }
+ this.searchBeforeId = undefined;
+ } else {
+ if (!beforeId) {
+ // Only clear on initial load error, not pagination error
+ this.allProjects = [];
+ }
+ this.loadBeforeId = undefined;
+ }
+ if (this.notify) {
+ this.notify(
+ {
+ group: "alert",
+ type: "danger",
+ title: "Error",
+ text: isSearch
+ ? "Failed to search projects. Please try again."
+ : "Failed to load projects. Please try again.",
+ },
+ TIMEOUTS.STANDARD,
+ );
+ }
+ }
+ }
+
+ /**
+ * Client-side contact search
+ * Assumes entities prop contains complete contact list from local database
+ */
+ async performContactSearch(): Promise {
+ if (!this.entities) {
+ this.filteredEntities = [];
+ return;
+ }
+
+ // Simulate async (for consistency with project search)
+ await new Promise((resolve) => setTimeout(resolve, 100));
+
+ const searchLower = this.searchTerm.toLowerCase().trim();
+
+ this.filteredEntities = (this.entities as Contact[])
+ .filter((contact: Contact) => {
+ const name = contact.name?.toLowerCase() || "";
+ const did = contact.did.toLowerCase();
+ return name.includes(searchLower) || did.includes(searchLower);
+ })
+ .sort((a: Contact, b: Contact) => {
+ // Sort alphabetically by name, falling back to DID if name is missing
+ const nameA = (a.name || a.did).toLowerCase();
+ const nameB = (b.name || b.did).toLowerCase();
+ return nameA.localeCompare(nameB);
+ });
+
+ // Contacts don't need pagination (complete list)
+ this.searchBeforeId = undefined;
+ }
+
/**
* Clear the search
*/
@@ -516,6 +735,7 @@ export default class EntityGrid extends Vue {
this.filteredEntities = [];
this.isSearching = false;
this.displayedCount = INITIAL_BATCH_SIZE;
+ this.searchBeforeId = undefined;
this.infiniteScrollReset?.();
// Clear any pending timeout
@@ -535,17 +755,48 @@ export default class EntityGrid extends Vue {
}
if (this.searchTerm.trim()) {
- // Search mode: check filtered entities
- return this.displayedCount < this.filteredEntities.length;
+ // Search mode: check if more results available
+ if (this.entityType === "projects") {
+ // Projects: can load more if:
+ // 1. We have more already-loaded results to show, OR
+ // 2. We've shown all loaded results AND there's a searchBeforeId to load more
+ const hasMoreLoaded =
+ this.displayedCount < this.filteredEntities.length;
+ const canLoadMoreFromServer =
+ this.displayedCount >= this.filteredEntities.length &&
+ !!this.searchBeforeId &&
+ !this.isLoadingSearchMore;
+ return hasMoreLoaded || canLoadMoreFromServer;
+ } else {
+ // Contacts: client-side filtering returns all results at once
+ return this.displayedCount < this.filteredEntities.length;
+ }
}
+ // Non-search mode
if (this.entityType === "projects") {
- // Projects: check if more available
- return this.displayedCount < this.entities.length;
+ // Projects: check internal state or prop
+ const projectsToCheck = this.entities || this.allProjects;
+ const beforeId = this.entities ? undefined : this.loadBeforeId;
+
+ // Can load more if:
+ // 1. We have more already-loaded results to show, OR
+ // 2. We've shown all loaded results AND there's a beforeId to load more (and not using entities prop)
+ const hasMoreLoaded = this.displayedCount < projectsToCheck.length;
+ const canLoadMoreFromServer =
+ !this.entities &&
+ this.displayedCount >= projectsToCheck.length &&
+ !!beforeId &&
+ !this.isLoadingProjects;
+
+ return hasMoreLoaded || canLoadMoreFromServer;
}
// People: check if more alphabetical contacts available
// Total available = recent + all alphabetical
+ if (!this.entities) {
+ return false;
+ }
const totalAvailable = RECENT_CONTACTS_COUNT + this.entities.length;
return this.displayedCount < totalAvailable;
}
@@ -553,16 +804,112 @@ export default class EntityGrid extends Vue {
/**
* Initialize infinite scroll on mount
*/
- mounted(): void {
+ async mounted(): Promise {
+ // Load apiServer for project searches/loads
+ if (this.entityType === "projects") {
+ const settings = await this.$accountSettings();
+ this.apiServer = settings.apiServer || "";
+
+ // Load projects on mount if entities prop not provided
+ if (!this.entities && this.apiServer) {
+ this.isLoadingProjects = true;
+ try {
+ await this.fetchProjects();
+ } catch (error) {
+ logger.error("Error loading projects on mount:", error);
+ } finally {
+ this.isLoadingProjects = false;
+ }
+ }
+ }
+
+ // Validate entities prop for people
+ if (this.entityType === "people" && !this.entities) {
+ logger.error(
+ "EntityGrid: entities prop is required when entityType is 'people'",
+ );
+ if (this.notify) {
+ this.notify(
+ {
+ group: "alert",
+ type: "danger",
+ title: "Error",
+ text: "Contacts data is required but not provided.",
+ },
+ TIMEOUTS.SHORT,
+ );
+ }
+ }
+
this.$nextTick(() => {
const container = this.$refs.scrollContainer as HTMLElement;
if (container) {
const { reset } = useInfiniteScroll(
container,
- () => {
- // Load more: increment displayedCount
- this.displayedCount += INCREMENT_SIZE;
+ async () => {
+ // Search mode: handle search pagination
+ if (this.searchTerm.trim()) {
+ if (this.entityType === "projects") {
+ // Projects: load more search results if available
+ if (
+ this.displayedCount >= this.filteredEntities.length &&
+ this.searchBeforeId &&
+ !this.isLoadingSearchMore
+ ) {
+ this.isLoadingSearchMore = true;
+ try {
+ const searchLower = this.searchTerm.toLowerCase().trim();
+ await this.fetchProjects(this.searchBeforeId, searchLower);
+ // After loading more, reset scroll state to allow further loading
+ this.infiniteScrollReset?.();
+ } catch (error) {
+ logger.error("Error loading more search results:", error);
+ // Error already handled in fetchProjects
+ } finally {
+ this.isLoadingSearchMore = false;
+ }
+ } else {
+ // Show more from already-loaded search results
+ this.displayedCount += INCREMENT_SIZE;
+ }
+ } else {
+ // Contacts: show more from already-filtered results
+ this.displayedCount += INCREMENT_SIZE;
+ }
+ } else {
+ // Non-search mode
+ if (this.entityType === "projects") {
+ const projectsToCheck = this.entities || this.allProjects;
+ const beforeId = this.entities ? undefined : this.loadBeforeId;
+
+ // If using internal state and need to load more from server
+ if (
+ !this.entities &&
+ this.displayedCount >= projectsToCheck.length &&
+ beforeId &&
+ !this.isLoadingProjects
+ ) {
+ this.isLoadingProjects = true;
+ try {
+ await this.fetchProjects(beforeId);
+ // After loading more, reset scroll state to allow further loading
+ this.infiniteScrollReset?.();
+ } catch (error) {
+ logger.error("Error loading more projects:", error);
+ // Error already handled in fetchProjects
+ } finally {
+ this.isLoadingProjects = false;
+ }
+ } else {
+ // Normal case: increment displayedCount to show more from memory
+ this.displayedCount += INCREMENT_SIZE;
+ }
+ } else {
+ // People: increment displayedCount to show more from memory
+ this.displayedCount += INCREMENT_SIZE;
+ }
+ }
},
{
distance: 50, // pixels from bottom
@@ -588,21 +935,35 @@ export default class EntityGrid extends Vue {
}
/**
- * Watch for changes in search term to reset displayed count
+ * Watch for changes in search term to reset displayed count and pagination
*/
@Watch("searchTerm")
onSearchTermChange(): void {
+ // Reset displayed count and pagination when search term changes
this.displayedCount = INITIAL_BATCH_SIZE;
+ this.searchBeforeId = undefined;
this.infiniteScrollReset?.();
}
/**
- * Watch for changes in entities prop to reset displayed count
+ * Watch for changes in entities prop to clear search and reset displayed count
*/
@Watch("entities")
onEntitiesChange(): void {
+ // Clear search when entities change (fresh dialog open)
+ if (this.searchTerm) {
+ this.searchTerm = "";
+ this.filteredEntities = [];
+ this.searchBeforeId = undefined;
+ }
this.displayedCount = INITIAL_BATCH_SIZE;
this.infiniteScrollReset?.();
+
+ // For projects: if entities prop is provided, clear internal state
+ if (this.entityType === "projects" && this.entities) {
+ this.allProjects = [];
+ this.loadBeforeId = undefined;
+ }
}
/**
diff --git a/src/components/EntitySelectionStep.vue b/src/components/EntitySelectionStep.vue
index fd62ccdd..3fba2141 100644
--- a/src/components/EntitySelectionStep.vue
+++ b/src/components/EntitySelectionStep.vue
@@ -14,7 +14,7 @@ properties * * @author Matthew Raymer */
diff --git a/src/views/OnboardMeetingSetupView.vue b/src/views/OnboardMeetingSetupView.vue
index a37c0aa4..a3378330 100644
--- a/src/views/OnboardMeetingSetupView.vue
+++ b/src/views/OnboardMeetingSetupView.vue
@@ -269,12 +269,13 @@
@@ -307,6 +308,7 @@
{
+ const projectLink =
+ this.currentMeeting?.projectLink ||
+ this.newOrUpdatedMeetingInputs?.projectLink;
+
+ if (!projectLink) {
+ this.selectedProjectData = null;
+ return;
+ }
+
+ 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;
@@ -648,7 +699,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);
@@ -659,6 +710,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.",
@@ -666,9 +721,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() {
@@ -783,55 +844,12 @@ export default class OnboardMeetingView extends Vue {
}
}
- /**
- * Load projects from the API
- */
- async loadProjects() {
- try {
- const headers = await getHeaders(this.activeDid);
- const url = `${this.apiServer}/api/v2/report/plans`;
- const resp = await this.axios.get(url, { headers });
-
- if (resp.status === 200 && resp.data.data) {
- this.allProjects = resp.data.data.map(
- (plan: {
- name: string;
- description: string;
- image?: string;
- handleId: string;
- issuerDid: string;
- }) => ({
- name: plan.name,
- description: plan.description,
- image: plan.image,
- handleId: plan.handleId,
- issuerDid: plan.issuerDid,
- }),
- );
- }
- } catch (error) {
- this.$logAndConsole(
- "Error loading projects: " + errorStringForLog(error),
- true,
- );
- // Don't show error to user - just leave projects empty
- this.allProjects = [];
- }
- }
-
/**
* 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;
}
/**
@@ -861,6 +879,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;
}
@@ -870,9 +891,30 @@ 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 = "";
}
}
+
+ /**
+ * Handle dialog open event - stop auto-refresh in MembersList
+ */
+ handleDialogOpen(): void {
+ const membersList = this.$refs.membersList as MembersList;
+ if (membersList) {
+ membersList.stopAutoRefresh();
+ }
+ }
+
+ /**
+ * Handle dialog close event - start auto-refresh in MembersList
+ */
+ handleDialogClose(): void {
+ const membersList = this.$refs.membersList as MembersList;
+ if (membersList) {
+ membersList.startAutoRefresh();
+ }
+ }
}