Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| cc14b9e0ce | |||
| 9a6b2fcf0d | |||
| 2b78307a51 |
@@ -6,6 +6,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
|
||||||
|
## [0.3.57] - 2025.02.11
|
||||||
|
### Added
|
||||||
|
- Automatic user creation in onboarding meetings
|
||||||
|
|
||||||
|
|
||||||
## [0.3.55] - 2025.02.07
|
## [0.3.55] - 2025.02.07
|
||||||
### Added
|
### Added
|
||||||
- End time for projects
|
- End time for projects
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ Look below for the "test-all" instructions.
|
|||||||
|
|
||||||
* Put the commit hash in the changelog (which will help you remember to bump the version later).
|
* Put the commit hash in the changelog (which will help you remember to bump the version later).
|
||||||
|
|
||||||
* Tag with the new version, [online](https://gitea.anomalistdesign.com/trent_larson/crowd-funder-for-time-pwa/releases) or `git tag 0.3.36` && `git push origin 0.3.36`.
|
* Tag with the new version, [online](https://gitea.anomalistdesign.com/trent_larson/crowd-funder-for-time-pwa/releases) or `git tag 0.3.55 && git push origin 0.3.55`.
|
||||||
|
|
||||||
* For test, build the app (because test server is not yet set up to build):
|
* For test, build the app (because test server is not yet set up to build):
|
||||||
|
|
||||||
@@ -70,7 +70,7 @@ TIME_SAFARI_APP_TITLE="TimeSafari_Test" VITE_APP_SERVER=https://test.timesafari.
|
|||||||
|
|
||||||
* `pkgx +npm sh`
|
* `pkgx +npm sh`
|
||||||
|
|
||||||
* `cd crowd-funder-for-time-pwa && git checkout master && git pull && git checkout 0.3.36 && npm install && npm run build && cd -`
|
* `cd crowd-funder-for-time-pwa && git checkout master && git pull && git checkout 0.3.55 && npm install && npm run build && cd -`
|
||||||
|
|
||||||
(The plain `npm run build` uses the .env.production file.)
|
(The plain `npm run build` uses the .env.production file.)
|
||||||
|
|
||||||
|
|||||||
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "TimeSafari",
|
"name": "TimeSafari",
|
||||||
"version": "0.3.55",
|
"version": "0.3.57",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "TimeSafari",
|
"name": "TimeSafari",
|
||||||
"version": "0.3.55",
|
"version": "0.3.57",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@capacitor/android": "^6.1.2",
|
"@capacitor/android": "^6.1.2",
|
||||||
"@capacitor/cli": "^6.1.2",
|
"@capacitor/cli": "^6.1.2",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "TimeSafari",
|
"name": "TimeSafari",
|
||||||
"version": "0.3.55",
|
"version": "0.3.57",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
"serve": "vite preview",
|
"serve": "vite preview",
|
||||||
|
|||||||
@@ -1,40 +1,41 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="space-y-4">
|
<div class="space-y-4">
|
||||||
<!-- Loading State -->
|
<!-- Loading State -->
|
||||||
<div v-if="isLoading" class="flex justify-center items-center py-8">
|
<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"
|
||||||
|
>
|
||||||
<fa icon="spinner" class="fa-spin-pulse" />
|
<fa icon="spinner" class="fa-spin-pulse" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Members List -->
|
<!-- Members List -->
|
||||||
|
|
||||||
<p
|
<div v-else>
|
||||||
v-if="decryptedMembers.length < members.length"
|
<div class="text-center text-red-600 py-4">
|
||||||
class="text-center text-red-600 py-4"
|
{{ decryptionErrorMessage() }}
|
||||||
>
|
</div>
|
||||||
{{
|
|
||||||
decryptFailureMessage ||
|
|
||||||
"Your password failed. Please go back and try again."
|
|
||||||
}}
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<div v-else class="space-y-4">
|
|
||||||
<div v-if="missingMyself" class="py-4 text-red-600">
|
<div v-if="missingMyself" class="py-4 text-red-600">
|
||||||
You are not admitted. The organizer will admit you.
|
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>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<span
|
<span
|
||||||
v-if="showOrganizerTools && isOrganizer"
|
v-if="membersToShow().length > 0 && showOrganizerTools && isOrganizer"
|
||||||
class="inline-flex items-center flex-wrap"
|
class="inline-flex items-center flex-wrap"
|
||||||
>
|
>
|
||||||
<span class="inline-flex items-center">
|
<span class="inline-flex items-center">
|
||||||
Use
|
• Click
|
||||||
<span
|
<span
|
||||||
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"
|
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="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"
|
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"
|
||||||
>
|
>
|
||||||
@@ -45,8 +46,11 @@
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<span class="inline-flex items-center">
|
<span
|
||||||
Use
|
v-if="membersToShow().length > 0"
|
||||||
|
class="inline-flex items-center"
|
||||||
|
>
|
||||||
|
• Click
|
||||||
<span
|
<span
|
||||||
class="mx-2 w-8 h-8 flex items-center justify-center rounded-full bg-green-100 text-green-600"
|
class="mx-2 w-8 h-8 flex items-center justify-center rounded-full bg-green-100 text-green-600"
|
||||||
>
|
>
|
||||||
@@ -56,7 +60,8 @@
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="members.length > 0" class="flex justify-center">
|
<div class="flex justify-center">
|
||||||
|
<!-- always have at least one refresh button even without members in case the organizer changes the password -->
|
||||||
<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"
|
||||||
@@ -68,7 +73,7 @@
|
|||||||
<div
|
<div
|
||||||
v-for="member in membersToShow()"
|
v-for="member in membersToShow()"
|
||||||
:key="member.member.memberId"
|
:key="member.member.memberId"
|
||||||
class="p-4 bg-gray-50 rounded-lg"
|
class="mt-2 p-4 bg-gray-50 rounded-lg"
|
||||||
>
|
>
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
@@ -131,7 +136,7 @@
|
|||||||
{{ member.did }}
|
{{ member.did }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="members.length > 0" class="flex justify-center mt-4">
|
<div v-if="membersToShow().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"
|
||||||
@@ -187,16 +192,15 @@ export default class MembersList extends Vue {
|
|||||||
libsUtil = libsUtil;
|
libsUtil = libsUtil;
|
||||||
|
|
||||||
@Prop({ required: true }) password!: string;
|
@Prop({ required: true }) password!: string;
|
||||||
@Prop({ default: "Your password failed. Please go back and try again." })
|
|
||||||
decryptFailureMessage!: string;
|
|
||||||
@Prop({ default: false }) showOrganizerTools!: boolean;
|
@Prop({ default: false }) showOrganizerTools!: boolean;
|
||||||
|
|
||||||
decryptedMembers: DecryptedMember[] = [];
|
decryptedMembers: DecryptedMember[] = [];
|
||||||
missingPassword = false;
|
firstName = "";
|
||||||
missingMyself = false;
|
isLoading = true;
|
||||||
isLoading = false;
|
|
||||||
isOrganizer = false;
|
isOrganizer = false;
|
||||||
members: Member[] = [];
|
members: Member[] = [];
|
||||||
|
missingPassword = false;
|
||||||
|
missingMyself = false;
|
||||||
activeDid = "";
|
activeDid = "";
|
||||||
apiServer = "";
|
apiServer = "";
|
||||||
contacts: Array<Contact> = [];
|
contacts: Array<Contact> = [];
|
||||||
@@ -205,13 +209,14 @@ export default class MembersList extends Vue {
|
|||||||
const settings = await retrieveSettingsForActiveAccount();
|
const settings = await retrieveSettingsForActiveAccount();
|
||||||
this.activeDid = settings.activeDid || "";
|
this.activeDid = settings.activeDid || "";
|
||||||
this.apiServer = settings.apiServer || "";
|
this.apiServer = settings.apiServer || "";
|
||||||
|
this.firstName = settings.firstName || "";
|
||||||
await this.fetchMembers();
|
await this.fetchMembers();
|
||||||
await this.loadContacts();
|
await this.loadContacts();
|
||||||
}
|
}
|
||||||
|
|
||||||
async fetchMembers() {
|
async fetchMembers() {
|
||||||
this.isLoading = true;
|
|
||||||
try {
|
try {
|
||||||
|
this.isLoading = true;
|
||||||
const headers = await getHeaders(this.activeDid);
|
const headers = await getHeaders(this.activeDid);
|
||||||
const response = await this.axios.get(
|
const response = await this.axios.get(
|
||||||
`${this.apiServer}/api/partner/groupOnboardMembers`,
|
`${this.apiServer}/api/partner/groupOnboardMembers`,
|
||||||
@@ -274,6 +279,28 @@ export default class MembersList extends Vue {
|
|||||||
this.missingMyself = !foundMyself;
|
this.missingMyself = !foundMyself;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
decryptionErrorMessage(): string {
|
||||||
|
if (this.isOrganizer) {
|
||||||
|
if (this.decryptedMembers.length < this.members.length) {
|
||||||
|
return "Some members have data that cannot be decrypted with that password.";
|
||||||
|
} else {
|
||||||
|
// the lists must be equal
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// non-organizers should only see problems if the first (organizer) member is not decrypted
|
||||||
|
if (
|
||||||
|
this.decryptedMembers.length === 0 ||
|
||||||
|
this.decryptedMembers[0].member.memberId !== this.members[0].memberId
|
||||||
|
) {
|
||||||
|
return "Your password is not the same as the organizer. Reload or have them check their password.";
|
||||||
|
} else {
|
||||||
|
// the first (organizer) member was decrypted OK
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
membersToShow(): DecryptedMember[] {
|
membersToShow(): DecryptedMember[] {
|
||||||
if (this.isOrganizer) {
|
if (this.isOrganizer) {
|
||||||
if (this.showOrganizerTools) {
|
if (this.showOrganizerTools) {
|
||||||
@@ -356,7 +383,7 @@ export default class MembersList extends Vue {
|
|||||||
group: "modal",
|
group: "modal",
|
||||||
type: "confirm",
|
type: "confirm",
|
||||||
title: "Continue Without Adding?",
|
title: "Continue Without Adding?",
|
||||||
text: "Are you sure you want to proceed with admission even though they are not a contact?",
|
text: "Are you sure you want to proceed with admission? If they are not a contact, you will not know their name after this meeting.",
|
||||||
yesText: "Continue",
|
yesText: "Continue",
|
||||||
onYes: async () => {
|
onYes: async () => {
|
||||||
await this.toggleAdmission(decrMember);
|
await this.toggleAdmission(decrMember);
|
||||||
|
|||||||
@@ -4,8 +4,7 @@
|
|||||||
<div class="dialog">
|
<div class="dialog">
|
||||||
<h1 class="text-xl font-bold text-center mb-4">Set Your Name</h1>
|
<h1 class="text-xl font-bold text-center mb-4">Set Your Name</h1>
|
||||||
|
|
||||||
This is not sent to servers. It is only shared with people when you send
|
{{ sharingExplanation }}
|
||||||
it to them.
|
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="Name"
|
placeholder="Name"
|
||||||
@@ -36,7 +35,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Vue, Component } from "vue-facing-decorator";
|
import { Vue, Component, Prop } from "vue-facing-decorator";
|
||||||
|
|
||||||
import { NotificationIface } from "@/constants/app";
|
import { NotificationIface } from "@/constants/app";
|
||||||
import { db, retrieveSettingsForActiveAccount } from "@/db/index";
|
import { db, retrieveSettingsForActiveAccount } from "@/db/index";
|
||||||
@@ -46,14 +45,21 @@ import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
|
|||||||
export default class UserNameDialog extends Vue {
|
export default class UserNameDialog extends Vue {
|
||||||
$notify!: (notification: NotificationIface, timeout?: number) => void;
|
$notify!: (notification: NotificationIface, timeout?: number) => void;
|
||||||
|
|
||||||
callback: (name: string) => void = () => {};
|
@Prop({
|
||||||
|
default:
|
||||||
|
"This is not sent to servers. It is only shared with people when you send it to them.",
|
||||||
|
})
|
||||||
|
sharingExplanation!: string;
|
||||||
|
@Prop({ default: false }) callbackOnCancel!: boolean;
|
||||||
|
|
||||||
|
callback: (name?: string) => void = () => {};
|
||||||
givenName = "";
|
givenName = "";
|
||||||
visible = false;
|
visible = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param aCallback - callback function for name, which may be ""
|
* @param aCallback - callback function for name, which may be ""
|
||||||
*/
|
*/
|
||||||
async open(aCallback?: (name: string) => void) {
|
async open(aCallback?: (name?: string) => void) {
|
||||||
this.callback = aCallback || this.callback;
|
this.callback = aCallback || this.callback;
|
||||||
const settings = await retrieveSettingsForActiveAccount();
|
const settings = await retrieveSettingsForActiveAccount();
|
||||||
this.givenName = settings.firstName || "";
|
this.givenName = settings.firstName || "";
|
||||||
@@ -70,6 +76,9 @@ export default class UserNameDialog extends Vue {
|
|||||||
|
|
||||||
onClickCancel() {
|
onClickCancel() {
|
||||||
this.visible = false;
|
this.visible = false;
|
||||||
|
if (this.callbackOnCancel) {
|
||||||
|
this.callback();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -8,8 +8,16 @@
|
|||||||
Meeting Members
|
Meeting Members
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
|
<!-- Loading Animation -->
|
||||||
|
<div
|
||||||
|
class="mt-16 text-center text-4xl bg-slate-400 text-white w-14 py-2.5 rounded-full mx-auto"
|
||||||
|
v-if="isLoading"
|
||||||
|
>
|
||||||
|
<fa icon="spinner" class="fa-spin-pulse"></fa>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Error State -->
|
<!-- Error State -->
|
||||||
<div v-if="errorMessage">
|
<div v-else-if="errorMessage">
|
||||||
<div class="text-center text-red-600 py-8">
|
<div class="text-center text-red-600 py-8">
|
||||||
{{ errorMessage }}
|
{{ errorMessage }}
|
||||||
</div>
|
</div>
|
||||||
@@ -19,13 +27,14 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Members List -->
|
<!-- Members List -->
|
||||||
<MembersList
|
<MembersList v-else :password="password" @error="handleError" />
|
||||||
v-else
|
|
||||||
:password="password"
|
|
||||||
:decrypt-failure-message="'That password failed. You may be in the wrong meeting. Go back and try again.'"
|
|
||||||
@error="handleError"
|
|
||||||
/>
|
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<UserNameDialog
|
||||||
|
ref="userNameDialog"
|
||||||
|
:callback-on-cancel="true"
|
||||||
|
sharing-explanation="This is encrypted and shared only with people in this meeting."
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
@@ -35,16 +44,35 @@ import { RouteLocation } from "vue-router";
|
|||||||
import QuickNav from "@/components/QuickNav.vue";
|
import QuickNav from "@/components/QuickNav.vue";
|
||||||
import TopMessage from "@/components/TopMessage.vue";
|
import TopMessage from "@/components/TopMessage.vue";
|
||||||
import MembersList from "@/components/MembersList.vue";
|
import MembersList from "@/components/MembersList.vue";
|
||||||
|
import UserNameDialog from "@/components/UserNameDialog.vue";
|
||||||
|
import { logConsoleAndDb, retrieveSettingsForActiveAccount } from "@/db/index";
|
||||||
|
import { encryptMessage } from "@/libs/crypto";
|
||||||
|
import {
|
||||||
|
errorStringForLog,
|
||||||
|
getHeaders,
|
||||||
|
serverMessageForUser,
|
||||||
|
} from "@/libs/endorserServer";
|
||||||
|
import { generateSaveAndActivateIdentity } from "@/libs/util";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
components: {
|
components: {
|
||||||
QuickNav,
|
QuickNav,
|
||||||
TopMessage,
|
TopMessage,
|
||||||
MembersList,
|
MembersList,
|
||||||
|
UserNameDialog,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
export default class OnboardMeetingMembersView extends Vue {
|
export default class OnboardMeetingMembersView extends Vue {
|
||||||
|
activeDid = "";
|
||||||
|
apiServer = "";
|
||||||
errorMessage = "";
|
errorMessage = "";
|
||||||
|
firstName = "";
|
||||||
|
isRegistered = false;
|
||||||
|
isLoading = true;
|
||||||
|
|
||||||
|
$refs!: {
|
||||||
|
userNameDialog: InstanceType<typeof UserNameDialog>;
|
||||||
|
};
|
||||||
|
|
||||||
get groupId(): string {
|
get groupId(): string {
|
||||||
return (this.$route as RouteLocation).params.groupId as string;
|
return (this.$route as RouteLocation).params.groupId as string;
|
||||||
@@ -63,6 +91,122 @@ export default class OnboardMeetingMembersView extends Vue {
|
|||||||
this.errorMessage = "The password is missing. Go back and try again.";
|
this.errorMessage = "The password is missing. Go back and try again.";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const settings = await retrieveSettingsForActiveAccount();
|
||||||
|
this.activeDid = settings.activeDid || "";
|
||||||
|
this.apiServer = settings.apiServer || "";
|
||||||
|
this.firstName = settings.firstName || "";
|
||||||
|
this.isRegistered = settings.isRegistered || false;
|
||||||
|
try {
|
||||||
|
if (!this.activeDid) {
|
||||||
|
this.activeDid = await generateSaveAndActivateIdentity();
|
||||||
|
this.isRegistered = false;
|
||||||
|
}
|
||||||
|
const headers = await getHeaders(this.activeDid);
|
||||||
|
const response = await this.axios.get(
|
||||||
|
`${this.apiServer}/api/partner/groupOnboardMember`,
|
||||||
|
{ headers },
|
||||||
|
);
|
||||||
|
const member = response.data?.data;
|
||||||
|
if (!member) {
|
||||||
|
if (!this.firstName) {
|
||||||
|
this.$refs.userNameDialog.open(this.addMemberToMeeting);
|
||||||
|
// addMemberToMeeting sets isLoading to false
|
||||||
|
} else {
|
||||||
|
await this.addMemberToMeeting(this.firstName);
|
||||||
|
// addMemberToMeeting sets isLoading to false
|
||||||
|
}
|
||||||
|
} else if (String(member.groupId) !== this.groupId) {
|
||||||
|
this.errorMessage =
|
||||||
|
"You are already in a different meeting. Reload or go back and try again.";
|
||||||
|
this.isLoading = false;
|
||||||
|
} else {
|
||||||
|
// must be already in the right meeting
|
||||||
|
if (!this.firstName) {
|
||||||
|
this.$refs.userNameDialog.open(this.updateMemberInMeeting);
|
||||||
|
// updateMemberInMeeting sets isLoading to false
|
||||||
|
} else {
|
||||||
|
await this.updateMemberInMeeting(this.firstName);
|
||||||
|
// updateMemberInMeeting sets isLoading to false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
this.errorMessage =
|
||||||
|
serverMessageForUser(error) ||
|
||||||
|
"There was an error checking for that meeting. Reload or go back and try again.";
|
||||||
|
logConsoleAndDb(
|
||||||
|
"Error checking meeting: " + errorStringForLog(error),
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
this.isLoading = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async addMemberToMeeting(name?: string) {
|
||||||
|
if (name != null) {
|
||||||
|
this.firstName = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
const memberData = {
|
||||||
|
name: this.firstName,
|
||||||
|
did: this.activeDid,
|
||||||
|
isRegistered: this.isRegistered,
|
||||||
|
};
|
||||||
|
const memberDataString = JSON.stringify(memberData);
|
||||||
|
const encryptedMemberData = await encryptMessage(
|
||||||
|
memberDataString,
|
||||||
|
this.password,
|
||||||
|
);
|
||||||
|
|
||||||
|
const headers = await getHeaders(this.activeDid);
|
||||||
|
try {
|
||||||
|
await this.axios.post(
|
||||||
|
`${this.apiServer}/api/partner/groupOnboardMember`,
|
||||||
|
{ groupId: this.groupId, content: encryptedMemberData },
|
||||||
|
{ headers },
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
logConsoleAndDb(
|
||||||
|
"Error adding member to meeting: " + errorStringForLog(error),
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
this.errorMessage =
|
||||||
|
serverMessageForUser(error) ||
|
||||||
|
"You're not in a meeting and couldn't be added to this one. Reload or go back and try again.";
|
||||||
|
}
|
||||||
|
this.isLoading = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateMemberInMeeting(name?: string) {
|
||||||
|
if (name != null) {
|
||||||
|
this.firstName = name;
|
||||||
|
}
|
||||||
|
const memberData = {
|
||||||
|
name: this.firstName,
|
||||||
|
did: this.activeDid,
|
||||||
|
isRegistered: this.isRegistered,
|
||||||
|
};
|
||||||
|
const memberDataString = JSON.stringify(memberData);
|
||||||
|
const encryptedMemberData = await encryptMessage(
|
||||||
|
memberDataString,
|
||||||
|
this.password,
|
||||||
|
);
|
||||||
|
const headers = await getHeaders(this.activeDid);
|
||||||
|
try {
|
||||||
|
await this.axios.put(
|
||||||
|
`${this.apiServer}/api/partner/groupOnboardMember`,
|
||||||
|
{ content: encryptedMemberData },
|
||||||
|
{ headers },
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
logConsoleAndDb(
|
||||||
|
"Error updating member in meeting: " + errorStringForLog(error),
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
this.errorMessage =
|
||||||
|
serverMessageForUser(error) ||
|
||||||
|
"There was an error updating your name. Reload or go back and try again.";
|
||||||
|
}
|
||||||
|
this.isLoading = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
handleError(message: string) {
|
handleError(message: string) {
|
||||||
|
|||||||
@@ -192,23 +192,23 @@
|
|||||||
|
|
||||||
<!-- Members Section -->
|
<!-- Members Section -->
|
||||||
<div
|
<div
|
||||||
v-if="!isLoading && currentMeeting != null"
|
v-if="!isLoading && currentMeeting != null && !!currentMeeting.password"
|
||||||
class="mt-8 p-4 border rounded-lg bg-white shadow"
|
class="mt-8 p-4 border rounded-lg bg-white shadow"
|
||||||
>
|
>
|
||||||
<div class="flex items-center justify-between mb-4">
|
<div class="flex items-center justify-between mb-4">
|
||||||
<h2 class="text-2xl">Meeting Members</h2>
|
<h2 class="text-2xl">Meeting Members</h2>
|
||||||
</div>
|
</div>
|
||||||
<router-link
|
<router-link
|
||||||
|
v-if="!!currentMeeting.password"
|
||||||
:to="onboardMeetingMembersLink()"
|
:to="onboardMeetingMembersLink()"
|
||||||
class="inline-block text-blue-600"
|
class="inline-block text-blue-600"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
>
|
>
|
||||||
Open shortcut page for members <fa icon="external-link" />
|
• Open shortcut page for members <fa icon="external-link" />
|
||||||
</router-link>
|
</router-link>
|
||||||
|
|
||||||
<MembersList
|
<MembersList
|
||||||
:password="currentMeeting.password || ''"
|
:password="currentMeeting.password || ''"
|
||||||
:decrypt-failure-message="DECRYPT_FAILURE_MESSAGE"
|
|
||||||
:show-organizer-tools="true"
|
:show-organizer-tools="true"
|
||||||
@error="handleMembersError"
|
@error="handleMembersError"
|
||||||
class="mt-4"
|
class="mt-4"
|
||||||
@@ -264,9 +264,6 @@ export default class OnboardMeetingView extends Vue {
|
|||||||
timeout?: number,
|
timeout?: number,
|
||||||
) => void;
|
) => void;
|
||||||
|
|
||||||
DECRYPT_FAILURE_MESSAGE =
|
|
||||||
"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;
|
||||||
activeDid = "";
|
activeDid = "";
|
||||||
|
|||||||
Reference in New Issue
Block a user