forked from jsnbuchanan/crowd-funder-for-time-pwa
refactor: rename SetVisibilityDialog to SetBulkVisibilityDialog and remove unused code
- Rename SetVisibilityDialog.vue to SetBulkVisibilityDialog.vue for better clarity - Update all component references in MembersList.vue (import, registration, template usage) - Update component class name from SetVisibilityDialog to SetBulkVisibilityDialog - Rename calling function name to showSetBulkVisibilityDialog to match class name change - Remove unused properties and created() method from App.vue This cleanup removes dead code and improves component naming consistency.
This commit is contained in:
333
src/components/SetBulkVisibilityDialog.vue
Normal file
333
src/components/SetBulkVisibilityDialog.vue
Normal file
@@ -0,0 +1,333 @@
|
||||
<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),
|
||||
);
|
||||
|
||||
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("success", successCount);
|
||||
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");
|
||||
}
|
||||
|
||||
cancel() {
|
||||
this.close();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
Reference in New Issue
Block a user