@ -371,49 +371,65 @@
< / p >
<!-- Custom table area - you can customize this -- >
< div class = "mb-4" >
< div
v - if = "shouldInitializeSelection(notification)"
class = "mb-4"
>
< table
class = "w-full border-collapse border border-slate-300 text-sm text-start"
>
< thead >
< thead
v - if = "
notification . membersData &&
notification . 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 / >
< input
type = "checkbox"
: checked = "isAllSelected(notification)"
: indeterminate = "isIndeterminate(notification)"
@ change = "toggleSelectAll(notification)"
/ >
Select All
< / label >
< / th >
< / tr >
< / thead >
< tbody >
<!-- Sample data - replace with your actual data -- >
< tr >
< 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 / >
John Doe
< / label >
<!-- Friend indicator -- >
< font -awesome
icon = "user-circle"
class = "fa-fw ms-auto text-slate-400 cursor-pointer hover:text-slate-600"
@ click = "showContactInfo"
/ >
< / div >
<!-- Dynamic data from MembersList -- >
< tr
v - if = "
! notification . membersData ||
notification . 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 >
< tr
v - for = "member in notification.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 / >
Jane Smith
< input
type = "checkbox"
: checked = "isMemberSelected(member.did)"
@ change = "toggleMemberSelection(member.did)"
/ >
{ { member . name || SOMEONE_UNNAMED } }
< / label >
<!-- Friend indicator -- >
<!-- 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"
@ -421,45 +437,40 @@
< / div >
< / td >
< / tr >
< tr >
< 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 / >
Jim Beam
< / label >
< / div >
< / td >
< / tr >
< tr >
< 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 / >
Susie Q
< / label >
< / div >
< / td >
< / tr >
< / tbody >
< / table >
< / div >
< div class = "space-y-2" >
< button
class = "block w-full text-center text-md font-bold uppercase bg-blue-600 text-white px-2 py-2 rounded-md"
v - if = "
notification . membersData &&
notification . 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 = "
notification . onYes ? notification . onYes ( ) : null ;
close ( notification . id ) ;
setVisibilityForSelectedMembers ( notification ) ;
closeDialog ( notification , close ) ;
"
>
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 = "close(notification.id)"
@ click = "closeDialog(notification, close )"
>
Maybe Later
{ {
notification . membersData &&
notification . membersData . length > 0
? "Maybe Later"
: "Cancel"
} }
< / button >
< / div >
< / div >
@ -477,6 +488,9 @@ import { Vue, Component } from "vue-facing-decorator";
import { NotificationIface } from "./constants/app" ;
import { PlatformServiceMixin } from "@/utils/PlatformServiceMixin" ;
import { logger } from "./utils/logger" ;
/ / e s l i n t - d i s a b l e - n e x t - l i n e @ t y p e s c r i p t - e s l i n t / n o - u n u s e d - v a r s
import { SOMEONE_UNNAMED } from "@/constants/entities" ;
import { setVisibilityUtil } from "./libs/endorserServer" ;
interface Settings {
notifyingNewActivityTime ? : string ;
@ -491,6 +505,208 @@ export default class App extends Vue {
$notify ! : ( notification : NotificationIface , timeout ? : number ) => void ;
stopAsking = false ;
selectedMembers : string [ ] = [ ] ;
selectionInitialized = false ;
get hasSelectedMembers ( ) {
return this . selectedMembers . length > 0 ;
}
activeDid = "" ;
apiServer = "" ;
async created ( ) {
/ / I n i t i a l i z e s e t t i n g s
const settings = await this . $accountSettings ( ) ;
this . apiServer = settings . apiServer || "" ;
/ / G e t a c t i v e D i d f r o m a c t i v e _ i d e n t i t y t a b l e
/ / e s l i n t - d i s a b l e - n e x t - l i n e @ t y p e s c r i p t - e s l i n t / n o - e x p l i c i t - a n y
const activeIdentity = await ( this as any ) . $getActiveIdentity ( ) ;
this . activeDid = activeIdentity . activeDid || "" ;
}
isAllSelected ( notification : NotificationIface ) {
const membersData = notification ? . membersData || [ ] ;
if ( ! membersData || membersData . length === 0 ) return false ;
return membersData . every ( ( member ) =>
this . selectedMembers . includes ( member . did ) ,
) ;
}
isIndeterminate ( notification : NotificationIface ) {
const membersData = notification ? . membersData || [ ] ;
if ( ! membersData || membersData . length === 0 ) return false ;
const selectedCount = membersData . filter ( ( member ) =>
this . selectedMembers . includes ( member . did ) ,
) . length ;
return selectedCount > 0 && selectedCount < membersData . length ;
}
toggleSelectAll ( notification : NotificationIface ) {
const membersData = notification ? . membersData || [ ] ;
if ( ! membersData || membersData . length === 0 ) return ;
if ( this . isAllSelected ( notification ) ) {
/ / D e s e l e c t a l l
this . selectedMembers = [ ] ;
} else {
/ / S e l e c t a l l
this . selectedMembers = 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 ) ;
}
shouldInitializeSelection ( notification : NotificationIface ) {
/ / T h i s m e t h o d w i l l i n i t i a l i z e s e l e c t i o n w h e n t h e d i a l o g o p e n s
if (
notification ? . type === "set-visibility-meeting-members" &&
! this . selectionInitialized
) {
this . initializeSelection ( notification ) ;
this . selectionInitialized = true ;
}
return true ;
}
initializeSelection ( notification : NotificationIface ) {
/ / R e s e t s e l e c t i o n w h e n d i a l o g o p e n s
this . selectedMembers = [ ] ;
/ / S e l e c t a l l b y d e f a u l t
const membersData = notification ? . membersData || [ ] ;
this . selectedMembers = membersData . map ( ( member ) => member . did ) ;
}
resetSelection ( ) {
this . selectedMembers = [ ] ;
this . selectionInitialized = false ;
}
async setVisibilityForSelectedMembers ( notification : NotificationIface ) {
try {
const membersData = notification ? . membersData || [ ] ;
const selectedMembers = membersData . filter ( ( member ) =>
this . selectedMembers . includes ( member . did ) ,
) ;
let successCount = 0 ;
for ( const member of selectedMembers ) {
try {
/ / I f t h e y ' r e n o t a c o n t a c t y e t , a d d t h e m a s a c o n t a c t f i r s t
if ( ! member . isContact ) {
await this . addAsContact ( member ) ;
}
/ / S e t t h e i r s e e s M e t o t r u e
await this . updateContactVisibility ( member . did , true ) ;
successCount ++ ;
} catch ( error ) {
/ / e s l i n t - d i s a b l e - n e x t - l i n e n o - c o n s o l e
console . error ( ` Error processing member ${ member . did } : ` , error ) ;
/ / C o n t i n u e w i t h o t h e r m e m b e r s e v e n i f o n e f a i l s
}
}
/ / S h o w s u c c e s s n o t i f i c a t i o n
this . $notify (
{
group : "alert" ,
type : "success" ,
title : "Visibility Set Successfully" ,
text : ` Visibility set for ${ successCount } member ${ successCount === 1 ? "" : "s" } . ` ,
} ,
5000 ,
) ;
} catch ( error ) {
/ / e s l i n t - d i s a b l e - n e x t - l i n e n o - c o n s o l e
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 ) {
/ / e s l i n t - d i s a b l e - n e x t - l i n e n o - c o n s o l e
console . error ( "Error adding contact:" , err ) ;
if ( err instanceof Error && err . message ? . indexOf ( "already exists" ) > - 1 ) {
/ / C o n t a c t a l r e a d y e x i s t s , c o n t i n u e
} else {
throw err ; / / R e - t h r o w i f i t ' s n o t a d u p l i c a t e e r r o r
}
}
}
async updateContactVisibility ( did : string , seesMe : boolean ) {
try {
/ / G e t t h e c o n t a c t o b j e c t
const contact = await this . $getContact ( did ) ;
if ( ! contact ) {
throw new Error ( ` Contact not found for DID: ${ did } ` ) ;
}
/ / U s e t h e p r o p e r A P I t o s e t v i s i b i l i t y o n t h e s e r v e r
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 ) {
/ / e s l i n t - d i s a b l e - n e x t - l i n e n o - c o n s o l e
console . error ( "Error updating contact visibility:" , err ) ;
throw err ;
}
}
async closeDialog (
notification : NotificationIface ,
closeFn : ( id : string ) => void ,
) {
this . resetSelection ( ) ;
/ / C l o s e t h e n o t i f i c a t i o n f i r s t
closeFn ( notification . id ) ;
/ / T h e n c a l l t h e c a l l b a c k a f t e r a s h o r t d e l a y t o e n s u r e d i a l o g i s c l o s e d
setTimeout ( async ( ) => {
if ( notification . callback ) {
await notification . callback ( ) ;
}
} , 100 ) ;
}
showContactInfo ( ) {
this . $notify (