Browse Source

make member view available to onboard meeting organizer and reorganize buttons

master
Trent Larson 2 days ago
parent
commit
fe71c3f754
  1. 261
      src/components/MembersList.vue
  2. 15
      src/libs/util.ts
  3. 17
      src/views/ContactsView.vue
  4. 2
      src/views/OnboardMeetingSetupView.vue

261
src/components/MembersList.vue

@ -27,37 +27,36 @@
v-if="showOrganizerTools && isOrganizer" v-if="showOrganizerTools && isOrganizer"
class="inline-flex items-center flex-wrap" class="inline-flex items-center flex-wrap"
> >
<span>Use these next to each person to add/remove them to/from the</span> <span class="inline-flex items-center">
<span class="inline-flex items-center whitespace-nowrap"> Use
<span>&nbsp;meeting:</span>
<span <span
class="ml-2 w-6 h-6 flex items-center justify-center rounded-full bg-blue-100 text-blue-600 hover:bg-blue-200 hover:text-blue-800 transition-colors" class="mx-2 min-w-[24px] min-h-[24px] w-6 h-6 flex items-center justify-center rounded-full bg-blue-100 text-blue-600"
> >
<fa icon="plus" class="text-sm" /> <fa icon="plus" class="text-sm" />
</span> </span>
and
<span <span
class="ml-2 w-6 h-6 flex items-center justify-center rounded-full bg-blue-100 text-blue-600 hover:bg-blue-200 hover:text-blue-800 transition-colors" class="mx-2 min-w-[24px] min-h-[24px] w-6 h-6 flex items-center justify-center rounded-full bg-blue-100 text-blue-600"
> >
<fa icon="minus" class="text-sm" /> <fa icon="minus" class="text-sm" />
</span> </span>
to add/remove them to/from the meeting.
</span> </span>
</span> </span>
</div> </div>
<div> <div>
<span class="inline-flex items-center flex-wrap"> <span class="inline-flex items-center">
<span>Use this next to each person to add them to your</span> Use
<span class="inline-flex items-center whitespace-nowrap"> <span
<span>&nbsp;contacts:</span> class="mx-2 w-8 h-8 flex items-center justify-center rounded-full bg-green-100 text-green-600"
<span >
class="ml-2 w-8 h-8 flex items-center justify-center rounded-full bg-green-100 text-green-600" <fa icon="circle-user" class="text-xl" />
>
<fa icon="circle-user" class="text-xl" />
</span>
</span> </span>
to add them to your contacts.
</span> </span>
</div> </div>
<div v-if="members.length > 0" class="flex justify-end"> <div v-if="members.length > 0" class="flex justify-center">
<button <button
@click="fetchMembers" @click="fetchMembers"
class="w-8 h-8 flex items-center justify-center rounded-full bg-blue-100 text-blue-600 hover:bg-blue-200 hover:text-blue-800 transition-colors" class="w-8 h-8 flex items-center justify-center rounded-full bg-blue-100 text-blue-600 hover:bg-blue-200 hover:text-blue-800 transition-colors"
@ -67,13 +66,37 @@
</button> </button>
</div> </div>
<div <div
v-for="member in decryptedMembers" v-for="member in membersToShow()"
:key="member.member.memberId" :key="member.member.memberId"
class="p-4 bg-gray-50 rounded-lg" class="p-4 bg-gray-50 rounded-lg"
> >
<div class="flex items-center justify-between"> <div class="flex items-center justify-between">
<div class="flex"> <div class="flex items-center">
<h3 class="text-lg font-medium">{{ member.name }}</h3> <h3 class="text-lg font-medium">{{ member.name }}</h3>
<div
v-if="!isContactAlready(member.did) && member.did !== activeDid"
class="flex justify-end"
>
<button
@click="addAsContact(member)"
class="ml-2 w-8 h-8 flex items-center justify-center rounded-full bg-green-100 text-green-600 hover:bg-green-200 hover:text-green-800 transition-colors"
title="Add as contact"
>
<fa icon="circle-user" class="text-xl" />
</button>
</div>
<button
v-if="member.did !== activeDid"
@click="
informAboutAddingContact(isContactAlready(member.did))
"
class="ml-2 mb-2 w-6 h-6 flex items-center justify-center rounded-full bg-slate-100 text-slate-500 hover:bg-slate-200 hover:text-slate-800 transition-colors"
title="Contact info"
>
<fa icon="circle-info" class="text-base" />
</button>
</div>
<div class="flex">
<span <span
v-if=" v-if="
showOrganizerTools && isOrganizer && member.did !== activeDid showOrganizerTools && isOrganizer && member.did !== activeDid
@ -82,7 +105,7 @@
> >
<button <button
@click="toggleAdmission(member)" @click="toggleAdmission(member)"
class="ml-2 w-6 h-6 flex items-center justify-center rounded-full bg-blue-100 text-blue-600 hover:bg-blue-200 hover:text-blue-800 transition-colors" class="mr-2 w-6 h-6 flex items-center justify-center rounded-full bg-blue-100 text-blue-600 hover:bg-blue-200 hover:text-blue-800 transition-colors"
:title=" :title="
member.member.admitted ? 'Remove member' : 'Admit member' member.member.admitted ? 'Remove member' : 'Admit member'
" "
@ -94,36 +117,19 @@
</button> </button>
<button <button
@click="informAboutAdmission()" @click="informAboutAdmission()"
class="ml-2 mb-2 w-6 h-6 flex items-center justify-center rounded-full bg-gray-100 text-gray-600 hover:bg-gray-200 hover:text-gray-800 transition-colors" class="mr-2 mb-2 w-6 h-6 flex items-center justify-center rounded-full bg-slate-100 text-slate-500 hover:bg-slate-200 hover:text-slate-800 transition-colors"
title="Admission info" title="Admission info"
> >
<fa icon="circle-info" class="text-base" /> <fa icon="circle-info" class="text-base" />
</button> </button>
</span> </span>
</div> </div>
<div
v-if="!isContactAlready(member.did) && member.did !== activeDid"
class="flex justify-end"
>
<button
@click="addAsContact(member)"
class="ml-1 w-8 h-8 flex items-center justify-center rounded-full bg-green-100 text-green-600 hover:bg-green-200 hover:text-green-800 transition-colors"
title="Add as contact"
>
<fa icon="circle-user" class="text-xl" />
</button>
<button
@click="informAboutAddingContact()"
class="ml-2 w-6 h-6 flex items-center justify-center rounded-full bg-gray-100 text-gray-600 hover:bg-gray-200 hover:text-gray-800 transition-colors"
title="Contact info"
>
<fa icon="circle-info" class="text-base" />
</button>
</div>
</div> </div>
<p class="text-sm text-gray-600">{{ member.did }}</p> <p class="text-sm text-gray-600 truncate">
{{ member.did }}
</p>
</div> </div>
<div v-if="members.length > 0" class="flex justify-end mt-4"> <div v-if="members.length > 0" class="flex justify-center mt-4">
<button <button
@click="fetchMembers" @click="fetchMembers"
class="w-8 h-8 flex items-center justify-center rounded-full bg-blue-100 text-blue-600 hover:bg-blue-200 hover:text-blue-800 transition-colors" class="w-8 h-8 flex items-center justify-center rounded-full bg-blue-100 text-blue-600 hover:bg-blue-200 hover:text-blue-800 transition-colors"
@ -156,6 +162,7 @@ import {
} from "@/libs/endorserServer"; } from "@/libs/endorserServer";
import { decryptMessage } from "@/libs/crypto"; import { decryptMessage } from "@/libs/crypto";
import { Contact } from "@/db/tables/contacts"; import { Contact } from "@/db/tables/contacts";
import * as libsUtil from "@/libs/util";
interface Member { interface Member {
admitted: boolean; admitted: boolean;
@ -177,6 +184,8 @@ export default class MembersList extends Vue {
timeout?: number, timeout?: number,
) => void; ) => void;
libsUtil = libsUtil;
@Prop({ required: true }) password!: string; @Prop({ required: true }) password!: string;
@Prop({ default: "Your password failed. Please go back and try again." }) @Prop({ default: "Your password failed. Please go back and try again." })
decryptFailureMessage!: string; decryptFailureMessage!: string;
@ -192,69 +201,6 @@ export default class MembersList extends Vue {
apiServer = ""; apiServer = "";
contacts: Array<Contact> = []; contacts: Array<Contact> = [];
async toggleAdmission(member: DecryptedMember) {
try {
const headers = await getHeaders(this.activeDid);
await this.axios.put(
`${this.apiServer}/api/partner/groupOnboardMember/${member.member.memberId}`,
{ admitted: !member.member.admitted },
{ headers },
);
// Update local state
member.member.admitted = !member.member.admitted;
// if admitted, now register that user if they are not registered
if (member.member.admitted && !member.member.registered) {
const contact = {
did: member.did,
name: member.name,
};
const result = await register(
this.activeDid,
this.apiServer,
this.axios,
contact,
);
if (result.success) {
member.member.registered = true;
await db.contacts.update(member.did, { registered: true });
this.$notify(
{
group: "alert",
type: "success",
title: "Registered",
text: "Besides being admitted, they were also registered.",
},
3000,
);
} else {
const additionalInfo = result.error || "";
this.$notify(
{
group: "alert",
type: "danger",
title: "Registration failed",
text:
"They were admitted, but registration failed. You can try again, or register from your contacts screen. " +
additionalInfo,
},
10000,
);
}
}
} catch (error) {
logConsoleAndDb(
"Error toggling admission: " + errorStringForLog(error),
true,
);
this.$emit(
"error",
serverMessageForUser(error) ||
"Failed to update member admission status.",
);
}
}
async created() { async created() {
const settings = await retrieveSettingsForActiveAccount(); const settings = await retrieveSettingsForActiveAccount();
this.activeDid = settings.activeDid || ""; this.activeDid = settings.activeDid || "";
@ -327,6 +273,20 @@ export default class MembersList extends Vue {
this.missingMyself = !foundMyself; this.missingMyself = !foundMyself;
} }
membersToShow(): DecryptedMember[] {
if (this.isOrganizer) {
if (this.showOrganizerTools) {
return this.decryptedMembers;
} else {
return this.decryptedMembers.filter(
(member: DecryptedMember) => member.member.admitted,
);
}
}
// non-organizers only get visible members from server
return this.decryptedMembers;
}
informAboutAdmission() { informAboutAdmission() {
this.$notify( this.$notify(
{ {
@ -339,16 +299,28 @@ export default class MembersList extends Vue {
); );
} }
informAboutAddingContact() { informAboutAddingContact(isContactAlready: boolean) {
this.$notify( if (isContactAlready) {
{ this.$notify(
group: "alert", {
type: "info", group: "alert",
title: "Contact info", type: "info",
text: "This is to add people to your contacts. If you want to remove them, you must do that from the contacts screen.", title: "Contact Exists",
}, text: "They are in your contacts. If you want to remove them, you must do that from the contacts screen.",
10000, },
); 10000,
);
} else {
this.$notify(
{
group: "alert",
type: "info",
title: "Contact Available",
text: "This is to add them to your contacts. If you want to remove them later, you must do that from the contacts screen.",
},
10000,
);
}
} }
async loadContacts() { async loadContacts() {
@ -359,6 +331,69 @@ export default class MembersList extends Vue {
return this.contacts.some((contact) => contact.did === did); return this.contacts.some((contact) => contact.did === did);
} }
async toggleAdmission(member: DecryptedMember) {
try {
const headers = await getHeaders(this.activeDid);
await this.axios.put(
`${this.apiServer}/api/partner/groupOnboardMember/${member.member.memberId}`,
{ admitted: !member.member.admitted },
{ headers },
);
// Update local state
member.member.admitted = !member.member.admitted;
// if admitted, now register that user if they are not registered
if (member.member.admitted && !member.member.registered) {
const contact = {
did: member.did,
name: member.name,
};
const result = await register(
this.activeDid,
this.apiServer,
this.axios,
contact,
);
if (result.success) {
member.member.registered = true;
await db.contacts.update(member.did, { registered: true });
this.$notify(
{
group: "alert",
type: "success",
title: "Registered",
text: "Besides being admitted, they were also registered.",
},
3000,
);
} else {
const additionalInfo = result.error || "";
this.$notify(
{
group: "alert",
type: "danger",
title: "Registration failed",
text:
"They were admitted, but registration failed. You can try again, or register from your contacts screen. " +
additionalInfo,
},
10000,
);
}
}
} catch (error) {
logConsoleAndDb(
"Error toggling admission: " + errorStringForLog(error),
true,
);
this.$emit(
"error",
serverMessageForUser(error) ||
"Failed to update member admission status.",
);
}
}
async addAsContact(member: DecryptedMember) { async addAsContact(member: DecryptedMember) {
try { try {
const newContact = { const newContact = {

15
src/libs/util.ts

@ -112,6 +112,21 @@ export const isGiveAction = (
return isGiveClaimType(veriClaim.claimType); return isGiveClaimType(veriClaim.claimType);
}; };
export const shortDid = (did: string) => {
if (did.startsWith("did:peer:")) {
return (
did.substring(0, "did:peer:".length + 2) +
"..." +
did.substring("did:peer:".length + 18, "did:peer:".length + 25) +
"..."
);
} else if (did.startsWith("did:ethr:")) {
return did.substring(0, "did:ethr:".length + 9) + "...";
} else {
return did.substring(0, did.indexOf(":", 4) + 7) + "...";
}
}
export const nameForDid = ( export const nameForDid = (
activeDid: string, activeDid: string,
contacts: Array<Contact>, contacts: Array<Contact>,

17
src/views/ContactsView.vue

@ -219,7 +219,7 @@
</router-link> </router-link>
<span class="ml-4 text-sm overflow-hidden">{{ <span class="ml-4 text-sm overflow-hidden">{{
shortDid(contact.did) libsUtil.shortDid(contact.did)
}}</span> }}</span>
</div> </div>
<div class="ml-4 text-sm"> <div class="ml-4 text-sm">
@ -1373,21 +1373,6 @@ export default class ContactsView extends Vue {
}); });
} }
private shortDid(did: string) {
if (did.startsWith("did:peer:")) {
return (
did.substring(0, "did:peer:".length + 2) +
"..." +
did.substring("did:peer:".length + 18, "did:peer:".length + 25) +
"..."
);
} else if (did.startsWith("did:ethr:")) {
return did.substring(0, "did:ethr:".length + 9) + "...";
} else {
return did.substring(0, did.indexOf(":", 4) + 7) + "...";
}
}
private showCopySelectionsInfo() { private showCopySelectionsInfo() {
this.$notify( this.$notify(
{ {

2
src/views/OnboardMeetingSetupView.vue

@ -265,7 +265,7 @@ export default class OnboardMeetingView extends Vue {
) => void; ) => void;
DECRYPT_FAILURE_MESSAGE = DECRYPT_FAILURE_MESSAGE =
"Unable to decrypt some member information. Check your password, or have them reset theirs."; "Unable to decrypt some member information. Check your password, or have them reset theirs if they don't show here.";
currentMeeting: ServerMeeting | null = null; currentMeeting: ServerMeeting | null = null;
newOrUpdatedMeeting: MeetingSetupInfo | null = null; newOrUpdatedMeeting: MeetingSetupInfo | null = null;

Loading…
Cancel
Save