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.
		
		
		
		
		
			
		
			
				
					
					
						
							336 lines
						
					
					
						
							10 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							336 lines
						
					
					
						
							10 KiB
						
					
					
				
								<template>
							 | 
						|
								  <div v-if="visible" class="dialog-overlay">
							 | 
						|
								    <div class="dialog">
							 | 
						|
								      <div class="text-slate-900 text-center">
							 | 
						|
								        <h3 class="text-lg font-semibold leading-[1.25] mb-2">
							 | 
						|
								          Set Visibility to Meeting Members
							 | 
						|
								        </h3>
							 | 
						|
								        <p class="text-sm mb-4">
							 | 
						|
								          Would you like to <b>make your activities visible</b> to the following
							 | 
						|
								          members? (This will also add them as contacts if they aren't already.)
							 | 
						|
								        </p>
							 | 
						|
								
							 | 
						|
								        <!-- Custom table area - you can customize this -->
							 | 
						|
								        <div v-if="shouldInitializeSelection" class="mb-4">
							 | 
						|
								          <table
							 | 
						|
								            class="w-full border-collapse border border-slate-300 text-sm text-start"
							 | 
						|
								          >
							 | 
						|
								            <thead v-if="membersData && membersData.length > 0">
							 | 
						|
								              <tr class="bg-slate-100 font-medium">
							 | 
						|
								                <th class="border border-slate-300 px-3 py-2">
							 | 
						|
								                  <label class="flex items-center gap-2">
							 | 
						|
								                    <input
							 | 
						|
								                      type="checkbox"
							 | 
						|
								                      :checked="isAllSelected"
							 | 
						|
								                      :indeterminate="isIndeterminate"
							 | 
						|
								                      @change="toggleSelectAll"
							 | 
						|
								                    />
							 | 
						|
								                    Select All
							 | 
						|
								                  </label>
							 | 
						|
								                </th>
							 | 
						|
								              </tr>
							 | 
						|
								            </thead>
							 | 
						|
								            <tbody>
							 | 
						|
								              <!-- Dynamic data from MembersList -->
							 | 
						|
								              <tr v-if="!membersData || membersData.length === 0">
							 | 
						|
								                <td
							 | 
						|
								                  class="border border-slate-300 px-3 py-2 text-center italic text-gray-500"
							 | 
						|
								                >
							 | 
						|
								                  No members need visibility settings
							 | 
						|
								                </td>
							 | 
						|
								              </tr>
							 | 
						|
								              <tr
							 | 
						|
								                v-for="member in membersData || []"
							 | 
						|
								                :key="member.member.memberId"
							 | 
						|
								              >
							 | 
						|
								                <td class="border border-slate-300 px-3 py-2">
							 | 
						|
								                  <div class="flex items-center justify-between gap-2">
							 | 
						|
								                    <label class="flex items-center gap-2">
							 | 
						|
								                      <input
							 | 
						|
								                        type="checkbox"
							 | 
						|
								                        :checked="isMemberSelected(member.did)"
							 | 
						|
								                        @change="toggleMemberSelection(member.did)"
							 | 
						|
								                      />
							 | 
						|
								                      {{ member.name || SOMEONE_UNNAMED }}
							 | 
						|
								                    </label>
							 | 
						|
								
							 | 
						|
								                    <!-- Friend indicator - only show if they are already a contact -->
							 | 
						|
								                    <font-awesome
							 | 
						|
								                      v-if="member.isContact"
							 | 
						|
								                      icon="user-circle"
							 | 
						|
								                      class="fa-fw ms-auto text-slate-400 cursor-pointer hover:text-slate-600"
							 | 
						|
								                      @click="showContactInfo"
							 | 
						|
								                    />
							 | 
						|
								                  </div>
							 | 
						|
								                </td>
							 | 
						|
								              </tr>
							 | 
						|
								            </tbody>
							 | 
						|
								          </table>
							 | 
						|
								        </div>
							 | 
						|
								
							 | 
						|
								        <div class="space-y-2">
							 | 
						|
								          <button
							 | 
						|
								            v-if="membersData && membersData.length > 0"
							 | 
						|
								            :disabled="!hasSelectedMembers"
							 | 
						|
								            :class="[
							 | 
						|
								              'block w-full text-center text-md font-bold uppercase px-2 py-2 rounded-md',
							 | 
						|
								              hasSelectedMembers
							 | 
						|
								                ? 'bg-blue-600 text-white cursor-pointer'
							 | 
						|
								                : 'bg-slate-400 text-slate-200 cursor-not-allowed',
							 | 
						|
								            ]"
							 | 
						|
								            @click="setVisibilityForSelectedMembers"
							 | 
						|
								          >
							 | 
						|
								            Set Visibility
							 | 
						|
								          </button>
							 | 
						|
								          <button
							 | 
						|
								            class="block w-full text-center text-md font-bold uppercase bg-slate-600 text-white px-2 py-2 rounded-md"
							 | 
						|
								            @click="cancel"
							 | 
						|
								          >
							 | 
						|
								            {{
							 | 
						|
								              membersData && membersData.length > 0 ? "Maybe Later" : "Cancel"
							 | 
						|
								            }}
							 | 
						|
								          </button>
							 | 
						|
								        </div>
							 | 
						|
								      </div>
							 | 
						|
								    </div>
							 | 
						|
								  </div>
							 | 
						|
								</template>
							 | 
						|
								
							 | 
						|
								<script lang="ts">
							 | 
						|
								import { Vue, Component, Prop } from "vue-facing-decorator";
							 | 
						|
								
							 | 
						|
								import { PlatformServiceMixin } from "@/utils/PlatformServiceMixin";
							 | 
						|
								import { SOMEONE_UNNAMED } from "@/constants/entities";
							 | 
						|
								import { setVisibilityUtil } from "@/libs/endorserServer";
							 | 
						|
								import { createNotifyHelpers } from "@/utils/notify";
							 | 
						|
								
							 | 
						|
								interface MemberData {
							 | 
						|
								  did: string;
							 | 
						|
								  name: string;
							 | 
						|
								  isContact: boolean;
							 | 
						|
								  member: {
							 | 
						|
								    memberId: string;
							 | 
						|
								  };
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								@Component({
							 | 
						|
								  mixins: [PlatformServiceMixin],
							 | 
						|
								})
							 | 
						|
								export default class SetBulkVisibilityDialog extends Vue {
							 | 
						|
								  @Prop({ default: false }) visible!: boolean;
							 | 
						|
								  @Prop({ default: () => [] }) membersData!: MemberData[];
							 | 
						|
								  @Prop({ default: "" }) activeDid!: string;
							 | 
						|
								  @Prop({ default: "" }) apiServer!: string;
							 | 
						|
								
							 | 
						|
								  // Vue notification system
							 | 
						|
								  $notify!: (
							 | 
						|
								    notification: { group: string; type: string; title: string; text: string },
							 | 
						|
								    timeout?: number,
							 | 
						|
								  ) => void;
							 | 
						|
								
							 | 
						|
								  // Notification system
							 | 
						|
								  notify!: ReturnType<typeof createNotifyHelpers>;
							 | 
						|
								
							 | 
						|
								  // Component state
							 | 
						|
								  selectedMembers: string[] = [];
							 | 
						|
								  selectionInitialized = false;
							 | 
						|
								
							 | 
						|
								  // Constants
							 | 
						|
								  // In Vue templates, imported constants need to be explicitly made available to the template
							 | 
						|
								  readonly SOMEONE_UNNAMED = SOMEONE_UNNAMED;
							 | 
						|
								
							 | 
						|
								  get hasSelectedMembers() {
							 | 
						|
								    return this.selectedMembers.length > 0;
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  get isAllSelected() {
							 | 
						|
								    if (!this.membersData || this.membersData.length === 0) return false;
							 | 
						|
								    return this.membersData.every((member) =>
							 | 
						|
								      this.selectedMembers.includes(member.did),
							 | 
						|
								    );
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  get isIndeterminate() {
							 | 
						|
								    if (!this.membersData || this.membersData.length === 0) return false;
							 | 
						|
								    const selectedCount = this.membersData.filter((member) =>
							 | 
						|
								      this.selectedMembers.includes(member.did),
							 | 
						|
								    ).length;
							 | 
						|
								    return selectedCount > 0 && selectedCount < this.membersData.length;
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  get shouldInitializeSelection() {
							 | 
						|
								    // This method will initialize selection when the dialog opens
							 | 
						|
								    if (!this.selectionInitialized) {
							 | 
						|
								      this.initializeSelection();
							 | 
						|
								      this.selectionInitialized = true;
							 | 
						|
								    }
							 | 
						|
								    return true;
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  created() {
							 | 
						|
								    this.notify = createNotifyHelpers(this.$notify);
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  initializeSelection() {
							 | 
						|
								    // Reset selection when dialog opens
							 | 
						|
								    this.selectedMembers = [];
							 | 
						|
								    // Select all by default
							 | 
						|
								    this.selectedMembers = this.membersData.map((member) => member.did);
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  resetSelection() {
							 | 
						|
								    this.selectedMembers = [];
							 | 
						|
								    this.selectionInitialized = false;
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  toggleSelectAll() {
							 | 
						|
								    if (!this.membersData || this.membersData.length === 0) return;
							 | 
						|
								
							 | 
						|
								    if (this.isAllSelected) {
							 | 
						|
								      // Deselect all
							 | 
						|
								      this.selectedMembers = [];
							 | 
						|
								    } else {
							 | 
						|
								      // Select all
							 | 
						|
								      this.selectedMembers = this.membersData.map((member) => member.did);
							 | 
						|
								    }
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  toggleMemberSelection(memberDid: string) {
							 | 
						|
								    const index = this.selectedMembers.indexOf(memberDid);
							 | 
						|
								    if (index > -1) {
							 | 
						|
								      this.selectedMembers.splice(index, 1);
							 | 
						|
								    } else {
							 | 
						|
								      this.selectedMembers.push(memberDid);
							 | 
						|
								    }
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  isMemberSelected(memberDid: string) {
							 | 
						|
								    return this.selectedMembers.includes(memberDid);
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  async setVisibilityForSelectedMembers() {
							 | 
						|
								    try {
							 | 
						|
								      const selectedMembers = this.membersData.filter((member) =>
							 | 
						|
								        this.selectedMembers.includes(member.did),
							 | 
						|
								      );
							 | 
						|
								      const notSelectedMembers = this.membersData.filter((member) =>
							 | 
						|
								        !this.selectedMembers.includes(member.did),
							 | 
						|
								      );
							 | 
						|
								
							 | 
						|
								      let successCount = 0;
							 | 
						|
								
							 | 
						|
								      for (const member of selectedMembers) {
							 | 
						|
								        try {
							 | 
						|
								          // If they're not a contact yet, add them as a contact first
							 | 
						|
								          if (!member.isContact) {
							 | 
						|
								            await this.addAsContact(member);
							 | 
						|
								          }
							 | 
						|
								
							 | 
						|
								          // Set their seesMe to true
							 | 
						|
								          await this.updateContactVisibility(member.did, true);
							 | 
						|
								
							 | 
						|
								          successCount++;
							 | 
						|
								        } catch (error) {
							 | 
						|
								          // eslint-disable-next-line no-console
							 | 
						|
								          console.error(`Error processing member ${member.did}:`, error);
							 | 
						|
								          // Continue with other members even if one fails
							 | 
						|
								        }
							 | 
						|
								      }
							 | 
						|
								
							 | 
						|
								      // Show success notification
							 | 
						|
								      this.$notify(
							 | 
						|
								        {
							 | 
						|
								          group: "alert",
							 | 
						|
								          type: "success",
							 | 
						|
								          title: "Visibility Set Successfully",
							 | 
						|
								          text: `Visibility set for ${successCount} member${successCount === 1 ? "" : "s"}.`,
							 | 
						|
								        },
							 | 
						|
								        5000,
							 | 
						|
								      );
							 | 
						|
								
							 | 
						|
								      // Emit success event
							 | 
						|
								      this.$emit("close", { notSelectedMemberDids: notSelectedMembers.map((member) => member.did) });
							 | 
						|
								      this.close();
							 | 
						|
								    } catch (error) {
							 | 
						|
								      // eslint-disable-next-line no-console
							 | 
						|
								      console.error("Error setting visibility:", error);
							 | 
						|
								      this.$notify(
							 | 
						|
								        {
							 | 
						|
								          group: "alert",
							 | 
						|
								          type: "danger",
							 | 
						|
								          title: "Error",
							 | 
						|
								          text: "Failed to set visibility for some members. Please try again.",
							 | 
						|
								        },
							 | 
						|
								        5000,
							 | 
						|
								      );
							 | 
						|
								    }
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  async addAsContact(member: { did: string; name: string }) {
							 | 
						|
								    try {
							 | 
						|
								      const newContact = {
							 | 
						|
								        did: member.did,
							 | 
						|
								        name: member.name,
							 | 
						|
								      };
							 | 
						|
								
							 | 
						|
								      await this.$insertContact(newContact);
							 | 
						|
								    } catch (err) {
							 | 
						|
								      // eslint-disable-next-line no-console
							 | 
						|
								      console.error("Error adding contact:", err);
							 | 
						|
								      if (err instanceof Error && err.message?.indexOf("already exists") > -1) {
							 | 
						|
								        // Contact already exists, continue
							 | 
						|
								      } else {
							 | 
						|
								        throw err; // Re-throw if it's not a duplicate error
							 | 
						|
								      }
							 | 
						|
								    }
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  async updateContactVisibility(did: string, seesMe: boolean) {
							 | 
						|
								    try {
							 | 
						|
								      // Get the contact object
							 | 
						|
								      const contact = await this.$getContact(did);
							 | 
						|
								      if (!contact) {
							 | 
						|
								        throw new Error(`Contact not found for DID: ${did}`);
							 | 
						|
								      }
							 | 
						|
								
							 | 
						|
								      // Use the proper API to set visibility on the server
							 | 
						|
								      const result = await setVisibilityUtil(
							 | 
						|
								        this.activeDid,
							 | 
						|
								        this.apiServer,
							 | 
						|
								        this.axios,
							 | 
						|
								        contact,
							 | 
						|
								        seesMe,
							 | 
						|
								      );
							 | 
						|
								
							 | 
						|
								      if (!result.success) {
							 | 
						|
								        throw new Error(result.error || "Failed to set visibility");
							 | 
						|
								      }
							 | 
						|
								    } catch (err) {
							 | 
						|
								      // eslint-disable-next-line no-console
							 | 
						|
								      console.error("Error updating contact visibility:", err);
							 | 
						|
								      throw err;
							 | 
						|
								    }
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  showContactInfo() {
							 | 
						|
								    this.$notify(
							 | 
						|
								      {
							 | 
						|
								        group: "alert",
							 | 
						|
								        type: "info",
							 | 
						|
								        title: "Contact Info",
							 | 
						|
								        text: "This user is already your contact, but your activities are not visible to them yet.",
							 | 
						|
								      },
							 | 
						|
								      5000,
							 | 
						|
								    );
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  close() {
							 | 
						|
								    this.resetSelection();
							 | 
						|
								    this.$emit("close", { notSelectedMemberDids: this.membersData.map((member) => member.did) });
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  cancel() {
							 | 
						|
								    this.close();
							 | 
						|
								  }
							 | 
						|
								}
							 | 
						|
								</script>
							 | 
						|
								
							 |