From 6fbc9c2a5b772138a3af04965035246ba569cfa8 Mon Sep 17 00:00:00 2001 From: Jose Olarte III Date: Wed, 22 Oct 2025 21:56:00 +0800 Subject: [PATCH] feat: Add AdmitPendingMembersDialog for bulk member admission - Add new AdmitPendingMembersDialog component with checkbox selection - Support two action modes: "Admit + Add Contacts" and "Admit Only" - Integrate dialog into MembersList with proper sequencing - Show admit dialog before visibility dialog when pending members exist - Fix auto-refresh pause/resume logic for both dialogs - Ensure consistent dialog behavior between initial load and manual refresh - Add proper async/await handling for data refresh operations - Optimize dialog state management and remove redundant code - Maintain proper flag timing to prevent race conditions The admit dialog now shows automatically when there are pending members, allowing organizers to efficiently admit multiple members at once while optionally adding them as contacts and setting visibility preferences. --- src/components/AdmitPendingMembersDialog.vue | 458 +++++++++++++++++++ src/components/MembersList.vue | 175 ++++++- 2 files changed, 620 insertions(+), 13 deletions(-) create mode 100644 src/components/AdmitPendingMembersDialog.vue diff --git a/src/components/AdmitPendingMembersDialog.vue b/src/components/AdmitPendingMembersDialog.vue new file mode 100644 index 00000000..d6cbd013 --- /dev/null +++ b/src/components/AdmitPendingMembersDialog.vue @@ -0,0 +1,458 @@ + + + + + diff --git a/src/components/MembersList.vue b/src/components/MembersList.vue index 1a5babbc..9b082312 100644 --- a/src/components/MembersList.vue +++ b/src/components/MembersList.vue @@ -177,6 +177,16 @@ + + + = []; + admitDialogDismissed = false; + isManualRefresh = false; + // Set Visibility Dialog state showSetVisibilityDialog = false; visibilityDialogMembers: Array<{ @@ -296,8 +319,13 @@ export default class MembersList extends Vue { // Start auto-refresh this.startAutoRefresh(); - // Check if we should show the visibility dialog on initial load - this.checkAndShowVisibilityDialog(); + // Check if we should show the admit pending members dialog first + this.checkAndShowAdmitPendingDialog(); + + // If no pending members, check for visibility dialog + if (!this.showAdmitPendingDialog) { + this.checkAndShowVisibilityDialog(); + } } async refreshData() { @@ -305,8 +333,13 @@ export default class MembersList extends Vue { await this.loadContacts(); await this.fetchMembers(); - // Check if we should show the visibility dialog after refresh - this.checkAndShowVisibilityDialog(); + // Check if we should show the admit pending members dialog first + this.checkAndShowAdmitPendingDialog(); + + // If no pending members, check for visibility dialog + if (!this.showAdmitPendingDialog) { + this.checkAndShowVisibilityDialog(); + } } async fetchMembers() { @@ -463,6 +496,26 @@ export default class MembersList extends Vue { return this.contacts.find((contact) => contact.did === did); } + getPendingMembers() { + return this.decryptedMembers + .filter((member) => { + // Exclude the current user + if (member.did === this.activeDid) { + return false; + } + // Only include non-admitted members + return !member.member.admitted; + }) + .map((member) => ({ + did: member.did, + name: member.name, + isContact: !!this.getContactFor(member.did), + member: { + memberId: member.member.memberId.toString(), + }, + })); + } + getMembersForVisibility() { return this.decryptedMembers .filter((member) => { @@ -492,7 +545,8 @@ export default class MembersList extends Vue { * Check if we should show the visibility dialog * Returns true if there are members for visibility and either: * - This is the first time (no previous members tracked), OR - * - New members have been added since last check (not removed) + * - New members have been added since last check (not removed), OR + * - This is a manual refresh (isManualRefresh flag is set) */ shouldShowVisibilityDialog(): boolean { const currentMembers = this.getMembersForVisibility(); @@ -506,6 +560,11 @@ export default class MembersList extends Vue { return true; } + // If this is a manual refresh, always show dialog if there are members + if (this.isManualRefresh) { + return true; + } + // Check if new members have been added (not just any change) const currentMemberIds = currentMembers.map((m) => m.did); const previousMemberIds = this.previousVisibilityMembers; @@ -527,6 +586,31 @@ export default class MembersList extends Vue { this.previousVisibilityMembers = currentMembers.map((m) => m.did); } + /** + * Check if we should show the admit pending members dialog + */ + shouldShowAdmitPendingDialog(): boolean { + // Don't show if already dismissed + if (this.admitDialogDismissed) { + return false; + } + + const pendingMembers = this.getPendingMembers(); + return pendingMembers.length > 0; + } + + /** + * Show the admit pending members dialog if conditions are met + */ + checkAndShowAdmitPendingDialog() { + if (this.shouldShowAdmitPendingDialog()) { + this.showAdmitPendingDialogMethod(); + } else { + // Ensure dialog state is false when no pending members + this.showAdmitPendingDialog = false; + } + } + /** * Show the visibility dialog if conditions are met */ @@ -675,6 +759,24 @@ export default class MembersList extends Vue { } } + showAdmitPendingDialogMethod() { + // Filter members to show only pending (non-admitted) members + const pendingMembers = this.getPendingMembers(); + + // Only show dialog if there are pending members + if (pendingMembers.length === 0) { + this.showAdmitPendingDialog = false; + return; + } + + // Pause auto-refresh when dialog opens + this.stopAutoRefresh(); + + // Open the dialog directly + this.pendingMembersData = pendingMembers; + this.showAdmitPendingDialog = true; + } + showSetBulkVisibilityDialog() { // Filter members to show only those who need visibility set const membersForVisibility = this.getMembersForVisibility(); @@ -682,6 +784,9 @@ export default class MembersList extends Vue { // Pause auto-refresh when dialog opens this.stopAutoRefresh(); + // Reset manual refresh flag when showing visibility dialog + this.isManualRefresh = false; + // Open the dialog directly this.visibilityDialogMembers = membersForVisibility; this.showSetVisibilityDialog = true; @@ -717,28 +822,72 @@ export default class MembersList extends Vue { } } - manualRefresh() { + async manualRefresh() { // Clear existing auto-refresh interval if (this.autoRefreshInterval) { clearInterval(this.autoRefreshInterval); this.autoRefreshInterval = null; } - // Trigger immediate refresh and restart timer - this.refreshData(); - this.startAutoRefresh(); + // Set manual refresh flag + this.isManualRefresh = true; + // Reset the dismissed flag on manual refresh + this.admitDialogDismissed = false; - // Always show dialog on manual refresh if there are members for visibility - if (this.getMembersForVisibility().length > 0) { - this.showSetBulkVisibilityDialog(); + // Trigger immediate refresh + await this.refreshData(); + + // Only start auto-refresh if no dialogs are showing + if (!this.showAdmitPendingDialog && !this.showSetVisibilityDialog) { + this.startAutoRefresh(); } } + // Admit Pending Members Dialog methods + async closeAdmitPendingDialog() { + this.showAdmitPendingDialog = false; + this.pendingMembersData = []; + this.admitDialogDismissed = true; + + // Handle manual refresh flow + if (this.isManualRefresh) { + await this.handleManualRefreshFlow(); + this.isManualRefresh = false; + } else { + // Normal flow: refresh data and resume auto-refresh + this.refreshData(); + this.startAutoRefresh(); + } + } + + async handleManualRefreshFlow() { + // Refresh data to reflect any changes made in the admit dialog + await this.refreshData(); + + // Use the same logic as normal flow to check for visibility dialog + this.checkAndShowVisibilityDialog(); + + // If no visibility dialog was shown, resume auto-refresh + if (!this.showSetVisibilityDialog) { + this.startAutoRefresh(); + } + } + + async onAdmitPendingSuccess(_result: { + admittedCount: number; + contactAddedCount: number; + visibilitySetCount: number; + }) { + // After admitting pending members, close the admit dialog + // The visibility dialog will be handled by the closeAdmitPendingDialog flow + await this.closeAdmitPendingDialog(); + } + // Set Visibility Dialog methods closeSetVisibilityDialog() { this.showSetVisibilityDialog = false; this.visibilityDialogMembers = []; - // Refresh data when dialog is closed + // Refresh data when dialog is closed to reflect any changes made this.refreshData(); // Resume auto-refresh when dialog is closed this.startAutoRefresh();