refactor: make the meeting member "set visibility" screen much like the organizer's "admit" screen
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="space-y-4">
|
||||
<!-- Loading State -->
|
||||
<div
|
||||
@@ -48,7 +49,7 @@
|
||||
<button
|
||||
class="text-sm bg-gradient-to-b from-slate-400 to-slate-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-3 py-1.5 rounded-md"
|
||||
title="Refresh members list now"
|
||||
@click="manualRefresh"
|
||||
@click="refreshData(false)"
|
||||
>
|
||||
<font-awesome icon="rotate" :class="{ 'fa-spin': isLoading }" />
|
||||
Refresh
|
||||
@@ -163,7 +164,7 @@
|
||||
<button
|
||||
class="text-sm bg-gradient-to-b from-slate-400 to-slate-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-3 py-1.5 rounded-md"
|
||||
title="Refresh members list now"
|
||||
@click="manualRefresh"
|
||||
@click="refreshData(false)"
|
||||
>
|
||||
<font-awesome icon="rotate" :class="{ 'fa-spin': isLoading }" />
|
||||
Refresh
|
||||
@@ -177,43 +178,44 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Admit Pending Members Dialog Component -->
|
||||
<!-- This Admit component is for the organizer to admit pending members to the meeting -->
|
||||
<AdmitPendingMembersDialog
|
||||
ref="admitPendingMembersDialog"
|
||||
:active-did="activeDid"
|
||||
:api-server="apiServer"
|
||||
:pending-members-data="pendingMembersData"
|
||||
@close="closeAdmitPendingDialog"
|
||||
@close="closeMemberSelectionDialogCallback"
|
||||
/>
|
||||
<!-- This Bulk Visibility component is for non-organizer members to add other members to their contacts and set their visibility -->
|
||||
<SetBulkVisibilityDialog
|
||||
:visible="visibleBulkVisibilityDialog"
|
||||
ref="setBulkVisibilityDialog"
|
||||
:active-did="activeDid"
|
||||
:api-server="apiServer"
|
||||
:members-data="pendingMembersData"
|
||||
@close="closeSetBulkVisibilityDialog"
|
||||
@close="closeMemberSelectionDialogCallback"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Vue, Prop, Emit } from "vue-facing-decorator";
|
||||
|
||||
import {
|
||||
errorStringForLog,
|
||||
getHeaders,
|
||||
register,
|
||||
serverMessageForUser,
|
||||
} from "../libs/endorserServer";
|
||||
import { decryptMessage } from "../libs/crypto";
|
||||
import { Contact } from "../db/tables/contacts";
|
||||
import * as libsUtil from "../libs/util";
|
||||
import { NotificationIface } from "../constants/app";
|
||||
import { PlatformServiceMixin } from "@/utils/PlatformServiceMixin";
|
||||
import { createNotifyHelpers, TIMEOUTS } from "@/utils/notify";
|
||||
import { NotificationIface } from "@/constants/app";
|
||||
import {
|
||||
NOTIFY_ADD_CONTACT_FIRST,
|
||||
NOTIFY_CONTINUE_WITHOUT_ADDING,
|
||||
} from "@/constants/notifications";
|
||||
import { SOMEONE_UNNAMED } from "@/constants/entities";
|
||||
import {
|
||||
errorStringForLog,
|
||||
getHeaders,
|
||||
register,
|
||||
serverMessageForUser,
|
||||
} from "@/libs/endorserServer";
|
||||
import { decryptMessage } from "@/libs/crypto";
|
||||
import { Contact } from "@/db/tables/contacts";
|
||||
import { MemberData } from "@/interfaces";
|
||||
import * as libsUtil from "@/libs/util";
|
||||
import { PlatformServiceMixin } from "@/utils/PlatformServiceMixin";
|
||||
import { createNotifyHelpers, TIMEOUTS } from "@/utils/notify";
|
||||
import AdmitPendingMembersDialog from "./AdmitPendingMembersDialog.vue";
|
||||
import SetBulkVisibilityDialog from "./SetBulkVisibilityDialog.vue";
|
||||
|
||||
@@ -263,16 +265,6 @@ export default class MembersList extends Vue {
|
||||
activeDid = "";
|
||||
apiServer = "";
|
||||
|
||||
// Admit Pending Members Dialog state
|
||||
pendingMembersData: Array<{
|
||||
did: string;
|
||||
name: string;
|
||||
isContact: boolean;
|
||||
member: { memberId: string };
|
||||
}> = [];
|
||||
|
||||
visibleBulkVisibilityDialog = false;
|
||||
|
||||
// Auto-refresh functionality
|
||||
countdownTimer = 10;
|
||||
autoRefreshInterval: NodeJS.Timeout | null = null;
|
||||
@@ -302,16 +294,6 @@ export default class MembersList extends Vue {
|
||||
this.refreshData();
|
||||
}
|
||||
|
||||
async refreshData(showPendingEvenIfAllWereIgnored = false) {
|
||||
// Force refresh both contacts and members
|
||||
this.contacts = await this.$getAllContacts();
|
||||
|
||||
await this.fetchMembers();
|
||||
|
||||
// Check if we should show the admit pending members dialog first
|
||||
this.checkAndShowAdmitPendingDialog(showPendingEvenIfAllWereIgnored);
|
||||
}
|
||||
|
||||
async fetchMembers() {
|
||||
try {
|
||||
this.isLoading = true;
|
||||
@@ -408,8 +390,22 @@ export default class MembersList extends Vue {
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// non-organizers only get visible members from server
|
||||
members = this.decryptedMembers;
|
||||
// non-organizers only get visible members from server, plus themselves
|
||||
|
||||
// this is a stub for this user just in case they are waiting to get in
|
||||
// which is especially useful so they can see their own DID
|
||||
const currentUser: DecryptedMember = {
|
||||
member: {
|
||||
admitted: false,
|
||||
content: "{}",
|
||||
memberId: -1,
|
||||
},
|
||||
name: this.firstName,
|
||||
did: this.activeDid,
|
||||
isRegistered: false,
|
||||
};
|
||||
const otherMembersPlusUser = [ currentUser, ...this.decryptedMembers ];
|
||||
members = otherMembersPlusUser;
|
||||
}
|
||||
|
||||
// Sort members according to priority:
|
||||
@@ -462,61 +458,51 @@ export default class MembersList extends Vue {
|
||||
return this.contacts.find((contact) => contact.did === did);
|
||||
}
|
||||
|
||||
getPendingMembers(): {
|
||||
did: string;
|
||||
name: string;
|
||||
isContact: boolean;
|
||||
member: { memberId: string };
|
||||
}[] {
|
||||
getPendingMembersToAdmit(): MemberData[] {
|
||||
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(),
|
||||
},
|
||||
}));
|
||||
.filter((member) =>
|
||||
member.did !== this.activeDid && !member.member.admitted
|
||||
)
|
||||
.map(this.convertDecryptedMemberToMemberData);
|
||||
}
|
||||
|
||||
getNonContactMembers(): {
|
||||
did: string;
|
||||
name: string;
|
||||
isContact: boolean;
|
||||
member: { memberId: string };
|
||||
}[] {
|
||||
getNonContactMembers(): MemberData[] {
|
||||
return this.decryptedMembers
|
||||
.filter((member) => !this.getContactFor(member.did))
|
||||
.map((member) => ({
|
||||
did: member.did,
|
||||
name: member.name,
|
||||
isContact: false,
|
||||
member: {
|
||||
memberId: member.member.memberId.toString(),
|
||||
},
|
||||
}));
|
||||
.filter((member) =>
|
||||
member.did !== this.activeDid && !this.getContactFor(member.did)
|
||||
)
|
||||
.map(this.convertDecryptedMemberToMemberData);
|
||||
}
|
||||
|
||||
convertDecryptedMemberToMemberData(
|
||||
decryptedMember: DecryptedMember,
|
||||
): MemberData {
|
||||
return {
|
||||
did: decryptedMember.did,
|
||||
name: decryptedMember.name,
|
||||
isContact: !!this.getContactFor(decryptedMember.did),
|
||||
member: {
|
||||
memberId: decryptedMember.member.memberId.toString(),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the admit pending members dialog if conditions are met
|
||||
*/
|
||||
checkAndShowAdmitPendingDialog(showPendingEvenIfAllWereIgnored = false) {
|
||||
async refreshData(bypassPromptIfAllWereIgnored = true) {
|
||||
// Force refresh both contacts and members
|
||||
this.contacts = await this.$getAllContacts();
|
||||
await this.fetchMembers();
|
||||
|
||||
const pendingMembers = this.isOrganizer
|
||||
? this.getPendingMembers()
|
||||
? this.getPendingMembersToAdmit()
|
||||
: this.getNonContactMembers();
|
||||
if (pendingMembers.length === 0) {
|
||||
this.startAutoRefresh();
|
||||
return;
|
||||
}
|
||||
if (!showPendingEvenIfAllWereIgnored) {
|
||||
if (bypassPromptIfAllWereIgnored) {
|
||||
// only show if there are pending members that have not been ignored
|
||||
const pendingMembersNotIgnored = pendingMembers.filter(
|
||||
(member) => !this.previousMemberDidsIgnored.includes(member.did),
|
||||
@@ -528,31 +514,21 @@ export default class MembersList extends Vue {
|
||||
}
|
||||
}
|
||||
this.stopAutoRefresh();
|
||||
this.pendingMembersData = pendingMembers;
|
||||
if (this.isOrganizer) {
|
||||
(
|
||||
this.$refs.admitPendingMembersDialog as AdmitPendingMembersDialog
|
||||
).open();
|
||||
).open(pendingMembers);
|
||||
} else {
|
||||
this.visibleBulkVisibilityDialog = true;
|
||||
(
|
||||
this.$refs.setBulkVisibilityDialog as SetBulkVisibilityDialog
|
||||
).open(pendingMembers);
|
||||
}
|
||||
}
|
||||
|
||||
// Admit Pending Members Dialog methods
|
||||
async closeAdmitPendingDialog(
|
||||
async closeMemberSelectionDialogCallback(
|
||||
result: { notSelectedMemberDids: string[] } | undefined,
|
||||
) {
|
||||
this.pendingMembersData = [];
|
||||
this.previousMemberDidsIgnored = result?.notSelectedMemberDids || [];
|
||||
|
||||
await this.refreshData();
|
||||
}
|
||||
|
||||
async closeSetBulkVisibilityDialog(
|
||||
result: { notSelectedMemberDids: string[] } | undefined,
|
||||
) {
|
||||
this.visibleBulkVisibilityDialog = false;
|
||||
this.pendingMembersData = [];
|
||||
this.previousMemberDidsIgnored = result?.notSelectedMemberDids || [];
|
||||
|
||||
await this.refreshData();
|
||||
@@ -697,6 +673,7 @@ export default class MembersList extends Vue {
|
||||
}
|
||||
|
||||
startAutoRefresh() {
|
||||
this.stopAutoRefresh();
|
||||
this.lastRefreshTime = Date.now();
|
||||
this.countdownTimer = 10;
|
||||
|
||||
@@ -726,17 +703,6 @@ export default class MembersList extends Vue {
|
||||
}
|
||||
}
|
||||
|
||||
async manualRefresh() {
|
||||
// Clear existing auto-refresh interval
|
||||
if (this.autoRefreshInterval) {
|
||||
clearInterval(this.autoRefreshInterval);
|
||||
this.autoRefreshInterval = null;
|
||||
}
|
||||
|
||||
// Trigger immediate refresh
|
||||
await this.refreshData(true);
|
||||
}
|
||||
|
||||
beforeDestroy() {
|
||||
this.stopAutoRefresh();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user