|
|
|
@ -1,198 +1,202 @@ |
|
|
|
<template> |
|
|
|
<div> |
|
|
|
<div class="space-y-4"> |
|
|
|
<!-- Loading State --> |
|
|
|
<div |
|
|
|
v-if="isLoading" |
|
|
|
class="mt-16 text-center text-4xl bg-slate-400 text-white w-14 py-2.5 rounded-full mx-auto" |
|
|
|
> |
|
|
|
<font-awesome icon="spinner" class="fa-spin-pulse" /> |
|
|
|
</div> |
|
|
|
|
|
|
|
<!-- Members List --> |
|
|
|
|
|
|
|
<div v-else> |
|
|
|
<div class="text-center text-red-600 my-4"> |
|
|
|
{{ decryptionErrorMessage() }} |
|
|
|
</div> |
|
|
|
|
|
|
|
<div v-if="missingMyself" class="py-4 text-red-600"> |
|
|
|
You are not currently admitted by the organizer. |
|
|
|
</div> |
|
|
|
<div v-if="!firstName" class="py-4 text-red-600"> |
|
|
|
Your name is not set, so others may not recognize you. Reload this page |
|
|
|
to set it. |
|
|
|
<div> |
|
|
|
<div class="space-y-4"> |
|
|
|
<!-- Loading State --> |
|
|
|
<div |
|
|
|
v-if="isLoading" |
|
|
|
class="mt-16 text-center text-4xl bg-slate-400 text-white w-14 py-2.5 rounded-full mx-auto" |
|
|
|
> |
|
|
|
<font-awesome icon="spinner" class="fa-spin-pulse" /> |
|
|
|
</div> |
|
|
|
|
|
|
|
<ul class="list-disc text-sm ps-4 space-y-2 mb-4"> |
|
|
|
<li |
|
|
|
v-if="membersToShow().length > 0 && showOrganizerTools && isOrganizer" |
|
|
|
> |
|
|
|
Click |
|
|
|
<font-awesome icon="circle-plus" class="text-blue-500 text-sm" /> |
|
|
|
/ |
|
|
|
<font-awesome icon="circle-minus" class="text-rose-500 text-sm" /> |
|
|
|
to add/remove them to/from the meeting. |
|
|
|
</li> |
|
|
|
<li v-if="membersToShow().length > 0"> |
|
|
|
Click |
|
|
|
<font-awesome icon="circle-user" class="text-green-600 text-sm" /> |
|
|
|
to add them to your contacts. |
|
|
|
</li> |
|
|
|
</ul> |
|
|
|
|
|
|
|
<div class="flex justify-between"> |
|
|
|
<!-- |
|
|
|
<!-- Members List --> |
|
|
|
|
|
|
|
<div v-else> |
|
|
|
<div class="text-center text-red-600 my-4"> |
|
|
|
{{ decryptionErrorMessage() }} |
|
|
|
</div> |
|
|
|
|
|
|
|
<div v-if="missingMyself" class="py-4 text-red-600"> |
|
|
|
You are not currently admitted by the organizer. |
|
|
|
</div> |
|
|
|
<div v-if="!firstName" class="py-4 text-red-600"> |
|
|
|
Your name is not set, so others may not recognize you. Reload this |
|
|
|
page to set it. |
|
|
|
</div> |
|
|
|
|
|
|
|
<ul class="list-disc text-sm ps-4 space-y-2 mb-4"> |
|
|
|
<li |
|
|
|
v-if=" |
|
|
|
membersToShow().length > 0 && showOrganizerTools && isOrganizer |
|
|
|
" |
|
|
|
> |
|
|
|
Click |
|
|
|
<font-awesome icon="circle-plus" class="text-blue-500 text-sm" /> |
|
|
|
/ |
|
|
|
<font-awesome icon="circle-minus" class="text-rose-500 text-sm" /> |
|
|
|
to add/remove them to/from the meeting. |
|
|
|
</li> |
|
|
|
<li v-if="membersToShow().length > 0"> |
|
|
|
Click |
|
|
|
<font-awesome icon="circle-user" class="text-green-600 text-sm" /> |
|
|
|
to add them to your contacts. |
|
|
|
</li> |
|
|
|
</ul> |
|
|
|
|
|
|
|
<div class="flex justify-between"> |
|
|
|
<!-- |
|
|
|
always have at least one refresh button even without members in case the organizer |
|
|
|
changes the password |
|
|
|
--> |
|
|
|
<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="refreshData(false)" |
|
|
|
<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="refreshData(false)" |
|
|
|
> |
|
|
|
<font-awesome icon="rotate" :class="{ 'fa-spin': isLoading }" /> |
|
|
|
Refresh |
|
|
|
<span class="text-xs">({{ countdownTimer }}s)</span> |
|
|
|
</button> |
|
|
|
</div> |
|
|
|
<ul |
|
|
|
v-if="membersToShow().length > 0" |
|
|
|
class="border-t border-slate-300 my-2" |
|
|
|
> |
|
|
|
<font-awesome icon="rotate" :class="{ 'fa-spin': isLoading }" /> |
|
|
|
Refresh |
|
|
|
<span class="text-xs">({{ countdownTimer }}s)</span> |
|
|
|
</button> |
|
|
|
</div> |
|
|
|
<ul |
|
|
|
v-if="membersToShow().length > 0" |
|
|
|
class="border-t border-slate-300 my-2" |
|
|
|
> |
|
|
|
<li |
|
|
|
v-for="member in membersToShow()" |
|
|
|
:key="member.member.memberId" |
|
|
|
:class="[ |
|
|
|
'border-b px-2 sm:px-3 py-1.5', |
|
|
|
{ |
|
|
|
'bg-blue-50 border-t border-blue-300 -mt-[1px]': |
|
|
|
!member.member.admitted && isOrganizer, |
|
|
|
}, |
|
|
|
{ 'border-slate-300': member.member.admitted }, |
|
|
|
]" |
|
|
|
> |
|
|
|
<div class="flex items-center gap-2 justify-between"> |
|
|
|
<div class="flex items-center gap-1 overflow-hidden"> |
|
|
|
<h3 |
|
|
|
:class="[ |
|
|
|
'font-semibold truncate', |
|
|
|
{ 'text-slate-500': !member.member.admitted && isOrganizer }, |
|
|
|
]" |
|
|
|
> |
|
|
|
<font-awesome |
|
|
|
v-if="member.member.memberId === members[0]?.memberId" |
|
|
|
icon="crown" |
|
|
|
class="fa-fw text-amber-400" |
|
|
|
/> |
|
|
|
<font-awesome |
|
|
|
v-if="!member.member.admitted && isOrganizer" |
|
|
|
icon="hourglass-half" |
|
|
|
class="fa-fw text-slate-400" |
|
|
|
/> |
|
|
|
{{ member.name || unnamedMember }} |
|
|
|
</h3> |
|
|
|
<div |
|
|
|
v-if="!getContactFor(member.did) && member.did !== activeDid" |
|
|
|
class="flex items-center gap-1.5 ms-1" |
|
|
|
<li |
|
|
|
v-for="member in membersToShow()" |
|
|
|
:key="member.member.memberId" |
|
|
|
:class="[ |
|
|
|
'border-b px-2 sm:px-3 py-1.5', |
|
|
|
{ |
|
|
|
'bg-blue-50 border-t border-blue-300 -mt-[1px]': |
|
|
|
!member.member.admitted && isOrganizer, |
|
|
|
}, |
|
|
|
{ 'border-slate-300': member.member.admitted }, |
|
|
|
]" |
|
|
|
> |
|
|
|
<div class="flex items-center gap-2 justify-between"> |
|
|
|
<div class="flex items-center gap-1 overflow-hidden"> |
|
|
|
<h3 |
|
|
|
:class="[ |
|
|
|
'font-semibold truncate', |
|
|
|
{ |
|
|
|
'text-slate-500': !member.member.admitted && isOrganizer, |
|
|
|
}, |
|
|
|
]" |
|
|
|
> |
|
|
|
<font-awesome |
|
|
|
v-if="member.member.memberId === members[0]?.memberId" |
|
|
|
icon="crown" |
|
|
|
class="fa-fw text-amber-400" |
|
|
|
/> |
|
|
|
<font-awesome |
|
|
|
v-if="!member.member.admitted && isOrganizer" |
|
|
|
icon="hourglass-half" |
|
|
|
class="fa-fw text-slate-400" |
|
|
|
/> |
|
|
|
{{ member.name || unnamedMember }} |
|
|
|
</h3> |
|
|
|
<div |
|
|
|
v-if="!getContactFor(member.did) && member.did !== activeDid" |
|
|
|
class="flex items-center gap-1.5 ms-1" |
|
|
|
> |
|
|
|
<button |
|
|
|
class="btn-add-contact" |
|
|
|
title="Add as contact" |
|
|
|
@click="addAsContact(member)" |
|
|
|
> |
|
|
|
<font-awesome icon="circle-user" /> |
|
|
|
</button> |
|
|
|
|
|
|
|
<button |
|
|
|
class="btn-info-contact" |
|
|
|
title="Contact Info" |
|
|
|
@click=" |
|
|
|
informAboutAddingContact( |
|
|
|
getContactFor(member.did) !== undefined, |
|
|
|
) |
|
|
|
" |
|
|
|
> |
|
|
|
<font-awesome icon="circle-info" /> |
|
|
|
</button> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<span |
|
|
|
v-if=" |
|
|
|
showOrganizerTools && isOrganizer && member.did !== activeDid |
|
|
|
" |
|
|
|
class="flex items-center gap-1.5" |
|
|
|
> |
|
|
|
<button |
|
|
|
class="btn-add-contact" |
|
|
|
title="Add as contact" |
|
|
|
@click="addAsContact(member)" |
|
|
|
:class=" |
|
|
|
member.member.admitted |
|
|
|
? 'btn-admission-remove' |
|
|
|
: 'btn-admission-add' |
|
|
|
" |
|
|
|
:title=" |
|
|
|
member.member.admitted ? 'Remove member' : 'Admit member' |
|
|
|
" |
|
|
|
@click="checkWhetherContactBeforeAdmitting(member)" |
|
|
|
> |
|
|
|
<font-awesome icon="circle-user" /> |
|
|
|
<font-awesome |
|
|
|
:icon=" |
|
|
|
member.member.admitted ? 'circle-minus' : 'circle-plus' |
|
|
|
" |
|
|
|
/> |
|
|
|
</button> |
|
|
|
|
|
|
|
<button |
|
|
|
class="btn-info-contact" |
|
|
|
title="Contact Info" |
|
|
|
@click=" |
|
|
|
informAboutAddingContact( |
|
|
|
getContactFor(member.did) !== undefined, |
|
|
|
) |
|
|
|
" |
|
|
|
class="btn-info-admission" |
|
|
|
title="Admission Info" |
|
|
|
@click="informAboutAdmission()" |
|
|
|
> |
|
|
|
<font-awesome icon="circle-info" /> |
|
|
|
</button> |
|
|
|
</div> |
|
|
|
</span> |
|
|
|
</div> |
|
|
|
<span |
|
|
|
v-if=" |
|
|
|
showOrganizerTools && isOrganizer && member.did !== activeDid |
|
|
|
" |
|
|
|
class="flex items-center gap-1.5" |
|
|
|
> |
|
|
|
<button |
|
|
|
:class=" |
|
|
|
member.member.admitted |
|
|
|
? 'btn-admission-remove' |
|
|
|
: 'btn-admission-add' |
|
|
|
" |
|
|
|
:title=" |
|
|
|
member.member.admitted ? 'Remove member' : 'Admit member' |
|
|
|
" |
|
|
|
@click="checkWhetherContactBeforeAdmitting(member)" |
|
|
|
> |
|
|
|
<font-awesome |
|
|
|
:icon=" |
|
|
|
member.member.admitted ? 'circle-minus' : 'circle-plus' |
|
|
|
" |
|
|
|
/> |
|
|
|
</button> |
|
|
|
|
|
|
|
<button |
|
|
|
class="btn-info-admission" |
|
|
|
title="Admission Info" |
|
|
|
@click="informAboutAdmission()" |
|
|
|
> |
|
|
|
<font-awesome icon="circle-info" /> |
|
|
|
</button> |
|
|
|
</span> |
|
|
|
</div> |
|
|
|
<p class="text-xs text-gray-600 truncate"> |
|
|
|
{{ member.did }} |
|
|
|
</p> |
|
|
|
</li> |
|
|
|
</ul> |
|
|
|
|
|
|
|
<div v-if="membersToShow().length > 0" class="flex justify-between"> |
|
|
|
<!-- |
|
|
|
<p class="text-xs text-gray-600 truncate"> |
|
|
|
{{ member.did }} |
|
|
|
</p> |
|
|
|
</li> |
|
|
|
</ul> |
|
|
|
|
|
|
|
<div v-if="membersToShow().length > 0" class="flex justify-between"> |
|
|
|
<!-- |
|
|
|
always have at least one refresh button even without members in case the organizer |
|
|
|
changes the password |
|
|
|
--> |
|
|
|
<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="refreshData(false)" |
|
|
|
> |
|
|
|
<font-awesome icon="rotate" :class="{ 'fa-spin': isLoading }" /> |
|
|
|
Refresh |
|
|
|
<span class="text-xs">({{ countdownTimer }}s)</span> |
|
|
|
</button> |
|
|
|
<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="refreshData(false)" |
|
|
|
> |
|
|
|
<font-awesome icon="rotate" :class="{ 'fa-spin': isLoading }" /> |
|
|
|
Refresh |
|
|
|
<span class="text-xs">({{ countdownTimer }}s)</span> |
|
|
|
</button> |
|
|
|
</div> |
|
|
|
|
|
|
|
<p v-if="members.length === 0" class="text-gray-500 py-4"> |
|
|
|
No members have joined this meeting yet |
|
|
|
</p> |
|
|
|
</div> |
|
|
|
|
|
|
|
<p v-if="members.length === 0" class="text-gray-500 py-4"> |
|
|
|
No members have joined this meeting yet |
|
|
|
</p> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
<!-- This Admit component is for the organizer to admit pending members to the meeting --> |
|
|
|
<AdmitPendingMembersDialog |
|
|
|
ref="admitPendingMembersDialog" |
|
|
|
:active-did="activeDid" |
|
|
|
:api-server="apiServer" |
|
|
|
@close="closeMemberSelectionDialogCallback" |
|
|
|
/> |
|
|
|
<!-- This Bulk Visibility component is for non-organizer members to add other members to their contacts and set their visibility --> |
|
|
|
<SetBulkVisibilityDialog |
|
|
|
ref="setBulkVisibilityDialog" |
|
|
|
:active-did="activeDid" |
|
|
|
:api-server="apiServer" |
|
|
|
@close="closeMemberSelectionDialogCallback" |
|
|
|
/> |
|
|
|
</div> |
|
|
|
<!-- This Admit component is for the organizer to admit pending members to the meeting --> |
|
|
|
<AdmitPendingMembersDialog |
|
|
|
ref="admitPendingMembersDialog" |
|
|
|
:active-did="activeDid" |
|
|
|
:api-server="apiServer" |
|
|
|
@close="closeMemberSelectionDialogCallback" |
|
|
|
/> |
|
|
|
<!-- This Bulk Visibility component is for non-organizer members to add other members to their contacts and set their visibility --> |
|
|
|
<SetBulkVisibilityDialog |
|
|
|
ref="setBulkVisibilityDialog" |
|
|
|
:active-did="activeDid" |
|
|
|
:api-server="apiServer" |
|
|
|
@close="closeMemberSelectionDialogCallback" |
|
|
|
/> |
|
|
|
</div> |
|
|
|
</template> |
|
|
|
|
|
|
|
<script lang="ts"> |
|
|
|
@ -404,7 +408,7 @@ export default class MembersList extends Vue { |
|
|
|
did: this.activeDid, |
|
|
|
isRegistered: false, |
|
|
|
}; |
|
|
|
const otherMembersPlusUser = [ currentUser, ...this.decryptedMembers ]; |
|
|
|
const otherMembersPlusUser = [currentUser, ...this.decryptedMembers]; |
|
|
|
members = otherMembersPlusUser; |
|
|
|
} |
|
|
|
|
|
|
|
@ -460,16 +464,17 @@ export default class MembersList extends Vue { |
|
|
|
|
|
|
|
getPendingMembersToAdmit(): MemberData[] { |
|
|
|
return this.decryptedMembers |
|
|
|
.filter((member) => |
|
|
|
member.did !== this.activeDid && !member.member.admitted |
|
|
|
.filter( |
|
|
|
(member) => member.did !== this.activeDid && !member.member.admitted, |
|
|
|
) |
|
|
|
.map(this.convertDecryptedMemberToMemberData); |
|
|
|
} |
|
|
|
|
|
|
|
getNonContactMembers(): MemberData[] { |
|
|
|
return this.decryptedMembers |
|
|
|
.filter((member) => |
|
|
|
member.did !== this.activeDid && !this.getContactFor(member.did) |
|
|
|
.filter( |
|
|
|
(member) => |
|
|
|
member.did !== this.activeDid && !this.getContactFor(member.did), |
|
|
|
) |
|
|
|
.map(this.convertDecryptedMemberToMemberData); |
|
|
|
} |
|
|
|
@ -515,13 +520,13 @@ export default class MembersList extends Vue { |
|
|
|
} |
|
|
|
this.stopAutoRefresh(); |
|
|
|
if (this.isOrganizer) { |
|
|
|
( |
|
|
|
this.$refs.admitPendingMembersDialog as AdmitPendingMembersDialog |
|
|
|
).open(pendingMembers); |
|
|
|
(this.$refs.admitPendingMembersDialog as AdmitPendingMembersDialog).open( |
|
|
|
pendingMembers, |
|
|
|
); |
|
|
|
} else { |
|
|
|
( |
|
|
|
this.$refs.setBulkVisibilityDialog as SetBulkVisibilityDialog |
|
|
|
).open(pendingMembers); |
|
|
|
(this.$refs.setBulkVisibilityDialog as SetBulkVisibilityDialog).open( |
|
|
|
pendingMembers, |
|
|
|
); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|