You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
343 lines
9.2 KiB
343 lines
9.2 KiB
<template>
|
|
<QuickNav selected="Contacts" />
|
|
<TopMessage />
|
|
|
|
<section id="Content" class="p-6 pb-24 max-w-3xl mx-auto">
|
|
<!-- Heading -->
|
|
<h1 id="ViewHeading" class="text-4xl text-center font-light mb-8">
|
|
Onboarding Meetings
|
|
</h1>
|
|
|
|
<!-- Loading State -->
|
|
<div v-if="isLoading" class="flex justify-center items-center py-8">
|
|
<font-awesome icon="spinner" class="fa-spin-pulse" />
|
|
</div>
|
|
|
|
<div v-else-if="attendingMeeting">
|
|
<p>You are in this meeting.</p>
|
|
<div
|
|
class="p-4 bg-white rounded-lg shadow hover:shadow-md transition-shadow cursor-pointer"
|
|
@click="promptPassword(attendingMeeting)"
|
|
>
|
|
<div class="flex justify-between items-center">
|
|
<h2 class="text-xl font-medium">{{ attendingMeeting.name }}</h2>
|
|
<button
|
|
@click.stop="leaveMeeting"
|
|
class="text-red-600 hover:text-red-700 p-2"
|
|
title="Leave Meeting"
|
|
>
|
|
<font-awesome icon="right-from-bracket" />
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Meeting List -->
|
|
<div v-else class="space-y-4">
|
|
<div
|
|
v-for="meeting in meetings"
|
|
:key="meeting.groupId"
|
|
class="p-4 bg-white rounded-lg shadow hover:shadow-md transition-shadow cursor-pointer"
|
|
@click="promptPassword(meeting)"
|
|
>
|
|
<h2 class="text-xl font-medium">{{ meeting.name }}</h2>
|
|
</div>
|
|
|
|
<p v-if="meetings.length === 0" class="text-center text-gray-500 py-8">
|
|
No onboarding meetings available
|
|
</p>
|
|
</div>
|
|
|
|
<!-- Password Dialog -->
|
|
<div
|
|
v-if="showPasswordDialog"
|
|
class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center p-4"
|
|
>
|
|
<div class="bg-white rounded-lg p-6 max-w-sm w-full">
|
|
<h3 class="text-lg font-medium mb-4">Enter Meeting Password</h3>
|
|
<input
|
|
ref="passwordInput"
|
|
v-model="password"
|
|
type="text"
|
|
class="w-full px-3 py-2 border rounded-md mb-4"
|
|
placeholder="Enter password"
|
|
@keyup.enter="submitPassword"
|
|
/>
|
|
<div class="flex justify-end space-x-4">
|
|
<button
|
|
@click="cancelPasswordDialog"
|
|
class="px-4 py-2 bg-gray-200 rounded hover:bg-gray-300"
|
|
>
|
|
Cancel
|
|
</button>
|
|
<button
|
|
@click="submitPassword"
|
|
class="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700"
|
|
>
|
|
Submit
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</template>
|
|
|
|
<script lang="ts">
|
|
import { Component, Vue } from "vue-facing-decorator";
|
|
import { nextTick } from "vue";
|
|
import { Router } from "vue-router";
|
|
|
|
import QuickNav from "../components/QuickNav.vue";
|
|
import TopMessage from "../components/TopMessage.vue";
|
|
import { logConsoleAndDb, retrieveSettingsForActiveAccount } from "../db/index";
|
|
import {
|
|
errorStringForLog,
|
|
getHeaders,
|
|
serverMessageForUser,
|
|
} from "../libs/endorserServer";
|
|
import { encryptMessage } from "../libs/crypto";
|
|
|
|
interface Meeting {
|
|
name: string;
|
|
groupId: number;
|
|
}
|
|
|
|
@Component({
|
|
components: {
|
|
QuickNav,
|
|
TopMessage,
|
|
},
|
|
})
|
|
export default class OnboardMeetingListView extends Vue {
|
|
$notify!: (
|
|
notification: {
|
|
group: string;
|
|
type: string;
|
|
title: string;
|
|
text: string;
|
|
onYes?: () => void;
|
|
yesText?: string;
|
|
},
|
|
timeout?: number,
|
|
) => void;
|
|
|
|
activeDid = "";
|
|
apiServer = "";
|
|
attendingMeeting: Meeting | null = null;
|
|
firstName = "";
|
|
isLoading = false;
|
|
isRegistered = false;
|
|
meetings: Meeting[] = [];
|
|
password = "";
|
|
selectedMeeting: Meeting | null = null;
|
|
showPasswordDialog = false;
|
|
|
|
async created() {
|
|
const settings = await retrieveSettingsForActiveAccount();
|
|
this.activeDid = settings.activeDid || "";
|
|
this.apiServer = settings.apiServer || "";
|
|
this.firstName = settings.firstName || "";
|
|
this.isRegistered = !!settings.isRegistered;
|
|
await this.fetchMeetings();
|
|
}
|
|
|
|
async fetchMeetings() {
|
|
this.isLoading = true;
|
|
try {
|
|
// get the meeting that the user is attending
|
|
const headers = await getHeaders(this.activeDid);
|
|
const response = await this.axios.get(
|
|
this.apiServer + "/api/partner/groupOnboardMember",
|
|
{ headers },
|
|
);
|
|
|
|
if (response.data?.data) {
|
|
// they're in a meeting already
|
|
const attendingMeetingId = response.data.data.groupId;
|
|
// retrieve the meeting details
|
|
const headers2 = await getHeaders(this.activeDid);
|
|
const response2 = await this.axios.get(
|
|
this.apiServer + "/api/partner/groupOnboard/" + attendingMeetingId,
|
|
{ headers: headers2 },
|
|
);
|
|
|
|
if (response2.data?.data) {
|
|
this.attendingMeeting = response2.data.data;
|
|
return;
|
|
} else {
|
|
// this should never happen
|
|
logConsoleAndDb(
|
|
"Error fetching meeting for user after saying they are in one.",
|
|
true,
|
|
);
|
|
}
|
|
}
|
|
|
|
const headers2 = await getHeaders(this.activeDid);
|
|
const response2 = await this.axios.get(
|
|
this.apiServer + "/api/partner/groupsOnboarding",
|
|
{ headers: headers2 },
|
|
);
|
|
|
|
if (response2.data?.data) {
|
|
this.meetings = response2.data.data;
|
|
}
|
|
} catch (error) {
|
|
logConsoleAndDb(
|
|
"Error fetching meetings: " + errorStringForLog(error),
|
|
true,
|
|
);
|
|
this.$notify(
|
|
{
|
|
group: "alert",
|
|
type: "danger",
|
|
title: "Error",
|
|
text: serverMessageForUser(error) || "Failed to fetch meetings.",
|
|
},
|
|
5000,
|
|
);
|
|
} finally {
|
|
this.isLoading = false;
|
|
}
|
|
}
|
|
|
|
promptPassword(meeting: Meeting) {
|
|
this.password = "";
|
|
this.selectedMeeting = meeting;
|
|
this.showPasswordDialog = true;
|
|
nextTick(() => {
|
|
const input = this.$refs.passwordInput as HTMLInputElement;
|
|
if (input) {
|
|
input.focus();
|
|
}
|
|
});
|
|
}
|
|
|
|
cancelPasswordDialog() {
|
|
this.password = "";
|
|
this.selectedMeeting = null;
|
|
this.showPasswordDialog = false;
|
|
}
|
|
|
|
async submitPassword() {
|
|
if (!this.selectedMeeting) {
|
|
// this should never happen
|
|
logConsoleAndDb(
|
|
"No meeting selected when prompting for password, which should never happen.",
|
|
true,
|
|
);
|
|
return;
|
|
}
|
|
|
|
try {
|
|
// Create member data object
|
|
const memberData = {
|
|
name: this.firstName,
|
|
did: this.activeDid,
|
|
isRegistered: this.isRegistered,
|
|
};
|
|
const memberDataString = JSON.stringify(memberData);
|
|
const encryptedMemberData = await encryptMessage(
|
|
memberDataString,
|
|
this.password,
|
|
);
|
|
|
|
// Get headers for authentication
|
|
const headers = await getHeaders(this.activeDid);
|
|
|
|
// Encrypt the member data
|
|
const postResult = await this.axios.post(
|
|
this.apiServer + "/api/partner/groupOnboardMember",
|
|
{
|
|
groupId: this.selectedMeeting.groupId,
|
|
content: encryptedMemberData,
|
|
},
|
|
{ headers },
|
|
);
|
|
|
|
if (postResult.data && postResult.data.success) {
|
|
// Navigate to members view with password and groupId
|
|
(this.$router as Router).push({
|
|
name: "onboard-meeting-members",
|
|
params: {
|
|
groupId: this.selectedMeeting.groupId.toString(),
|
|
},
|
|
query: {
|
|
password: this.password,
|
|
memberId: postResult.data.memberId,
|
|
},
|
|
});
|
|
|
|
this.cancelPasswordDialog();
|
|
} else {
|
|
throw { response: postResult };
|
|
}
|
|
} catch (error) {
|
|
logConsoleAndDb(
|
|
"Error joining meeting: " + errorStringForLog(error),
|
|
true,
|
|
);
|
|
this.$notify(
|
|
{
|
|
group: "alert",
|
|
type: "danger",
|
|
title: "Error",
|
|
text:
|
|
serverMessageForUser(error) || "You failed to join the meeting.",
|
|
},
|
|
5000,
|
|
);
|
|
}
|
|
}
|
|
|
|
async leaveMeeting() {
|
|
this.$notify(
|
|
{
|
|
group: "modal",
|
|
type: "confirm",
|
|
title: "Leave Meeting",
|
|
text: "Are you sure you want to leave this meeting?",
|
|
onYes: async () => {
|
|
try {
|
|
const headers = await getHeaders(this.activeDid);
|
|
await this.axios.delete(
|
|
this.apiServer + "/api/partner/groupOnboardMember",
|
|
{ headers },
|
|
);
|
|
|
|
this.attendingMeeting = null;
|
|
await this.fetchMeetings();
|
|
|
|
this.$notify(
|
|
{
|
|
group: "alert",
|
|
type: "success",
|
|
title: "Success",
|
|
text: "You left the meeting.",
|
|
},
|
|
5000,
|
|
);
|
|
} catch (error) {
|
|
logConsoleAndDb(
|
|
"Error leaving meeting: " + errorStringForLog(error),
|
|
true,
|
|
);
|
|
this.$notify(
|
|
{
|
|
group: "alert",
|
|
type: "danger",
|
|
title: "Error",
|
|
text:
|
|
serverMessageForUser(error) ||
|
|
"You failed to leave the meeting.",
|
|
},
|
|
5000,
|
|
);
|
|
}
|
|
},
|
|
},
|
|
-1,
|
|
);
|
|
}
|
|
}
|
|
</script>
|
|
|