forked from trent_larson/crowd-funder-for-time-pwa
fix linting (and change a little wording in onboarding page)
This commit is contained in:
@@ -22,7 +22,9 @@
|
||||
title="Edit Meeting"
|
||||
>
|
||||
<fa icon="pen" class="fa-fw" />
|
||||
<span class="sr-only">{{ isInCreateMode() ? 'Create Meeting' : 'Edit Meeting' }}</span>
|
||||
<span class="sr-only">{{
|
||||
isInCreateMode() ? "Create Meeting" : "Edit Meeting"
|
||||
}}</span>
|
||||
</button>
|
||||
</div>
|
||||
<button
|
||||
@@ -33,28 +35,41 @@
|
||||
title="Delete Meeting"
|
||||
>
|
||||
<fa icon="trash-can" class="fa-fw" />
|
||||
<span class="sr-only">{{ isDeleting ? 'Deleting...' : 'Delete Meeting' }}</span>
|
||||
<span class="sr-only">{{
|
||||
isDeleting ? "Deleting..." : "Delete Meeting"
|
||||
}}</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<p><strong>Name:</strong> {{ currentMeeting.name }}</p>
|
||||
<p><strong>Expires:</strong> {{ formatExpirationTime(currentMeeting.expiresAt) }}</p>
|
||||
<p>
|
||||
<strong>Expires:</strong>
|
||||
{{ formatExpirationTime(currentMeeting.expiresAt) }}
|
||||
</p>
|
||||
|
||||
<div v-if="currentMeeting.password" class="mt-4">
|
||||
<p class="text-gray-600">Share the password with the people you want to onboard.</p>
|
||||
<p class="text-gray-600">
|
||||
Share the password with the people you want to onboard.
|
||||
</p>
|
||||
</div>
|
||||
<div v-else class="text-red-600">
|
||||
Your copy of the password is not saved. Edit the meeting, or delete it and create a new meeting.
|
||||
Your copy of the password is not saved. Edit the meeting, or delete it
|
||||
and create a new meeting.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Delete Confirmation Dialog -->
|
||||
<div v-if="showDeleteConfirm" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center p-4">
|
||||
<div
|
||||
v-if="showDeleteConfirm"
|
||||
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">Delete Meeting?</h3>
|
||||
<p class="text-gray-600 mb-6">This action cannot be undone. Are you sure you want to delete this meeting?</p>
|
||||
<p class="text-gray-600 mb-6">
|
||||
This action cannot be undone. Are you sure you want to delete this
|
||||
meeting?
|
||||
</p>
|
||||
<div class="flex justify-between space-x-4">
|
||||
<button
|
||||
@click="showDeleteConfirm = false"
|
||||
@@ -74,14 +89,27 @@
|
||||
|
||||
<!-- Create/Edit Meeting Form -->
|
||||
<div
|
||||
v-if="!isLoading && isInEditOrCreateMode() && newOrUpdatedMeeting != null /* duplicate check is for typechecks */"
|
||||
v-if="
|
||||
!isLoading &&
|
||||
isInEditOrCreateMode() &&
|
||||
newOrUpdatedMeeting != null /* duplicate check is for typechecks */
|
||||
"
|
||||
class="mt-8"
|
||||
>
|
||||
<h2 class="text-2xl mb-4">{{ isInCreateMode() ? 'Create New Meeting' : 'Edit Meeting' }}</h2>
|
||||
<!-- This is my first form. Not sure whether I like it or not; gotta see if the browser benefits extend to the native app. -->
|
||||
<form @submit.prevent="isInCreateMode() ? createMeeting() : updateMeeting()" class="space-y-4">
|
||||
<h2 class="text-2xl mb-4">
|
||||
{{ isInCreateMode() ? "Create New Meeting" : "Edit Meeting" }}
|
||||
</h2>
|
||||
<!-- This is my first form. Not sure if I like it; will see if the browser benefits extend to the native app. -->
|
||||
<form
|
||||
@submit.prevent="isInCreateMode() ? createMeeting() : updateMeeting()"
|
||||
class="space-y-4"
|
||||
>
|
||||
<div>
|
||||
<label for="meetingName" class="block text-sm font-medium text-gray-700">Meeting Name</label>
|
||||
<label
|
||||
for="meetingName"
|
||||
class="block text-sm font-medium text-gray-700"
|
||||
>Meeting Name</label
|
||||
>
|
||||
<input
|
||||
id="meetingName"
|
||||
v-model="newOrUpdatedMeeting.name"
|
||||
@@ -93,7 +121,11 @@
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="expirationTime" class="block text-sm font-medium text-gray-700">Meeting Expiration Time</label>
|
||||
<label
|
||||
for="expirationTime"
|
||||
class="block text-sm font-medium text-gray-700"
|
||||
>Meeting Expiration Time</label
|
||||
>
|
||||
<input
|
||||
id="expirationTime"
|
||||
v-model="newOrUpdatedMeeting.expiresAt"
|
||||
@@ -105,7 +137,9 @@
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="password" class="block text-sm font-medium text-gray-700">Meeting Password</label>
|
||||
<label for="password" class="block text-sm font-medium text-gray-700"
|
||||
>Meeting Password</label
|
||||
>
|
||||
<input
|
||||
id="password"
|
||||
v-model="newOrUpdatedMeeting.password"
|
||||
@@ -117,7 +151,9 @@
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="userName" class="block text-sm font-medium text-gray-700">Your Name</label>
|
||||
<label for="userName" class="block text-sm font-medium text-gray-700"
|
||||
>Your Name</label
|
||||
>
|
||||
<input
|
||||
id="userName"
|
||||
v-model="newOrUpdatedMeeting.userFullName"
|
||||
@@ -133,7 +169,15 @@
|
||||
class="w-full bg-gradient-to-b from-green-400 to-green-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-4 py-2 rounded-md hover:from-green-500 hover:to-green-800"
|
||||
:disabled="isLoading"
|
||||
>
|
||||
{{ isLoading ? (isInCreateMode() ? 'Creating...' : 'Updating...' ) : (isInCreateMode() ? 'Create Meeting' : 'Update Meeting') }}
|
||||
{{
|
||||
isLoading
|
||||
? isInCreateMode()
|
||||
? "Creating..."
|
||||
: "Updating..."
|
||||
: isInCreateMode()
|
||||
? "Create Meeting"
|
||||
: "Update Meeting"
|
||||
}}
|
||||
</button>
|
||||
<button
|
||||
v-if="isInEditOrCreateMode()"
|
||||
@@ -147,12 +191,15 @@
|
||||
</div>
|
||||
|
||||
<!-- Members Section -->
|
||||
<div v-if="!isLoading && currentMeeting != null" class="mt-8 p-4 border rounded-lg bg-white shadow">
|
||||
<div
|
||||
v-if="!isLoading && currentMeeting != null"
|
||||
class="mt-8 p-4 border rounded-lg bg-white shadow"
|
||||
>
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<h2 class="text-2xl">Meeting Members</h2>
|
||||
</div>
|
||||
<router-link
|
||||
:to="`/onboard-meeting-members/${currentMeeting.groupId}?password=${encodeURIComponent(currentMeeting.password || '')}`"
|
||||
:to="onboardMeetingMembersLink()"
|
||||
class="inline-block px-4 text-blue-600"
|
||||
target="_blank"
|
||||
>
|
||||
@@ -176,20 +223,24 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Vue } from 'vue-facing-decorator';
|
||||
import QuickNav from '@/components/QuickNav.vue';
|
||||
import TopMessage from '@/components/TopMessage.vue';
|
||||
import MembersList from '@/components/MembersList.vue';
|
||||
import { logConsoleAndDb, retrieveSettingsForActiveAccount } from '@/db/index';
|
||||
import { errorStringForLog, getHeaders, serverMessageForUser } from '@/libs/endorserServer';
|
||||
import { encryptMessage } from '@/libs/crypto';
|
||||
import { Component, Vue } from "vue-facing-decorator";
|
||||
import QuickNav from "@/components/QuickNav.vue";
|
||||
import TopMessage from "@/components/TopMessage.vue";
|
||||
import MembersList from "@/components/MembersList.vue";
|
||||
import { logConsoleAndDb, retrieveSettingsForActiveAccount } from "@/db/index";
|
||||
import {
|
||||
errorStringForLog,
|
||||
getHeaders,
|
||||
serverMessageForUser,
|
||||
} from "@/libs/endorserServer";
|
||||
import { encryptMessage } from "@/libs/crypto";
|
||||
|
||||
interface ServerMeeting {
|
||||
groupId: string; // from the server
|
||||
name: string; // from the server
|
||||
groupId: number; // from the server
|
||||
name: string; // from the server
|
||||
expiresAt: string; // from the server
|
||||
userFullName?: string; // from the user's session
|
||||
password?: string; // from the user's session
|
||||
password?: string; // from the user's session
|
||||
}
|
||||
|
||||
interface MeetingSetupInfo {
|
||||
@@ -207,16 +258,19 @@ interface MeetingSetupInfo {
|
||||
},
|
||||
})
|
||||
export default class OnboardMeetingView extends Vue {
|
||||
$notify!: (notification: { group: string; type: string; title: string; text: string }, timeout?: number) => void;
|
||||
$notify!: (
|
||||
notification: { group: string; type: string; title: string; text: string },
|
||||
timeout?: number,
|
||||
) => void;
|
||||
|
||||
currentMeeting: ServerMeeting | null = null;
|
||||
newOrUpdatedMeeting: MeetingSetupInfo | null = null;
|
||||
activeDid = '';
|
||||
apiServer = '';
|
||||
activeDid = "";
|
||||
apiServer = "";
|
||||
isDeleting = false;
|
||||
isLoading = true;
|
||||
showDeleteConfirm = false;
|
||||
fullName = '';
|
||||
fullName = "";
|
||||
get minDateTime() {
|
||||
const now = new Date();
|
||||
now.setMinutes(now.getMinutes() + 5); // Set minimum 5 minutes in the future
|
||||
@@ -225,10 +279,10 @@ export default class OnboardMeetingView extends Vue {
|
||||
|
||||
async created() {
|
||||
const settings = await retrieveSettingsForActiveAccount();
|
||||
this.activeDid = settings.activeDid || '';
|
||||
this.apiServer = settings.apiServer || '';
|
||||
this.fullName = settings.firstName || '';
|
||||
|
||||
this.activeDid = settings.activeDid || "";
|
||||
this.apiServer = settings.apiServer || "";
|
||||
this.fullName = settings.firstName || "";
|
||||
|
||||
await this.fetchCurrentMeeting();
|
||||
this.isLoading = false;
|
||||
}
|
||||
@@ -255,21 +309,21 @@ export default class OnboardMeetingView extends Vue {
|
||||
// Format a date object to YYYY-MM-DDTHH:mm format for datetime-local input
|
||||
private formatDateForInput(date: Date): string {
|
||||
const year = date.getFullYear();
|
||||
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||||
const day = String(date.getDate()).padStart(2, '0');
|
||||
const hours = String(date.getHours()).padStart(2, '0');
|
||||
const minutes = String(date.getMinutes()).padStart(2, '0');
|
||||
|
||||
const month = String(date.getMonth() + 1).padStart(2, "0");
|
||||
const day = String(date.getDate()).padStart(2, "0");
|
||||
const hours = String(date.getHours()).padStart(2, "0");
|
||||
const minutes = String(date.getMinutes()).padStart(2, "0");
|
||||
|
||||
return `${year}-${month}-${day}T${hours}:${minutes}`;
|
||||
}
|
||||
|
||||
blankMeeting(): MeetingSetupInfo {
|
||||
return {
|
||||
// no groupId yet
|
||||
name: '',
|
||||
name: "",
|
||||
expiresAt: this.getDefaultExpirationTime(),
|
||||
userFullName: this.fullName,
|
||||
password: this.currentMeeting?.password || "",
|
||||
password: (this.currentMeeting?.password as string) || "",
|
||||
};
|
||||
}
|
||||
|
||||
@@ -277,10 +331,10 @@ export default class OnboardMeetingView extends Vue {
|
||||
try {
|
||||
const headers = await getHeaders(this.activeDid);
|
||||
const response = await this.axios.get(
|
||||
this.apiServer + '/api/partner/groupOnboard',
|
||||
{ headers }
|
||||
this.apiServer + "/api/partner/groupOnboard",
|
||||
{ headers },
|
||||
);
|
||||
|
||||
|
||||
if (response?.data?.data) {
|
||||
this.currentMeeting = {
|
||||
...response.data.data,
|
||||
@@ -302,7 +356,9 @@ export default class OnboardMeetingView extends Vue {
|
||||
|
||||
try {
|
||||
if (!this.newOrUpdatedMeeting) {
|
||||
throw Error('There was no meeting data to create. We should never get here.');
|
||||
throw Error(
|
||||
"There was no meeting data to create. We should never get here.",
|
||||
);
|
||||
}
|
||||
|
||||
// Convert local time to UTC for comparison and server submission
|
||||
@@ -311,57 +367,59 @@ export default class OnboardMeetingView extends Vue {
|
||||
if (localExpiresAt <= now) {
|
||||
this.$notify(
|
||||
{
|
||||
group: 'alert',
|
||||
type: 'warning',
|
||||
title: 'Invalid Time',
|
||||
text: 'Select a future time for the meeting expiration.',
|
||||
group: "alert",
|
||||
type: "warning",
|
||||
title: "Invalid Time",
|
||||
text: "Select a future time for the meeting expiration.",
|
||||
},
|
||||
5000
|
||||
5000,
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (!this.newOrUpdatedMeeting.userFullName) {
|
||||
this.$notify(
|
||||
{
|
||||
group: 'alert',
|
||||
type: 'warning',
|
||||
title: 'Invalid Name',
|
||||
text: 'Please enter your name.',
|
||||
group: "alert",
|
||||
type: "warning",
|
||||
title: "Invalid Name",
|
||||
text: "Please enter your name.",
|
||||
},
|
||||
5000
|
||||
5000,
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (!this.newOrUpdatedMeeting.password) {
|
||||
this.$notify(
|
||||
{
|
||||
group: 'alert',
|
||||
type: 'warning',
|
||||
title: 'Invalid Password',
|
||||
text: 'Please enter a password.',
|
||||
group: "alert",
|
||||
type: "warning",
|
||||
title: "Invalid Password",
|
||||
text: "Please enter a password.",
|
||||
},
|
||||
5000
|
||||
5000,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// create content with user's name and DID encrypted with password
|
||||
const content = {
|
||||
name: this.newOrUpdatedMeeting.userFullName,
|
||||
did: this.activeDid,
|
||||
};
|
||||
const encryptedContent = await encryptMessage(JSON.stringify(content), this.newOrUpdatedMeeting.password);
|
||||
|
||||
const encryptedContent = await encryptMessage(
|
||||
JSON.stringify(content),
|
||||
this.newOrUpdatedMeeting.password,
|
||||
);
|
||||
|
||||
const headers = await getHeaders(this.activeDid);
|
||||
const response = await this.axios.post(
|
||||
this.apiServer + '/api/partner/groupOnboard',
|
||||
this.apiServer + "/api/partner/groupOnboard",
|
||||
{
|
||||
name: this.newOrUpdatedMeeting.name,
|
||||
expiresAt: localExpiresAt.toISOString(),
|
||||
content: encryptedContent,
|
||||
},
|
||||
{ headers }
|
||||
{ headers },
|
||||
);
|
||||
|
||||
if (response.data && response.data.success) {
|
||||
@@ -373,27 +431,32 @@ export default class OnboardMeetingView extends Vue {
|
||||
this.newOrUpdatedMeeting = null;
|
||||
this.$notify(
|
||||
{
|
||||
group: 'alert',
|
||||
type: 'success',
|
||||
title: 'Success',
|
||||
text: 'Meeting created.',
|
||||
group: "alert",
|
||||
type: "success",
|
||||
title: "Success",
|
||||
text: "Meeting created.",
|
||||
},
|
||||
3000
|
||||
3000,
|
||||
);
|
||||
} else {
|
||||
throw { response: response };
|
||||
}
|
||||
} catch (error) {
|
||||
logConsoleAndDb('Error creating meeting: ' + errorStringForLog(error), true);
|
||||
logConsoleAndDb(
|
||||
"Error creating meeting: " + errorStringForLog(error),
|
||||
true,
|
||||
);
|
||||
const errorMessage = serverMessageForUser(error);
|
||||
this.$notify(
|
||||
{
|
||||
group: 'alert',
|
||||
type: 'danger',
|
||||
title: 'Error',
|
||||
text: errorMessage || 'Failed to create meeting. Try reloading or submitting again.',
|
||||
group: "alert",
|
||||
type: "danger",
|
||||
title: "Error",
|
||||
text:
|
||||
errorMessage ||
|
||||
"Failed to create meeting. Try reloading or submitting again.",
|
||||
},
|
||||
5000
|
||||
5000,
|
||||
);
|
||||
} finally {
|
||||
this.isLoading = false;
|
||||
@@ -403,14 +466,16 @@ export default class OnboardMeetingView extends Vue {
|
||||
formatExpirationTime(expiresAt: string): string {
|
||||
const expiration = new Date(expiresAt); // Server time is in UTC
|
||||
const now = new Date();
|
||||
const diffHours = Math.round((expiration.getTime() - now.getTime()) / (1000 * 60 * 60));
|
||||
|
||||
const diffHours = Math.round(
|
||||
(expiration.getTime() - now.getTime()) / (1000 * 60 * 60),
|
||||
);
|
||||
|
||||
if (diffHours < 0) {
|
||||
return 'Expired';
|
||||
return "Expired";
|
||||
} else if (diffHours < 1) {
|
||||
return 'Less than an hour';
|
||||
return "Less than an hour";
|
||||
} else if (diffHours === 1) {
|
||||
return '1 hour';
|
||||
return "1 hour";
|
||||
} else {
|
||||
return `${diffHours} hours`;
|
||||
}
|
||||
@@ -424,34 +489,33 @@ export default class OnboardMeetingView extends Vue {
|
||||
this.isDeleting = true;
|
||||
try {
|
||||
const headers = await getHeaders(this.activeDid);
|
||||
await this.axios.delete(
|
||||
this.apiServer + '/api/partner/groupOnboard',
|
||||
{ headers }
|
||||
);
|
||||
await this.axios.delete(this.apiServer + "/api/partner/groupOnboard", {
|
||||
headers,
|
||||
});
|
||||
|
||||
this.currentMeeting = null;
|
||||
this.newOrUpdatedMeeting = this.blankMeeting();
|
||||
this.showDeleteConfirm = false;
|
||||
|
||||
|
||||
this.$notify(
|
||||
{
|
||||
group: 'alert',
|
||||
type: 'success',
|
||||
title: 'Success',
|
||||
text: 'Meeting deleted successfully.',
|
||||
group: "alert",
|
||||
type: "success",
|
||||
title: "Success",
|
||||
text: "Meeting deleted successfully.",
|
||||
},
|
||||
3000
|
||||
3000,
|
||||
);
|
||||
} catch (error) {
|
||||
console.error('Error deleting meeting:', error);
|
||||
console.error("Error deleting meeting:", error);
|
||||
this.$notify(
|
||||
{
|
||||
group: 'alert',
|
||||
type: 'danger',
|
||||
title: 'Error',
|
||||
text: serverMessageForUser(error) || 'Failed to delete meeting.',
|
||||
group: "alert",
|
||||
type: "danger",
|
||||
title: "Error",
|
||||
text: serverMessageForUser(error) || "Failed to delete meeting.",
|
||||
},
|
||||
5000
|
||||
5000,
|
||||
);
|
||||
} finally {
|
||||
this.isDeleting = false;
|
||||
@@ -465,11 +529,13 @@ export default class OnboardMeetingView extends Vue {
|
||||
this.newOrUpdatedMeeting = {
|
||||
name: this.currentMeeting.name,
|
||||
expiresAt: this.formatDateForInput(localExpiresAt),
|
||||
userFullName: this.currentMeeting.userFullName || '',
|
||||
password: this.currentMeeting.password || '',
|
||||
userFullName: this.currentMeeting.userFullName || "",
|
||||
password: this.currentMeeting.password || "",
|
||||
};
|
||||
} else {
|
||||
console.error('There is no current meeting to edit. We should never get here.');
|
||||
console.error(
|
||||
"There is no current meeting to edit. We should never get here.",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -481,7 +547,7 @@ export default class OnboardMeetingView extends Vue {
|
||||
async updateMeeting() {
|
||||
this.isLoading = true;
|
||||
if (!this.newOrUpdatedMeeting) {
|
||||
throw Error('There was no meeting data to update.');
|
||||
throw Error("There was no meeting data to update.");
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -491,36 +557,36 @@ export default class OnboardMeetingView extends Vue {
|
||||
if (localExpiresAt <= now) {
|
||||
this.$notify(
|
||||
{
|
||||
group: 'alert',
|
||||
type: 'warning',
|
||||
title: 'Invalid Time',
|
||||
text: 'Select a future time for the meeting expiration.',
|
||||
group: "alert",
|
||||
type: "warning",
|
||||
title: "Invalid Time",
|
||||
text: "Select a future time for the meeting expiration.",
|
||||
},
|
||||
5000
|
||||
5000,
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (!this.newOrUpdatedMeeting.userFullName) {
|
||||
this.$notify(
|
||||
{
|
||||
group: 'alert',
|
||||
type: 'warning',
|
||||
title: 'Invalid Name',
|
||||
text: 'Please enter your name.',
|
||||
group: "alert",
|
||||
type: "warning",
|
||||
title: "Invalid Name",
|
||||
text: "Please enter your name.",
|
||||
},
|
||||
5000
|
||||
5000,
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (!this.newOrUpdatedMeeting.password) {
|
||||
this.$notify(
|
||||
{
|
||||
group: 'alert',
|
||||
type: 'warning',
|
||||
title: 'Invalid Password',
|
||||
text: 'Please enter a password.',
|
||||
group: "alert",
|
||||
type: "warning",
|
||||
title: "Invalid Password",
|
||||
text: "Please enter a password.",
|
||||
},
|
||||
5000
|
||||
5000,
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -529,57 +595,74 @@ export default class OnboardMeetingView extends Vue {
|
||||
name: this.newOrUpdatedMeeting.userFullName,
|
||||
did: this.activeDid,
|
||||
};
|
||||
const encryptedContent = await encryptMessage(JSON.stringify(content), this.newOrUpdatedMeeting.password);
|
||||
|
||||
const encryptedContent = await encryptMessage(
|
||||
JSON.stringify(content),
|
||||
this.newOrUpdatedMeeting.password,
|
||||
);
|
||||
|
||||
const headers = await getHeaders(this.activeDid);
|
||||
const response = await this.axios.put(
|
||||
this.apiServer + '/api/partner/groupOnboard',
|
||||
this.apiServer + "/api/partner/groupOnboard",
|
||||
{
|
||||
// the groupId is in the currentMeeting but it's not necessary while users only have one meeting
|
||||
name: this.newOrUpdatedMeeting.name,
|
||||
expiresAt: localExpiresAt.toISOString(),
|
||||
content: encryptedContent,
|
||||
},
|
||||
{ headers }
|
||||
{ headers },
|
||||
);
|
||||
|
||||
if (response.data && response.data.success) {
|
||||
// Update the current meeting with only the necessary fields
|
||||
this.currentMeeting = {
|
||||
...this.newOrUpdatedMeeting,
|
||||
groupId: this.currentMeeting?.groupId || "",
|
||||
groupId: (this.currentMeeting?.groupId as number) || -1,
|
||||
};
|
||||
this.newOrUpdatedMeeting = null;
|
||||
} else {
|
||||
throw { response: response };
|
||||
}
|
||||
} catch (error) {
|
||||
logConsoleAndDb('Error updating meeting: ' + errorStringForLog(error), true);
|
||||
logConsoleAndDb(
|
||||
"Error updating meeting: " + errorStringForLog(error),
|
||||
true,
|
||||
);
|
||||
const errorMessage = serverMessageForUser(error);
|
||||
this.$notify(
|
||||
{
|
||||
group: 'alert',
|
||||
type: 'danger',
|
||||
title: 'Error',
|
||||
text: errorMessage || 'Failed to update meeting. Try reloading or submitting again.',
|
||||
group: "alert",
|
||||
type: "danger",
|
||||
title: "Error",
|
||||
text:
|
||||
errorMessage ||
|
||||
"Failed to update meeting. Try reloading or submitting again.",
|
||||
},
|
||||
5000
|
||||
5000,
|
||||
);
|
||||
} finally {
|
||||
this.isLoading = false;
|
||||
}
|
||||
}
|
||||
|
||||
onboardMeetingMembersLink(): string {
|
||||
if (this.currentMeeting) {
|
||||
return `/onboard-meeting-members/${this.currentMeeting?.groupId}?password=${encodeURIComponent(
|
||||
this.currentMeeting?.password || "",
|
||||
)}`;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
handleMembersError(message: string) {
|
||||
this.$notify(
|
||||
{
|
||||
group: 'alert',
|
||||
type: 'danger',
|
||||
title: 'Error',
|
||||
group: "alert",
|
||||
type: "danger",
|
||||
title: "Error",
|
||||
text: message,
|
||||
},
|
||||
5000
|
||||
5000,
|
||||
);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user