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.
This commit is contained in:
458
src/components/AdmitPendingMembersDialog.vue
Normal file
458
src/components/AdmitPendingMembersDialog.vue
Normal file
@@ -0,0 +1,458 @@
|
||||
<template>
|
||||
<div v-if="visible" class="dialog-overlay">
|
||||
<div class="dialog">
|
||||
<div class="text-slate-900 text-center">
|
||||
<h3 class="text-lg font-semibold leading-[1.25] mb-2">
|
||||
Admit Pending Members
|
||||
</h3>
|
||||
<p class="text-sm mb-4">
|
||||
The following members are waiting to be admitted to the meeting. You
|
||||
can choose to admit them and optionally add them as contacts with
|
||||
visibility settings.
|
||||
</p>
|
||||
|
||||
<!-- Custom table area - you can customize this -->
|
||||
<div v-if="shouldInitializeSelection" class="mb-4">
|
||||
<table
|
||||
class="w-full border-collapse border border-slate-300 text-sm text-start"
|
||||
>
|
||||
<thead v-if="pendingMembersData && pendingMembersData.length > 0">
|
||||
<tr class="bg-slate-100 font-medium">
|
||||
<th class="border border-slate-300 px-3 py-2">
|
||||
<label class="flex items-center gap-2">
|
||||
<input
|
||||
type="checkbox"
|
||||
:checked="isAllSelected"
|
||||
:indeterminate="isIndeterminate"
|
||||
@change="toggleSelectAll"
|
||||
/>
|
||||
Select All
|
||||
</label>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<!-- Dynamic data from MembersList -->
|
||||
<tr v-if="!pendingMembersData || pendingMembersData.length === 0">
|
||||
<td
|
||||
class="border border-slate-300 px-3 py-2 text-center italic text-gray-500"
|
||||
>
|
||||
No pending members to admit
|
||||
</td>
|
||||
</tr>
|
||||
<tr
|
||||
v-for="member in pendingMembersData || []"
|
||||
:key="member.member.memberId"
|
||||
>
|
||||
<td class="border border-slate-300 px-3 py-2">
|
||||
<div class="flex items-center justify-between gap-2">
|
||||
<label class="flex items-center gap-2">
|
||||
<input
|
||||
type="checkbox"
|
||||
:checked="isMemberSelected(member.did)"
|
||||
@change="toggleMemberSelection(member.did)"
|
||||
/>
|
||||
{{ member.name || SOMEONE_UNNAMED }}
|
||||
</label>
|
||||
|
||||
<!-- Contact indicator - only show if they are already a contact -->
|
||||
<font-awesome
|
||||
v-if="member.isContact"
|
||||
icon="user-circle"
|
||||
class="fa-fw ms-auto text-slate-400 cursor-pointer hover:text-slate-600"
|
||||
@click="showContactInfo"
|
||||
/>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="space-y-2">
|
||||
<button
|
||||
v-if="pendingMembersData && pendingMembersData.length > 0"
|
||||
:disabled="!hasSelectedMembers"
|
||||
:class="[
|
||||
'block w-full text-center text-md font-bold uppercase px-2 py-2 rounded-md',
|
||||
hasSelectedMembers
|
||||
? 'bg-green-600 text-white cursor-pointer'
|
||||
: 'bg-slate-400 text-slate-200 cursor-not-allowed',
|
||||
]"
|
||||
@click="admitAndSetVisibility"
|
||||
>
|
||||
Admit Pending + Add Contacts
|
||||
</button>
|
||||
<button
|
||||
v-if="pendingMembersData && pendingMembersData.length > 0"
|
||||
:disabled="!hasSelectedMembers"
|
||||
:class="[
|
||||
'block w-full text-center text-md font-bold uppercase px-2 py-2 rounded-md',
|
||||
hasSelectedMembers
|
||||
? 'bg-blue-600 text-white cursor-pointer'
|
||||
: 'bg-slate-400 text-slate-200 cursor-not-allowed',
|
||||
]"
|
||||
@click="admitOnly"
|
||||
>
|
||||
Admit Pending Only
|
||||
</button>
|
||||
<button
|
||||
class="block w-full text-center text-md font-bold uppercase bg-slate-600 text-white px-2 py-2 rounded-md"
|
||||
@click="cancel"
|
||||
>
|
||||
Maybe Later
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Vue, Component, Prop } from "vue-facing-decorator";
|
||||
|
||||
import { PlatformServiceMixin } from "@/utils/PlatformServiceMixin";
|
||||
import { SOMEONE_UNNAMED } from "@/constants/entities";
|
||||
import { setVisibilityUtil, getHeaders } from "@/libs/endorserServer";
|
||||
import { createNotifyHelpers } from "@/utils/notify";
|
||||
|
||||
interface PendingMemberData {
|
||||
did: string;
|
||||
name: string;
|
||||
isContact: boolean;
|
||||
member: {
|
||||
memberId: string;
|
||||
};
|
||||
}
|
||||
|
||||
@Component({
|
||||
mixins: [PlatformServiceMixin],
|
||||
})
|
||||
export default class AdmitPendingMembersDialog extends Vue {
|
||||
@Prop({ default: false }) visible!: boolean;
|
||||
@Prop({ default: () => [] }) pendingMembersData!: PendingMemberData[];
|
||||
@Prop({ default: "" }) activeDid!: string;
|
||||
@Prop({ default: "" }) apiServer!: string;
|
||||
|
||||
// Vue notification system
|
||||
$notify!: (
|
||||
notification: { group: string; type: string; title: string; text: string },
|
||||
timeout?: number,
|
||||
) => void;
|
||||
|
||||
// Notification system
|
||||
notify!: ReturnType<typeof createNotifyHelpers>;
|
||||
|
||||
// Component state
|
||||
selectedMembers: string[] = [];
|
||||
selectionInitialized = false;
|
||||
|
||||
// Constants
|
||||
// In Vue templates, imported constants need to be explicitly made available to the template
|
||||
readonly SOMEONE_UNNAMED = SOMEONE_UNNAMED;
|
||||
|
||||
get hasSelectedMembers() {
|
||||
return this.selectedMembers.length > 0;
|
||||
}
|
||||
|
||||
get isAllSelected() {
|
||||
if (!this.pendingMembersData || this.pendingMembersData.length === 0)
|
||||
return false;
|
||||
return this.pendingMembersData.every((member) =>
|
||||
this.selectedMembers.includes(member.did),
|
||||
);
|
||||
}
|
||||
|
||||
get isIndeterminate() {
|
||||
if (!this.pendingMembersData || this.pendingMembersData.length === 0)
|
||||
return false;
|
||||
const selectedCount = this.pendingMembersData.filter((member) =>
|
||||
this.selectedMembers.includes(member.did),
|
||||
).length;
|
||||
return selectedCount > 0 && selectedCount < this.pendingMembersData.length;
|
||||
}
|
||||
|
||||
get shouldInitializeSelection() {
|
||||
// This method will initialize selection when the dialog opens
|
||||
if (!this.selectionInitialized) {
|
||||
this.initializeSelection();
|
||||
this.selectionInitialized = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
created() {
|
||||
this.notify = createNotifyHelpers(this.$notify);
|
||||
}
|
||||
|
||||
initializeSelection() {
|
||||
// Reset selection when dialog opens
|
||||
this.selectedMembers = [];
|
||||
// Select all by default
|
||||
this.selectedMembers = this.pendingMembersData.map((member) => member.did);
|
||||
}
|
||||
|
||||
resetSelection() {
|
||||
this.selectedMembers = [];
|
||||
this.selectionInitialized = false;
|
||||
}
|
||||
|
||||
toggleSelectAll() {
|
||||
if (!this.pendingMembersData || this.pendingMembersData.length === 0)
|
||||
return;
|
||||
|
||||
if (this.isAllSelected) {
|
||||
// Deselect all
|
||||
this.selectedMembers = [];
|
||||
} else {
|
||||
// Select all
|
||||
this.selectedMembers = this.pendingMembersData.map(
|
||||
(member) => member.did,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
toggleMemberSelection(memberDid: string) {
|
||||
const index = this.selectedMembers.indexOf(memberDid);
|
||||
if (index > -1) {
|
||||
this.selectedMembers.splice(index, 1);
|
||||
} else {
|
||||
this.selectedMembers.push(memberDid);
|
||||
}
|
||||
}
|
||||
|
||||
isMemberSelected(memberDid: string) {
|
||||
return this.selectedMembers.includes(memberDid);
|
||||
}
|
||||
|
||||
async admitAndSetVisibility() {
|
||||
try {
|
||||
const selectedMembers = this.pendingMembersData.filter((member) =>
|
||||
this.selectedMembers.includes(member.did),
|
||||
);
|
||||
|
||||
let admittedCount = 0;
|
||||
let contactAddedCount = 0;
|
||||
let visibilitySetCount = 0;
|
||||
|
||||
for (const member of selectedMembers) {
|
||||
try {
|
||||
// First, admit the member
|
||||
await this.admitMember(member);
|
||||
admittedCount++;
|
||||
|
||||
// If they're not a contact yet, add them as a contact
|
||||
if (!member.isContact) {
|
||||
await this.addAsContact(member);
|
||||
contactAddedCount++;
|
||||
}
|
||||
|
||||
// Set their seesMe to true
|
||||
await this.updateContactVisibility(member.did, true);
|
||||
visibilitySetCount++;
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(`Error processing member ${member.did}:`, error);
|
||||
// Continue with other members even if one fails
|
||||
}
|
||||
}
|
||||
|
||||
// Show success notification
|
||||
this.$notify(
|
||||
{
|
||||
group: "alert",
|
||||
type: "success",
|
||||
title: "Members Admitted Successfully",
|
||||
text: `Admitted ${admittedCount} member${admittedCount === 1 ? "" : "s"}, added ${contactAddedCount} as contact${contactAddedCount === 1 ? "" : "s"}, and set visibility for ${visibilitySetCount} member${visibilitySetCount === 1 ? "" : "s"}.`,
|
||||
},
|
||||
5000,
|
||||
);
|
||||
|
||||
// Emit success event
|
||||
this.$emit("success", {
|
||||
admittedCount,
|
||||
contactAddedCount,
|
||||
visibilitySetCount,
|
||||
});
|
||||
this.close();
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error("Error admitting members:", error);
|
||||
this.$notify(
|
||||
{
|
||||
group: "alert",
|
||||
type: "danger",
|
||||
title: "Error",
|
||||
text: "Failed to admit some members. Please try again.",
|
||||
},
|
||||
5000,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async admitOnly() {
|
||||
try {
|
||||
const selectedMembers = this.pendingMembersData.filter((member) =>
|
||||
this.selectedMembers.includes(member.did),
|
||||
);
|
||||
|
||||
let admittedCount = 0;
|
||||
|
||||
for (const member of selectedMembers) {
|
||||
try {
|
||||
// Just admit the member
|
||||
await this.admitMember(member);
|
||||
admittedCount++;
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(`Error admitting member ${member.did}:`, error);
|
||||
// Continue with other members even if one fails
|
||||
}
|
||||
}
|
||||
|
||||
// Show success notification
|
||||
this.$notify(
|
||||
{
|
||||
group: "alert",
|
||||
type: "success",
|
||||
title: "Members Admitted Successfully",
|
||||
text: `Admitted ${admittedCount} member${admittedCount === 1 ? "" : "s"} to the meeting.`,
|
||||
},
|
||||
5000,
|
||||
);
|
||||
|
||||
// Emit success event
|
||||
this.$emit("success", {
|
||||
admittedCount,
|
||||
contactAddedCount: 0,
|
||||
visibilitySetCount: 0,
|
||||
});
|
||||
this.close();
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error("Error admitting members:", error);
|
||||
this.$notify(
|
||||
{
|
||||
group: "alert",
|
||||
type: "danger",
|
||||
title: "Error",
|
||||
text: "Failed to admit some members. Please try again.",
|
||||
},
|
||||
5000,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async admitMember(member: {
|
||||
did: string;
|
||||
name: string;
|
||||
member: { memberId: string };
|
||||
}) {
|
||||
try {
|
||||
const headers = await getHeaders(this.activeDid);
|
||||
await this.axios.put(
|
||||
`${this.apiServer}/api/partner/groupOnboardMember/${member.member.memberId}`,
|
||||
{ admitted: true },
|
||||
{ headers },
|
||||
);
|
||||
} catch (err) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error("Error admitting member:", err);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
async addAsContact(member: { did: string; name: string }) {
|
||||
try {
|
||||
const newContact = {
|
||||
did: member.did,
|
||||
name: member.name,
|
||||
};
|
||||
|
||||
await this.$insertContact(newContact);
|
||||
} catch (err) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error("Error adding contact:", err);
|
||||
if (err instanceof Error && err.message?.indexOf("already exists") > -1) {
|
||||
// Contact already exists, continue
|
||||
} else {
|
||||
throw err; // Re-throw if it's not a duplicate error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async updateContactVisibility(did: string, seesMe: boolean) {
|
||||
try {
|
||||
// Get the contact object
|
||||
const contact = await this.$getContact(did);
|
||||
if (!contact) {
|
||||
throw new Error(`Contact not found for DID: ${did}`);
|
||||
}
|
||||
|
||||
// Use the proper API to set visibility on the server
|
||||
const result = await setVisibilityUtil(
|
||||
this.activeDid,
|
||||
this.apiServer,
|
||||
this.axios,
|
||||
contact,
|
||||
seesMe,
|
||||
);
|
||||
|
||||
if (!result.success) {
|
||||
throw new Error(result.error || "Failed to set visibility");
|
||||
}
|
||||
} catch (err) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error("Error updating contact visibility:", err);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
showContactInfo() {
|
||||
this.$notify(
|
||||
{
|
||||
group: "alert",
|
||||
type: "info",
|
||||
title: "Contact Info",
|
||||
text: "This user is already your contact, but they are not yet admitted to the meeting.",
|
||||
},
|
||||
5000,
|
||||
);
|
||||
}
|
||||
|
||||
close() {
|
||||
this.resetSelection();
|
||||
this.$emit("close");
|
||||
}
|
||||
|
||||
cancel() {
|
||||
this.close();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.dialog-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.dialog {
|
||||
background: white;
|
||||
border-radius: 8px;
|
||||
padding: 24px;
|
||||
max-width: 500px;
|
||||
width: 90%;
|
||||
max-height: 80vh;
|
||||
overflow-y: auto;
|
||||
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
</style>
|
||||
@@ -177,6 +177,16 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Admit Pending Members Dialog Component -->
|
||||
<AdmitPendingMembersDialog
|
||||
:visible="showAdmitPendingDialog"
|
||||
:pending-members-data="pendingMembersData"
|
||||
:active-did="activeDid"
|
||||
:api-server="apiServer"
|
||||
@close="closeAdmitPendingDialog"
|
||||
@success="onAdmitPendingSuccess"
|
||||
/>
|
||||
|
||||
<!-- Set Visibility Dialog Component -->
|
||||
<SetBulkVisibilityDialog
|
||||
:visible="showSetVisibilityDialog"
|
||||
@@ -208,6 +218,7 @@ import {
|
||||
} from "@/constants/notifications";
|
||||
import { SOMEONE_UNNAMED } from "@/constants/entities";
|
||||
import SetBulkVisibilityDialog from "./SetBulkVisibilityDialog.vue";
|
||||
import AdmitPendingMembersDialog from "./AdmitPendingMembersDialog.vue";
|
||||
|
||||
interface Member {
|
||||
admitted: boolean;
|
||||
@@ -225,6 +236,7 @@ interface DecryptedMember {
|
||||
@Component({
|
||||
components: {
|
||||
SetBulkVisibilityDialog,
|
||||
AdmitPendingMembersDialog,
|
||||
},
|
||||
mixins: [PlatformServiceMixin],
|
||||
})
|
||||
@@ -253,6 +265,17 @@ export default class MembersList extends Vue {
|
||||
activeDid = "";
|
||||
apiServer = "";
|
||||
|
||||
// Admit Pending Members Dialog state
|
||||
showAdmitPendingDialog = false;
|
||||
pendingMembersData: Array<{
|
||||
did: string;
|
||||
name: string;
|
||||
isContact: boolean;
|
||||
member: { memberId: string };
|
||||
}> = [];
|
||||
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();
|
||||
|
||||
Reference in New Issue
Block a user