|
|
@ -139,7 +139,7 @@ |
|
|
|
<button |
|
|
|
v-if="contact.seesMe" |
|
|
|
class="text-sm uppercase bg-gradient-to-b from-slate-400 to-slate-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white mx-0.5 my-0.5 px-2 py-1.5 rounded-md" |
|
|
|
@click="setVisibility(contact, false, true)" |
|
|
|
@click="promptSetVisibility(contact, false)" |
|
|
|
title="They can see you" |
|
|
|
> |
|
|
|
<fa icon="eye" class="fa-fw" /> |
|
|
@ -147,7 +147,7 @@ |
|
|
|
<button |
|
|
|
v-else |
|
|
|
class="text-sm uppercase bg-gradient-to-b from-slate-400 to-slate-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white mx-0.5 my-0.5 px-2 py-1.5 rounded-md" |
|
|
|
@click="setVisibility(contact, true, true)" |
|
|
|
@click="promptSetVisibility(contact, true)" |
|
|
|
title="They cannot see you" |
|
|
|
> |
|
|
|
<fa icon="eye-slash" class="fa-fw" /> |
|
|
@ -161,7 +161,7 @@ |
|
|
|
<fa icon="rotate" class="fa-fw" /> |
|
|
|
</button> |
|
|
|
<button |
|
|
|
@click="register(contact)" |
|
|
|
@click="promptRegister(contact)" |
|
|
|
class="text-sm uppercase bg-gradient-to-b from-slate-400 to-slate-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white ml-6 px-2 py-1.5 rounded-md" |
|
|
|
v-if="activeDid" |
|
|
|
title="Registration" |
|
|
@ -176,7 +176,7 @@ |
|
|
|
</div> |
|
|
|
|
|
|
|
<button |
|
|
|
@click="deleteContact(contact)" |
|
|
|
@click="promptDeleteContact(contact)" |
|
|
|
class="text-sm uppercase bg-gradient-to-b from-rose-500 to-rose-800 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white ml-6 px-2 py-1.5 rounded-md" |
|
|
|
title="Delete" |
|
|
|
> |
|
|
@ -189,7 +189,7 @@ |
|
|
|
> |
|
|
|
<button |
|
|
|
class="text-sm bg-gradient-to-b from-blue-400 to-blue-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-2 py-1.5 rounded-l-md" |
|
|
|
@click="showGiftedDialog(activeDid, contact.did)" |
|
|
|
@click="promptShowGiftedDialog(activeDid, contact.did)" |
|
|
|
:title="givenByMeDescriptions[contact.did] || ''" |
|
|
|
> |
|
|
|
To: |
|
|
@ -210,7 +210,7 @@ |
|
|
|
|
|
|
|
<button |
|
|
|
class="text-sm bg-gradient-to-b from-blue-400 to-blue-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white -ml-1.5 px-2 py-1.5 rounded-r-md border-l" |
|
|
|
@click="showGiftedDialog(contact.did, this.activeDid)" |
|
|
|
@click="promptShowGiftedDialog(contact.did, this.activeDid)" |
|
|
|
:title="givenToMeDescriptions[contact.did] || ''" |
|
|
|
> |
|
|
|
From: |
|
|
@ -781,211 +781,242 @@ export default class ContactsView extends Vue { |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
async deleteContact(contact: Contact) { |
|
|
|
if ( |
|
|
|
confirm( |
|
|
|
"You should first make sure that your activity is no longer visible to them." + |
|
|
|
" Note that this only deletes them from your contacts on this device." + |
|
|
|
" \n\nAre you sure you want to remove " + |
|
|
|
// prompt with confirmation if they want to delete a contact |
|
|
|
promptDeleteContact(contact: Contact) { |
|
|
|
this.$notify( |
|
|
|
{ |
|
|
|
group: "modal", |
|
|
|
type: "confirm", |
|
|
|
title: "Delete", |
|
|
|
text: |
|
|
|
"Are you sure you want to remove " + |
|
|
|
this.nameForDid(this.contacts, contact.did) + |
|
|
|
" with DID " + |
|
|
|
contact.did + |
|
|
|
" from your contact list?", |
|
|
|
) |
|
|
|
) { |
|
|
|
await db.open(); |
|
|
|
await db.contacts.delete(contact.did); |
|
|
|
this.contacts = R.without([contact], this.contacts); |
|
|
|
} |
|
|
|
onYes: async () => { |
|
|
|
await this.deleteContact(contact); |
|
|
|
}, |
|
|
|
}, |
|
|
|
-1, |
|
|
|
); |
|
|
|
} |
|
|
|
|
|
|
|
async register(contact: Contact) { |
|
|
|
if ( |
|
|
|
confirm( |
|
|
|
"Are you sure you want to register " + |
|
|
|
async deleteContact(contact: Contact) { |
|
|
|
await db.open(); |
|
|
|
await db.contacts.delete(contact.did); |
|
|
|
this.contacts = R.without([contact], this.contacts); |
|
|
|
} |
|
|
|
|
|
|
|
// prompt to register a new contact |
|
|
|
async promptRegister(contact: Contact) { |
|
|
|
this.$notify( |
|
|
|
{ |
|
|
|
group: "modal", |
|
|
|
type: "confirm", |
|
|
|
title: "Register", |
|
|
|
text: |
|
|
|
"Are you sure you want to register " + |
|
|
|
this.nameForDid(this.contacts, contact.did) + |
|
|
|
(contact.registered |
|
|
|
? " -- especially since they are already marked as registered" |
|
|
|
: "") + |
|
|
|
"?", |
|
|
|
) |
|
|
|
) { |
|
|
|
this.$notify( |
|
|
|
{ |
|
|
|
group: "alert", |
|
|
|
type: "toast", |
|
|
|
text: "", |
|
|
|
title: "Registration submitted...", |
|
|
|
onYes: async () => { |
|
|
|
await this.register(contact); |
|
|
|
}, |
|
|
|
1000, |
|
|
|
); |
|
|
|
}, |
|
|
|
-1, |
|
|
|
); |
|
|
|
} |
|
|
|
|
|
|
|
const identity = await this.getIdentity(this.activeDid); |
|
|
|
async register(contact: Contact) { |
|
|
|
this.$notify( |
|
|
|
{ |
|
|
|
group: "alert", |
|
|
|
type: "toast", |
|
|
|
text: "", |
|
|
|
title: "Registration submitted...", |
|
|
|
}, |
|
|
|
1000, |
|
|
|
); |
|
|
|
|
|
|
|
const vcClaim: RegisterVerifiableCredential = { |
|
|
|
"@context": "https://schema.org", |
|
|
|
"@type": "RegisterAction", |
|
|
|
agent: { identifier: identity.did }, |
|
|
|
object: SERVICE_ID, |
|
|
|
participant: { identifier: contact.did }, |
|
|
|
}; |
|
|
|
// Make a payload for the claim |
|
|
|
const vcPayload = { |
|
|
|
vc: { |
|
|
|
"@context": ["https://www.w3.org/2018/credentials/v1"], |
|
|
|
type: ["VerifiableCredential"], |
|
|
|
credentialSubject: vcClaim, |
|
|
|
}, |
|
|
|
}; |
|
|
|
// Create a signature using private key of identity |
|
|
|
if (identity.keys[0].privateKeyHex !== null) { |
|
|
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion |
|
|
|
const privateKeyHex: string = identity.keys[0].privateKeyHex!; |
|
|
|
const signer = await SimpleSigner(privateKeyHex); |
|
|
|
const alg = undefined; |
|
|
|
// Create a JWT for the request |
|
|
|
const vcJwt: string = await didJwt.createJWT(vcPayload, { |
|
|
|
alg: alg, |
|
|
|
issuer: identity.did, |
|
|
|
signer: signer, |
|
|
|
}); |
|
|
|
|
|
|
|
// Make the xhr request payload |
|
|
|
const payload = JSON.stringify({ jwtEncoded: vcJwt }); |
|
|
|
const url = this.apiServer + "/api/v2/claim"; |
|
|
|
const headers = await this.getHeaders(identity); |
|
|
|
|
|
|
|
try { |
|
|
|
const resp = await this.axios.post(url, payload, { headers }); |
|
|
|
if (resp.data?.success?.embeddedRecordError) { |
|
|
|
let message = "There was some problem with the registration."; |
|
|
|
if (typeof resp.data.success.embeddedRecordError == "string") { |
|
|
|
message += " " + resp.data.success.embeddedRecordError; |
|
|
|
} |
|
|
|
this.$notify( |
|
|
|
{ |
|
|
|
group: "alert", |
|
|
|
type: "danger", |
|
|
|
title: "Registration Still Unknown", |
|
|
|
text: message, |
|
|
|
}, |
|
|
|
5000, |
|
|
|
); |
|
|
|
} else if (resp.data?.success?.handleId) { |
|
|
|
contact.registered = true; |
|
|
|
db.contacts.update(contact.did, { registered: true }); |
|
|
|
|
|
|
|
this.$notify( |
|
|
|
{ |
|
|
|
group: "alert", |
|
|
|
type: "success", |
|
|
|
title: "Registration Success", |
|
|
|
text: |
|
|
|
(contact.name || "That unnamed person") + |
|
|
|
" has been registered.", |
|
|
|
}, |
|
|
|
5000, |
|
|
|
); |
|
|
|
} |
|
|
|
} catch (error) { |
|
|
|
console.error("Error when registering:", error); |
|
|
|
let userMessage = "There was an error. See logs for more info."; |
|
|
|
const serverError = error as AxiosError; |
|
|
|
if (serverError) { |
|
|
|
if (serverError.response?.data?.error?.message) { |
|
|
|
userMessage = serverError.response.data.error.message; |
|
|
|
} else if (serverError.message) { |
|
|
|
userMessage = serverError.message; // Info for the user |
|
|
|
} else { |
|
|
|
userMessage = JSON.stringify(serverError.toJSON()); |
|
|
|
} |
|
|
|
} else { |
|
|
|
userMessage = error as string; |
|
|
|
const identity = await this.getIdentity(this.activeDid); |
|
|
|
|
|
|
|
const vcClaim: RegisterVerifiableCredential = { |
|
|
|
"@context": "https://schema.org", |
|
|
|
"@type": "RegisterAction", |
|
|
|
agent: { identifier: identity.did }, |
|
|
|
object: SERVICE_ID, |
|
|
|
participant: { identifier: contact.did }, |
|
|
|
}; |
|
|
|
// Make a payload for the claim |
|
|
|
const vcPayload = { |
|
|
|
vc: { |
|
|
|
"@context": ["https://www.w3.org/2018/credentials/v1"], |
|
|
|
type: ["VerifiableCredential"], |
|
|
|
credentialSubject: vcClaim, |
|
|
|
}, |
|
|
|
}; |
|
|
|
// Create a signature using private key of identity |
|
|
|
if (identity.keys[0].privateKeyHex !== null) { |
|
|
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion |
|
|
|
const privateKeyHex: string = identity.keys[0].privateKeyHex!; |
|
|
|
const signer = await SimpleSigner(privateKeyHex); |
|
|
|
const alg = undefined; |
|
|
|
// Create a JWT for the request |
|
|
|
const vcJwt: string = await didJwt.createJWT(vcPayload, { |
|
|
|
alg: alg, |
|
|
|
issuer: identity.did, |
|
|
|
signer: signer, |
|
|
|
}); |
|
|
|
|
|
|
|
// Make the xhr request payload |
|
|
|
const payload = JSON.stringify({ jwtEncoded: vcJwt }); |
|
|
|
const url = this.apiServer + "/api/v2/claim"; |
|
|
|
const headers = await this.getHeaders(identity); |
|
|
|
|
|
|
|
try { |
|
|
|
const resp = await this.axios.post(url, payload, { headers }); |
|
|
|
if (resp.data?.success?.embeddedRecordError) { |
|
|
|
let message = "There was some problem with the registration."; |
|
|
|
if (typeof resp.data.success.embeddedRecordError == "string") { |
|
|
|
message += " " + resp.data.success.embeddedRecordError; |
|
|
|
} |
|
|
|
// Now set that error for the user to see. |
|
|
|
this.$notify( |
|
|
|
{ |
|
|
|
group: "alert", |
|
|
|
type: "danger", |
|
|
|
title: "Registration Error", |
|
|
|
text: userMessage, |
|
|
|
title: "Registration Still Unknown", |
|
|
|
text: message, |
|
|
|
}, |
|
|
|
5000, |
|
|
|
); |
|
|
|
} else if (resp.data?.success?.handleId) { |
|
|
|
contact.registered = true; |
|
|
|
db.contacts.update(contact.did, { registered: true }); |
|
|
|
|
|
|
|
this.$notify( |
|
|
|
{ |
|
|
|
group: "alert", |
|
|
|
type: "success", |
|
|
|
title: "Registration Success", |
|
|
|
text: |
|
|
|
(contact.name || "That unnamed person") + |
|
|
|
" has been registered.", |
|
|
|
}, |
|
|
|
5000, |
|
|
|
); |
|
|
|
} |
|
|
|
} catch (error) { |
|
|
|
console.error("Error when registering:", error); |
|
|
|
let userMessage = "There was an error. See logs for more info."; |
|
|
|
const serverError = error as AxiosError; |
|
|
|
if (serverError) { |
|
|
|
if (serverError.response?.data?.error?.message) { |
|
|
|
userMessage = serverError.response.data.error.message; |
|
|
|
} else if (serverError.message) { |
|
|
|
userMessage = serverError.message; // Info for the user |
|
|
|
} else { |
|
|
|
userMessage = JSON.stringify(serverError.toJSON()); |
|
|
|
} |
|
|
|
} else { |
|
|
|
userMessage = error as string; |
|
|
|
} |
|
|
|
// Now set that error for the user to see. |
|
|
|
this.$notify( |
|
|
|
{ |
|
|
|
group: "alert", |
|
|
|
type: "danger", |
|
|
|
title: "Registration Error", |
|
|
|
text: userMessage, |
|
|
|
}, |
|
|
|
5000, |
|
|
|
); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
async promptSetVisibility(contact: Contact, visibility: boolean) { |
|
|
|
const visibilityPrompt = visibility |
|
|
|
? "Are you sure you want to make your activity visible to them?" |
|
|
|
: "Are you sure you want to hide all your activity from them?"; |
|
|
|
this.$notify( |
|
|
|
{ |
|
|
|
group: "modal", |
|
|
|
type: "confirm", |
|
|
|
title: "Set Visibility", |
|
|
|
text: visibilityPrompt, |
|
|
|
onYes: async () => { |
|
|
|
await this.setVisibility(contact, visibility, true); |
|
|
|
}, |
|
|
|
}, |
|
|
|
-1, |
|
|
|
); |
|
|
|
} |
|
|
|
|
|
|
|
async setVisibility( |
|
|
|
contact: Contact, |
|
|
|
visibility: boolean, |
|
|
|
showSuccessAlert: boolean, |
|
|
|
) { |
|
|
|
const visibilityPrompt = |
|
|
|
showSuccessAlert && |
|
|
|
(visibility |
|
|
|
? "Are you sure you want to make your activity visible to them?" |
|
|
|
: "Are you sure you want to hide all your activity from them?"); |
|
|
|
if (!visibilityPrompt || confirm(visibilityPrompt)) { |
|
|
|
const url = |
|
|
|
this.apiServer + |
|
|
|
"/api/report/" + |
|
|
|
(visibility ? "canSeeMe" : "cannotSeeMe"); |
|
|
|
const identity = await this.getIdentity(this.activeDid); |
|
|
|
const headers = await this.getHeaders(identity); |
|
|
|
const payload = JSON.stringify({ did: contact.did }); |
|
|
|
const url = |
|
|
|
this.apiServer + |
|
|
|
"/api/report/" + |
|
|
|
(visibility ? "canSeeMe" : "cannotSeeMe"); |
|
|
|
const identity = await this.getIdentity(this.activeDid); |
|
|
|
const headers = await this.getHeaders(identity); |
|
|
|
const payload = JSON.stringify({ did: contact.did }); |
|
|
|
|
|
|
|
try { |
|
|
|
const resp = await this.axios.post(url, payload, { headers }); |
|
|
|
if (resp.status === 200) { |
|
|
|
if (showSuccessAlert) { |
|
|
|
this.$notify( |
|
|
|
{ |
|
|
|
group: "alert", |
|
|
|
type: "success", |
|
|
|
title: "Visibility Set", |
|
|
|
text: |
|
|
|
this.nameForDid(this.contacts, contact.did) + |
|
|
|
" can " + |
|
|
|
(visibility ? "" : "not ") + |
|
|
|
"see your activity.", |
|
|
|
}, |
|
|
|
3000, |
|
|
|
); |
|
|
|
} |
|
|
|
contact.seesMe = visibility; |
|
|
|
db.contacts.update(contact.did, { seesMe: visibility }); |
|
|
|
} else { |
|
|
|
console.error( |
|
|
|
"Got some bad server response when setting visibility: ", |
|
|
|
resp.status, |
|
|
|
resp, |
|
|
|
); |
|
|
|
const message = |
|
|
|
resp.data.error?.message || "Got some error setting visibility."; |
|
|
|
try { |
|
|
|
const resp = await this.axios.post(url, payload, { headers }); |
|
|
|
if (resp.status === 200) { |
|
|
|
if (showSuccessAlert) { |
|
|
|
this.$notify( |
|
|
|
{ |
|
|
|
group: "alert", |
|
|
|
type: "danger", |
|
|
|
title: "Error Setting Visibility", |
|
|
|
text: message, |
|
|
|
type: "success", |
|
|
|
title: "Visibility Set", |
|
|
|
text: |
|
|
|
this.nameForDid(this.contacts, contact.did) + |
|
|
|
" can " + |
|
|
|
(visibility ? "" : "not ") + |
|
|
|
"see your activity.", |
|
|
|
}, |
|
|
|
5000, |
|
|
|
3000, |
|
|
|
); |
|
|
|
} |
|
|
|
} catch (err) { |
|
|
|
console.error("Got some error when setting visibility:", err); |
|
|
|
contact.seesMe = visibility; |
|
|
|
db.contacts.update(contact.did, { seesMe: visibility }); |
|
|
|
} else { |
|
|
|
console.error( |
|
|
|
"Got some bad server response when setting visibility: ", |
|
|
|
resp.status, |
|
|
|
resp, |
|
|
|
); |
|
|
|
const message = |
|
|
|
resp.data.error?.message || "Got some error setting visibility."; |
|
|
|
this.$notify( |
|
|
|
{ |
|
|
|
group: "alert", |
|
|
|
type: "danger", |
|
|
|
title: "Error Setting Visibility", |
|
|
|
text: "Check connectivity and try again.", |
|
|
|
text: message, |
|
|
|
}, |
|
|
|
5000, |
|
|
|
); |
|
|
|
} |
|
|
|
} catch (err) { |
|
|
|
console.error("Got some error when setting visibility:", err); |
|
|
|
this.$notify( |
|
|
|
{ |
|
|
|
group: "alert", |
|
|
|
type: "danger", |
|
|
|
title: "Error Setting Visibility", |
|
|
|
text: "Check connectivity and try again.", |
|
|
|
}, |
|
|
|
5000, |
|
|
|
); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
@ -1058,34 +1089,47 @@ export default class ContactsView extends Vue { |
|
|
|
); |
|
|
|
} |
|
|
|
|
|
|
|
private showGiftedDialog(giverDid: string, recipientDid: string) { |
|
|
|
// if they have unconfirmed amounts, ask to confirm those first |
|
|
|
promptShowGiftedDialog(giverDid: string, recipientDid: string) { |
|
|
|
// if they have unconfirmed amounts, ask to confirm those |
|
|
|
if ( |
|
|
|
recipientDid == this.activeDid && |
|
|
|
recipientDid === this.activeDid && |
|
|
|
this.givenToMeUnconfirmed[giverDid] > 0 |
|
|
|
) { |
|
|
|
const isAre = this.givenToMeUnconfirmed[giverDid] == 1 ? "is" : "are"; |
|
|
|
const hours = this.givenToMeUnconfirmed[giverDid] == 1 ? "hour" : "hours"; |
|
|
|
if ( |
|
|
|
confirm( |
|
|
|
"There " + |
|
|
|
isAre + |
|
|
|
" " + |
|
|
|
this.givenToMeUnconfirmed[giverDid] + |
|
|
|
" unconfirmed " + |
|
|
|
hours + |
|
|
|
" from them." + |
|
|
|
" Would you like to confirm some of those hours?", |
|
|
|
) |
|
|
|
) { |
|
|
|
this.$router.push({ |
|
|
|
name: "contact-amounts", |
|
|
|
query: { contactDid: giverDid }, |
|
|
|
}); |
|
|
|
return; |
|
|
|
} |
|
|
|
const message = |
|
|
|
"There " + |
|
|
|
isAre + |
|
|
|
" " + |
|
|
|
this.givenToMeUnconfirmed[giverDid] + |
|
|
|
" unconfirmed " + |
|
|
|
hours + |
|
|
|
" from them." + |
|
|
|
" Would you like to confirm some of those hours?"; |
|
|
|
this.$notify( |
|
|
|
{ |
|
|
|
group: "modal", |
|
|
|
type: "confirm", |
|
|
|
title: "Delete", |
|
|
|
text: message, |
|
|
|
onNo: async () => { |
|
|
|
this.showGiftedDialog(giverDid, recipientDid); |
|
|
|
}, |
|
|
|
onYes: async () => { |
|
|
|
this.$router.push({ |
|
|
|
name: "contact-amounts", |
|
|
|
query: { contactDid: giverDid }, |
|
|
|
}); |
|
|
|
}, |
|
|
|
}, |
|
|
|
-1, |
|
|
|
); |
|
|
|
} else { |
|
|
|
this.showGiftedDialog(giverDid, recipientDid); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private showGiftedDialog(giverDid: string, recipientDid: string) { |
|
|
|
let giver: GiverReceiverInputInfo, receiver: GiverReceiverInputInfo; |
|
|
|
if (giverDid) { |
|
|
|
giver = { |
|
|
|