@ -8,6 +8,7 @@
<!-- Back -- >
<!-- Back -- >
< button
< button
class = "text-lg text-center px-2 py-1 absolute -left-2 -top-1"
class = "text-lg text-center px-2 py-1 absolute -left-2 -top-1"
aria - label = "Go back"
@ click = "$router.go(-1)"
@ click = "$router.go(-1)"
>
>
< font -awesome icon = "chevron-left" class = "fa-fw" / >
< font -awesome icon = "chevron-left" class = "fa-fw" / >
@ -26,14 +27,7 @@
capitalizeAndInsertSpacesBeforeCaps ( veriClaim . claimType || "" )
capitalizeAndInsertSpacesBeforeCaps ( veriClaim . claimType || "" )
} }
} }
< button
< button
v - if = "
v - if = "canEditClaim"
[ 'GiveAction' , 'Offer' , 'PlanAction' ] . includes (
veriClaim . claimType as string ,
) && veriClaim . issuer === activeDid
/ / a P l a n A c t i o n a g e n t a l s o c o u l d e d i t o n e o f t h o s e ,
/ / b u t r a t h e r t h a n a d d m o r e P l a n - s p e c i f i c l o g i c t o d e t e c t t h e a g e n t
/ / w e ' l l l e t t h e m c l i c k t h e P r o j e c t l i n k a n d e d i t f r o m t h e r e
"
title = "Edit"
title = "Edit"
data - testId = "editClaimButton"
data - testId = "editClaimButton"
@ click = "onClickEditClaim"
@ click = "onClickEditClaim"
@ -60,6 +54,7 @@
v - if = "veriClaim.id"
v - if = "veriClaim.id"
class = "text-blue-500 ml-2 mt-2"
class = "text-blue-500 ml-2 mt-2"
title = "Copy Printable Certificate Link"
title = "Copy Printable Certificate Link"
aria - label = "Copy printable certificate link"
@ click = "
@ click = "
copyToClipboard (
copyToClipboard (
'A link to the certificate page' ,
'A link to the certificate page' ,
@ -74,6 +69,7 @@
< div class = "flex justify-end w-full" >
< div class = "flex justify-end w-full" >
< button
< button
title = "Copy Link"
title = "Copy Link"
aria - label = "Copy page link"
@ click = "copyToClipboard('A link to this page', windowDeepLink)"
@ click = "copyToClipboard('A link to this page', windowDeepLink)"
>
>
< font -awesome icon = "link" class = "text-slate-500" / >
< font -awesome icon = "link" class = "text-slate-500" / >
@ -83,11 +79,7 @@
< div class = "text-sm" >
< div class = "text-sm" >
< div data -testId = " description " >
< div data -testId = " description " >
< font -awesome icon = "message" class = "fa-fw text-slate-400" / >
< font -awesome icon = "message" class = "fa-fw text-slate-400" / >
{ {
{ { claimDescription } }
( veriClaim . claim ? . itemOffered as any ) ? . description ||
( veriClaim . claim as any ) ? . description ||
""
} }
< / div >
< / div >
< div >
< div >
< font -awesome icon = "user" class = "fa-fw text-slate-400" / >
< font -awesome icon = "user" class = "fa-fw text-slate-400" / >
@ -96,17 +88,11 @@
< div >
< div >
< font -awesome icon = "calendar" class = "fa-fw text-slate-400" / >
< font -awesome icon = "calendar" class = "fa-fw text-slate-400" / >
Recorded
Recorded
{ { veriClaim . issuedAt ? . replace ( /T/ , " " ) . replace ( /Z/ , " UTC" ) } }
{ { formattedIssueDate } }
< / div >
< / div >
< div
< div v-if ="claimImage" class="flex justify-center" >
v - if = "(veriClaim.claim as any).image"
< a :href ="claimImage" target = "_blank" >
class = "flex justify-center"
< img :src ="claimImage" class = "h-24 rounded-xl" / >
>
< a : href = "(veriClaim.claim as any).image" target = "_blank" >
< img
: src = "(veriClaim.claim as any).image"
class = "h-24 rounded-xl"
/ >
< / a >
< / a >
< / div >
< / div >
@ -183,14 +169,7 @@
< div class = "grow overflow-hidden" >
< div class = "grow overflow-hidden" >
< a
< a
class = "text-blue-500 mt-4 cursor-pointer"
class = "text-blue-500 mt-4 cursor-pointer"
@ click = "
@ click = "handleProviderClick(provider)"
provider . identifier . startsWith ( 'did:' )
? $router . push (
'/did/' +
encodeURIComponent ( provider . identifier ) ,
)
: showDifferentClaimPage ( provider . identifier )
"
>
>
an activity ...
an activity ...
< / a >
< / a >
@ -266,13 +245,7 @@
< / div >
< / div >
< div class = "mt-2" >
< div class = "mt-2" >
< span v-if ="totalConfirmers() === 0" > Nobody has confirmed this. < / span >
{ { confirmationStatusText } }
< span v -else -if = " totalConfirmers ( ) = = = 1 " >
One person has confirmed this .
< / span >
< span v-else >
{ { totalConfirmers ( ) } } people have confirmed this .
< / span >
< / div >
< / div >
< div v-if ="totalConfirmers() > 0" >
< div v-if ="totalConfirmers() > 0" >
@ -392,13 +365,7 @@
< font -awesome v -else icon = "chevron-right" / >
< font -awesome v -else icon = "chevron-right" / >
< / h2 >
< / h2 >
< div v-if ="showVeriClaimDump" >
< div v-if ="showVeriClaimDump" >
< div
< div v-if ="isFullyHidden" class="mb-2" >
v - if = "
serverUtil . containsHiddenDid ( veriClaim ) &&
R . isEmpty ( veriClaimDidsVisible )
"
class = "mb-2"
>
Some of the details are not visible to you ; they show as "HIDDEN" . They
Some of the details are not visible to you ; they show as "HIDDEN" . They
are not visible to any of your direct contacts , either .
are not visible to any of your direct contacts , either .
< span v-if ="canShare" >
< span v-if ="canShare" >
@ -425,7 +392,7 @@
< / span >
< / span >
< / div >
< / div >
< div v-if ="!R.isEmpty(veriClaimDidsVisible) " >
< div v-if ="hasPartialVisibility " >
Some of the details are not visible to you but they are visible to some
Some of the details are not visible to you but they are visible to some
of your contacts .
of your contacts .
< span v-if ="canShare" >
< span v-if ="canShare" >
@ -484,11 +451,7 @@
class = "text-blue-500"
class = "text-blue-500"
>
>
< font -awesome icon = "globe" class = "fa-fw" / >
< font -awesome icon = "globe" class = "fa-fw" / >
{ {
{ { extractDomain ( veriClaim . publicUrls [ visDid ] || "" ) } }
veriClaim . publicUrls [ visDid ] . substring (
veriClaim . publicUrls [ visDid ] . indexOf ( "//" ) + 2 ,
)
} }
< / a >
< / a >
< / span >
< / span >
< / span >
< / span >
@ -560,9 +523,13 @@ import QuickNav from "../components/QuickNav.vue";
import { APP_SERVER , NotificationIface } from "../constants/app" ;
import { APP_SERVER , NotificationIface } from "../constants/app" ;
import { Contact } from "../db/tables/contacts" ;
import { Contact } from "../db/tables/contacts" ;
import * as serverUtil from "../libs/endorserServer" ;
import * as serverUtil from "../libs/endorserServer" ;
import { GenericCredWrapper , OfferClaim , ProviderInfo } from "../interfaces" ;
import {
GenericCredWrapper ,
OfferClaim ,
GiveActionClaim ,
ProviderInfo ,
} from "../interfaces" ;
import * as libsUtil from "../libs/util" ;
import * as libsUtil from "../libs/util" ;
import { logger } from "../utils/logger" ;
import { PlatformServiceMixin } from "@/utils/PlatformServiceMixin" ;
import { PlatformServiceMixin } from "@/utils/PlatformServiceMixin" ;
@ Component ( {
@ Component ( {
@ -609,7 +576,102 @@ export default class ClaimView extends Vue {
yaml = yaml ;
yaml = yaml ;
libsUtil = libsUtil ;
libsUtil = libsUtil ;
serverUtil = serverUtil ;
serverUtil = serverUtil ;
window = window ;
/ / = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
/ / C O M P U T E D P R O P E R T I E S
/ / = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
/ * *
* Whether the current user can edit this claim
* /
get canEditClaim ( ) : boolean {
return (
[ "GiveAction" , "Offer" , "PlanAction" ] . includes (
this . veriClaim . claimType as string ,
) && this . veriClaim . issuer === this . activeDid
) ;
}
/ * *
* The description to display for this claim
* /
get claimDescription ( ) : string {
const claim = this . veriClaim . claim ;
/ / H a n d l e O f f e r c l a i m s w i t h i t e m O f f e r e d
if ( this . veriClaim . claimType === "Offer" ) {
const offerClaim = claim as OfferClaim ;
return (
offerClaim . itemOffered ? . description || offerClaim . description || ""
) ;
}
/ / H a n d l e G i v e A c t i o n c l a i m s
if ( this . veriClaim . claimType === "GiveAction" ) {
const giveClaim = claim as GiveActionClaim ;
return giveClaim . description || "" ;
}
/ / F a l l b a c k f o r o t h e r c l a i m t y p e s
return ( claim as { description ? : string } ) ? . description || "" ;
}
/ * *
* Formatted issue date for display
* /
get formattedIssueDate ( ) : string {
return (
this . veriClaim . issuedAt ? . replace ( /T/ , " " ) . replace ( /Z/ , " UTC" ) || ""
) ;
}
/ * *
* Text describing the confirmation status
* /
get confirmationStatusText ( ) : string {
const count = this . totalConfirmers ( ) ;
if ( count === 0 ) return "Nobody has confirmed this." ;
if ( count === 1 ) return "One person has confirmed this." ;
return ` ${ count } people have confirmed this. ` ;
}
/ * *
* Whether the claim is fully hidden from the user
* /
get isFullyHidden ( ) : boolean {
return (
serverUtil . containsHiddenDid ( this . veriClaim ) &&
R . isEmpty ( this . veriClaimDidsVisible )
) ;
}
/ * *
* Whether the claim has some visibility through contacts
* /
get hasPartialVisibility ( ) : boolean {
return ! R . isEmpty ( this . veriClaimDidsVisible ) ;
}
/ * *
* The image URL for this claim if available
* /
get claimImage ( ) : string | undefined {
const claim = this . veriClaim . claim ;
/ / H a n d l e d i f f e r e n t c l a i m t y p e s t h a t m i g h t h a v e i m a g e s
if ( this . veriClaim . claimType === "Offer" ) {
const offerClaim = claim as OfferClaim ;
return offerClaim . image ;
}
if ( this . veriClaim . claimType === "GiveAction" ) {
const giveClaim = claim as GiveActionClaim ;
return giveClaim . image ;
}
/ / F a l l b a c k f o r o t h e r c l a i m t y p e s
return ( claim as { image ? : string } ) ? . image ;
}
resetThisValues ( ) {
resetThisValues ( ) {
this . confirmerIdList = [ ] ;
this . confirmerIdList = [ ] ;
@ -628,6 +690,28 @@ export default class ClaimView extends Vue {
this . veriClaimDidsVisible = { } ;
this . veriClaimDidsVisible = { } ;
}
}
/ / = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
/ / U T I L I T Y M E T H O D S
/ / = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
/ * *
* Handle provider click navigation
* /
handleProviderClick ( provider : ProviderInfo ) : void {
if ( provider . identifier . startsWith ( "did:" ) ) {
this . $router . push ( "/did/" + encodeURIComponent ( provider . identifier ) ) ;
} else {
this . showDifferentClaimPage ( provider . identifier ) ;
}
}
/ * *
* Extract domain from URL for display
* /
extractDomain ( url : string ) : string {
return url . substring ( url . indexOf ( "//" ) + 2 ) ;
}
async created ( ) {
async created ( ) {
const settings = await this . $settings ( ) ;
const settings = await this . $settings ( ) ;
@ -640,7 +724,7 @@ export default class ClaimView extends Vue {
try {
try {
this . allMyDids = await libsUtil . retrieveAccountDids ( ) ;
this . allMyDids = await libsUtil . retrieveAccountDids ( ) ;
} catch ( error ) {
} catch ( error ) {
await logger . toConsoleAndDb (
await this . $logAndConsole (
"Error retrieving all account DIDs on home page:" + error ,
"Error retrieving all account DIDs on home page:" + error ,
true ,
true ,
) ;
) ;
@ -676,10 +760,9 @@ export default class ClaimView extends Vue {
/ / i n s e r t a s p a c e b e f o r e a n y c a p i t a l l e t t e r s e x c e p t t h e i n i t i a l l e t t e r
/ / i n s e r t a s p a c e b e f o r e a n y c a p i t a l l e t t e r s e x c e p t t h e i n i t i a l l e t t e r
/ / ( a n d c a p i t a l i z e i n i t i a l l e t t e r , j u s t i n c a s e )
/ / ( a n d c a p i t a l i z e i n i t i a l l e t t e r , j u s t i n c a s e )
capitalizeAndInsertSpacesBeforeCaps ( text : string ) {
capitalizeAndInsertSpacesBeforeCaps ( text : string ) : string {
return ! text
if ( ! text ) return "" ;
? ""
return text [ 0 ] . toUpperCase ( ) + text . substr ( 1 ) . replace ( /([A-Z])/g , " $1" ) ;
: text [ 0 ] . toUpperCase ( ) + text . substr ( 1 ) . replace ( /([A-Z])/g , " $1" ) ;
}
}
totalConfirmers ( ) {
totalConfirmers ( ) {
@ -691,7 +774,7 @@ export default class ClaimView extends Vue {
}
}
/ / I s n ' t t h e r e a b e t t e r w a y t o m a k e t h i s a v a i l a b l e t o t h e t e m p l a t e ?
/ / I s n ' t t h e r e a b e t t e r w a y t o m a k e t h i s a v a i l a b l e t o t h e t e m p l a t e ?
didInfo ( did : string ) {
didInfo ( did : string ) : string {
return serverUtil . didInfo (
return serverUtil . didInfo (
did ,
did ,
this . activeDid ,
this . activeDid ,
@ -719,7 +802,7 @@ export default class ClaimView extends Vue {
) ;
) ;
} else {
} else {
/ / a c t u a l l y , a x i o s t y p i c a l l y t h r o w s a n e r r o r s o w e n e v e r g e t h e r e
/ / a c t u a l l y , a x i o s t y p i c a l l y t h r o w s a n e r r o r s o w e n e v e r g e t h e r e
logger . error ( "Error getting claim:" , resp ) ;
await this . $logError ( "Error getting claim: " + JSON . stringify ( resp ) ) ;
this . $notify (
this . $notify (
{
{
group : "alert" ,
group : "alert" ,
@ -747,7 +830,9 @@ export default class ClaimView extends Vue {
if ( giveResp . status === 200 && giveResp . data . data ? . length > 0 ) {
if ( giveResp . status === 200 && giveResp . data . data ? . length > 0 ) {
this . detailsForGive = giveResp . data . data [ 0 ] ;
this . detailsForGive = giveResp . data . data [ 0 ] ;
} else {
} else {
logger . error ( "Error getting detailed give info:" , giveResp ) ;
await this . $logError (
"Error getting detailed give info: " + JSON . stringify ( giveResp ) ,
) ;
}
}
/ / l o o k f o r p r o v i d e r s
/ / l o o k f o r p r o v i d e r s
@ -766,7 +851,9 @@ export default class ClaimView extends Vue {
) {
) {
this . providersForGive = providerResp . data . data ;
this . providersForGive = providerResp . data . data ;
} else {
} else {
logger . error ( "Error getting give providers:" , giveResp ) ;
await this . $logError (
"Error getting give providers: " + JSON . stringify ( giveResp ) ,
) ;
this . $notify (
this . $notify (
{
{
group : "alert" ,
group : "alert" ,
@ -789,7 +876,9 @@ export default class ClaimView extends Vue {
if ( offerResp . status === 200 ) {
if ( offerResp . status === 200 ) {
this . detailsForOffer = offerResp . data . data [ 0 ] ;
this . detailsForOffer = offerResp . data . data [ 0 ] ;
} else {
} else {
logger . error ( "Error getting detailed offer info:" , offerResp ) ;
await this . $logError (
"Error getting detailed offer info: " + JSON . stringify ( offerResp ) ,
) ;
this . $notify (
this . $notify (
{
{
group : "alert" ,
group : "alert" ,
@ -819,7 +908,9 @@ export default class ClaimView extends Vue {
}
}
} catch ( error : unknown ) {
} catch ( error : unknown ) {
const serverError = error as AxiosError ;
const serverError = error as AxiosError ;
logger . error ( "Error retrieving claim:" , serverError ) ;
await this . $logError (
"Error retrieving claim: " + JSON . stringify ( serverError ) ,
) ;
this . $notify (
this . $notify (
{
{
group : "alert" ,
group : "alert" ,
@ -844,7 +935,9 @@ export default class ClaimView extends Vue {
this . fullClaimDump = yaml . dump ( this . fullClaim ) ;
this . fullClaimDump = yaml . dump ( this . fullClaim ) ;
} else {
} else {
/ / a c t u a l l y , a x i o s t y p i c a l l y t h r o w s a n e r r o r s o w e n e v e r g e t h e r e
/ / a c t u a l l y , a x i o s t y p i c a l l y t h r o w s a n e r r o r s o w e n e v e r g e t h e r e
logger . error ( "Error getting full claim:" , resp ) ;
await this . $logError (
"Error getting full claim: " + JSON . stringify ( resp ) ,
) ;
this . $notify (
this . $notify (
{
{
group : "alert" ,
group : "alert" ,
@ -856,7 +949,9 @@ export default class ClaimView extends Vue {
) ;
) ;
}
}
} catch ( error : unknown ) {
} catch ( error : unknown ) {
logger . error ( "Error retrieving full claim:" , error ) ;
await this . $logError (
"Error retrieving full claim: " + JSON . stringify ( error ) ,
) ;
const serverError = error as AxiosError ;
const serverError = error as AxiosError ;
if ( serverError . response ? . status === 403 ) {
if ( serverError . response ? . status === 403 ) {
let issuerPhrase = "" ;
let issuerPhrase = "" ;
@ -951,7 +1046,9 @@ export default class ClaimView extends Vue {
5000 ,
5000 ,
) ;
) ;
} else {
} else {
logger . error ( "Got error submitting the confirmation:" , result ) ;
await this . $logError (
"Got error submitting the confirmation: " + JSON . stringify ( result ) ,
) ;
this . $notify (
this . $notify (
{
{
group : "alert" ,
group : "alert" ,
@ -1013,7 +1110,7 @@ export default class ClaimView extends Vue {
} ) ;
} ) ;
}
}
onClickEditClaim ( ) {
async onClickEditClaim ( ) {
if ( this . veriClaim . claimType === "GiveAction" ) {
if ( this . veriClaim . claimType === "GiveAction" ) {
const route = {
const route = {
name : "gifted-details" ,
name : "gifted-details" ,
@ -1041,9 +1138,8 @@ export default class ClaimView extends Vue {
} ;
} ;
( this . $router as Router ) . push ( route ) ;
( this . $router as Router ) . push ( route ) ;
} else {
} else {
logger . error (
await this . $logError (
"Unrecognized claim type for edit:" ,
"Unrecognized claim type for edit: " + this . veriClaim . claimType ,
this . veriClaim . claimType ,
) ;
) ;
this . $notify (
this . $notify (
{
{