Browse Source

add registration inside contact import, with flag to hide it

Trent Larson 7 months ago
parent
commit
c403356055
  1. 46
      src/App.vue
  2. 4
      src/constants/app.ts
  3. 3
      src/db/tables/settings.ts
  4. 60
      src/libs/endorserServer.ts
  5. 57
      src/views/AccountViewView.vue
  6. 117
      src/views/ContactQRScanShowView.vue
  7. 219
      src/views/ContactsView.vue
  8. 2
      src/views/DIDView.vue

46
src/App.vue

@ -146,13 +146,19 @@
move="transition duration-500" move="transition duration-500"
move-delay="delay-300" move-delay="delay-300"
> >
<!-- see NotificationIface in constants/app.ts -->
<div <div
v-for="notification in notifications" v-for="notification in notifications"
:key="notification.id" :key="notification.id"
class="w-full" class="w-full"
role="alert" role="alert"
> >
<!-- type "confirm" will post a message and, with onYes function, show a "Yes" button to call that function --> <!--
Type of "confirm" will post a message.
With onYes function, show a "Yes" button to call that function.
With onNo function, show a "No" button to call that function,
and pass it state of "askAgain" field shown if you set promptToStopAsking.
-->
<div <div
v-if="notification.type === 'confirm'" v-if="notification.type === 'confirm'"
class="absolute inset-0 h-screen flex flex-col items-center justify-center bg-slate-900/50" class="absolute inset-0 h-screen flex flex-col items-center justify-center bg-slate-900/50"
@ -180,16 +186,49 @@
<button <button
v-if="notification.onNo" v-if="notification.onNo"
@click=" @click="
notification.onNo(); notification.onNo(stopAsking);
close(notification.id); close(notification.id);
stopAsking = false; // reset value
" "
class="block w-full text-center text-md font-bold uppercase bg-yellow-600 text-white px-2 py-2 rounded-md mb-2" class="block w-full text-center text-md font-bold uppercase bg-yellow-600 text-white px-2 py-2 rounded-md mb-2"
> >
No No
</button> </button>
<label
v-if="notification.promptToStopAsking && notification.onNo"
for="toggleStopAsking"
class="flex items-center justify-between cursor-pointer my-4"
@click="stopAsking = !stopAsking"
>
<!-- label -->
<span class="ml-2">... and do not ask again.</span>
<!-- toggle -->
<div class="relative ml-2">
<!-- input -->
<input
type="checkbox"
v-model="stopAsking"
name="stopAsking"
class="sr-only"
/>
<!-- line -->
<div class="block bg-slate-500 w-14 h-8 rounded-full"></div>
<!-- dot -->
<div
class="dot absolute left-1 top-1 bg-slate-400 w-6 h-6 rounded-full transition"
></div>
</div>
</label>
<button <button
@click="close(notification.id)" @click="
notification.onCancel
? notification.onCancel(stopAsking)
: null;
close(notification.id);
stopAsking = false; // reset value
"
class="block w-full text-center text-md font-bold uppercase bg-slate-600 text-white px-2 py-2 rounded-md" class="block w-full text-center text-md font-bold uppercase bg-slate-600 text-white px-2 py-2 rounded-md"
> >
{{ notification.onYes ? "Cancel" : "Close" }} {{ notification.onYes ? "Cancel" : "Close" }}
@ -373,6 +412,7 @@ import { sendTestThroughPushServer } from "@/libs/util";
export default class App extends Vue { export default class App extends Vue {
$notify!: (notification: NotificationIface, timeout?: number) => void; $notify!: (notification: NotificationIface, timeout?: number) => void;
stopAsking = false;
b64 = ""; b64 = "";
hourAm = true; hourAm = true;
hourInput = "8"; hourInput = "8";

4
src/constants/app.ts

@ -39,6 +39,8 @@ export interface NotificationIface {
type: string; // "toast" | "info" | "success" | "warning" | "danger" type: string; // "toast" | "info" | "success" | "warning" | "danger"
title: string; title: string;
text: string; text: string;
onNo?: () => Promise<void>; onCancel?: (stopAsking: boolean) => Promise<void>;
onNo?: (stopAsking: boolean) => Promise<void>;
onYes?: () => Promise<void>; onYes?: () => Promise<void>;
promptToStopAsking?: boolean;
} }

3
src/db/tables/settings.ts

@ -21,6 +21,7 @@ export type Settings = {
filterFeedByVisible?: boolean; // filter by visible users ie. anyone not hidden filterFeedByVisible?: boolean; // filter by visible users ie. anyone not hidden
firstName?: string; // user's full name firstName?: string; // user's full name
hideRegisterPromptOnNewContact?: boolean;
isRegistered?: boolean; isRegistered?: boolean;
lastName?: string; // deprecated - put all names in firstName lastName?: string; // deprecated - put all names in firstName
lastNotifiedClaimId?: string; lastNotifiedClaimId?: string;
@ -36,7 +37,7 @@ export type Settings = {
}>; }>;
showContactGivesInline?: boolean; // Display contact inline or not showContactGivesInline?: boolean; // Display contact inline or not
showShortcutBvc?: boolean; // Show shortcut for BVC actions showShortcutBvc?: boolean; // Show shortcut for Bountiful Voluntaryist Community actions
vapid?: string; // VAPID (Voluntary Application Server Identification) field for web push vapid?: string; // VAPID (Voluntary Application Server Identification) field for web push
warnIfProdServer?: boolean; // Warn if using a production server warnIfProdServer?: boolean; // Warn if using a production server
warnIfTestServer?: boolean; // Warn if using a testing server warnIfTestServer?: boolean; // Warn if using a testing server

60
src/libs/endorserServer.ts

@ -911,6 +911,65 @@ export const bvcMeetingJoinClaim = (did: string, startTime: string) => {
}; };
}; };
export async function register(
activeDid: string,
apiServer: string,
axios: Axios,
contact: Contact,
) {
const identity = await getIdentity(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) {
return { error: "Private key not found." };
}
// 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 = apiServer + "/api/v2/claim";
const headers = await getHeaders(identity);
const resp = await axios.post(url, payload, { headers });
if (resp.data?.success?.handleId) {
return { success: true };
} else if (resp.data?.success?.embeddedRecordError) {
let message =
"There was some problem with the registration and so it may not be complete.";
if (typeof resp.data.success.embeddedRecordError == "string") {
message += " " + resp.data.success.embeddedRecordError;
}
return { error: message };
} else {
console.error(resp);
return { error: "Got a server error when registering." };
}
}
export async function setVisibilityUtil( export async function setVisibilityUtil(
activeDid: string, activeDid: string,
apiServer: string, apiServer: string,
@ -931,7 +990,6 @@ export async function setVisibilityUtil(
try { try {
const resp = await axios.post(url, payload, { headers }); const resp = await axios.post(url, payload, { headers });
if (resp.status === 200) { if (resp.status === 200) {
contact.seesMe = visibility;
db.contacts.update(contact.did, { seesMe: visibility }); db.contacts.update(contact.did, { seesMe: visibility });
return { success: true }; return { success: true };
} else { } else {

57
src/views/AccountViewView.vue

@ -532,25 +532,47 @@
<span class="text-sm">{{ DEFAULT_IMAGE_API_SERVER }}</span> <span class="text-sm">{{ DEFAULT_IMAGE_API_SERVER }}</span>
</div> </div>
<label
for="toggleHideRegisterPromptOnNewContact"
class="flex items-center justify-between cursor-pointer mt-4"
@click="toggleHideRegisterPromptOnNewContact()"
>
<!-- label -->
<span class="text-slate-500 text-sm font-bold">
Hide Register Prompt on New Contact
</span>
<!-- toggle -->
<div class="relative ml-2">
<!-- input -->
<input type="checkbox" v-model="hideRegisterPromptOnNewContact" class="sr-only" />
<!-- line -->
<div class="block bg-slate-500 w-14 h-8 rounded-full" />
<!-- dot -->
<div
class="dot absolute left-1 top-1 bg-slate-400 w-6 h-6 rounded-full transition"
/>
</div>
</label>
<label <label
for="toggleShowShortcutBvc" for="toggleShowShortcutBvc"
class="flex items-center justify-between cursor-pointer mt-4" class="flex items-center justify-between cursor-pointer mt-4"
@click="toggleShowShortcutBvc" @click="toggleShowShortcutBvc"
> >
<!-- label --> <!-- label -->
<span class="text-slate-500 text-sm font-bold" <span class="text-slate-500 text-sm font-bold">
>Show BVC Shortcut on Home Page</span Show BVC Shortcut on Home Page
> </span>
<!-- toggle --> <!-- toggle -->
<div class="relative ml-2"> <div class="relative ml-2">
<!-- input --> <!-- input -->
<input type="checkbox" v-model="showShortcutBvc" class="sr-only" /> <input type="checkbox" v-model="showShortcutBvc" class="sr-only" />
<!-- line --> <!-- line -->
<div class="block bg-slate-500 w-14 h-8 rounded-full"></div> <div class="block bg-slate-500 w-14 h-8 rounded-full" />
<!-- dot --> <!-- dot -->
<div <div
class="dot absolute left-1 top-1 bg-slate-400 w-6 h-6 rounded-full transition" class="dot absolute left-1 top-1 bg-slate-400 w-6 h-6 rounded-full transition"
></div> />
</div> </div>
</label> </label>
@ -665,6 +687,7 @@ export default class AccountViewView extends Vue {
showB64Copy = false; showB64Copy = false;
showPubCopy = false; showPubCopy = false;
showAdvanced = false; showAdvanced = false;
hideRegisterPromptOnNewContact = false;
showShortcutBvc = false; showShortcutBvc = false;
subscription: PushSubscription | null = null; subscription: PushSubscription | null = null;
warnIfProdServer = false; warnIfProdServer = false;
@ -726,6 +749,8 @@ export default class AccountViewView extends Vue {
this.isRegistered = !!settings?.isRegistered; this.isRegistered = !!settings?.isRegistered;
this.profileImageUrl = settings?.profileImageUrl as string; this.profileImageUrl = settings?.profileImageUrl as string;
this.showContactGives = !!settings?.showContactGivesInline; this.showContactGives = !!settings?.showContactGivesInline;
this.hideRegisterPromptOnNewContact =
!!settings?.hideRegisterPromptOnNewContact;
this.showShortcutBvc = !!settings?.showShortcutBvc; this.showShortcutBvc = !!settings?.showShortcutBvc;
this.warnIfProdServer = !!settings?.warnIfProdServer; this.warnIfProdServer = !!settings?.warnIfProdServer;
this.warnIfTestServer = !!settings?.warnIfTestServer; this.warnIfTestServer = !!settings?.warnIfTestServer;
@ -951,6 +976,28 @@ export default class AccountViewView extends Vue {
} }
} }
public async toggleHideRegisterPromptOnNewContact() {
const newSetting = !this.hideRegisterPromptOnNewContact;
try {
await db.open();
db.settings.update(MASTER_SETTINGS_KEY, {
hideRegisterPromptOnNewContact: newSetting,
});
this.hideRegisterPromptOnNewContact = newSetting;
} catch (err) {
this.$notify(
{
group: "alert",
type: "danger",
title: "Error Updating Setting",
text: "The setting may not have saved. Try again, maybe after restarting the app.",
},
-1,
);
console.error("Telling user to try again because:", err);
}
}
public async updateShowShortcutBvc(newSetting: boolean) { public async updateShowShortcutBvc(newSetting: boolean) {
try { try {
await db.open(); await db.open();

117
src/views/ContactQRScanShowView.vue

@ -71,6 +71,7 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import { AxiosError } from "axios";
import * as didJwt from "did-jwt"; import * as didJwt from "did-jwt";
import { sha256 } from "ethereum-cryptography/sha256.js"; import { sha256 } from "ethereum-cryptography/sha256.js";
import QRCodeVue3 from "qr-code-generator-vue3"; import QRCodeVue3 from "qr-code-generator-vue3";
@ -95,6 +96,7 @@ import {
CONTACT_URL_PREFIX, CONTACT_URL_PREFIX,
ENDORSER_JWT_URL_LOCATION, ENDORSER_JWT_URL_LOCATION,
isDid, isDid,
register,
setVisibilityUtil, setVisibilityUtil,
} from "@/libs/endorserServer"; } from "@/libs/endorserServer";
@ -113,6 +115,8 @@ export default class ContactQRScanShow extends Vue {
activeDid = ""; activeDid = "";
apiServer = ""; apiServer = "";
givenName = ""; givenName = "";
hideRegisterPromptOnNewContact = false;
isRegistered = false;
qrValue = ""; qrValue = "";
async created() { async created() {
@ -121,6 +125,9 @@ export default class ContactQRScanShow extends Vue {
this.activeDid = (settings?.activeDid as string) || ""; this.activeDid = (settings?.activeDid as string) || "";
this.apiServer = (settings?.apiServer as string) || ""; this.apiServer = (settings?.apiServer as string) || "";
this.givenName = (settings?.firstName as string) || ""; this.givenName = (settings?.firstName as string) || "";
this.hideRegisterPromptOnNewContact =
!!settings?.hideRegisterPromptOnNewContact;
this.isRegistered = !!settings?.isRegistered;
await accountsDB.open(); await accountsDB.open();
const accounts = await accountsDB.accounts.toArray(); const accounts = await accountsDB.accounts.toArray();
@ -247,6 +254,7 @@ export default class ContactQRScanShow extends Vue {
let addedMessage; let addedMessage;
if (this.activeDid) { if (this.activeDid) {
await this.setVisibility(newContact, true); await this.setVisibility(newContact, true);
newContact.seesMe = true; // didn't work inside setVisibility
addedMessage = addedMessage =
"They were added, and your activity is visible to them."; "They were added, and your activity is visible to them.";
} else { } else {
@ -261,6 +269,42 @@ export default class ContactQRScanShow extends Vue {
}, },
3000, 3000,
); );
if (this.isRegistered) {
if (!this.hideRegisterPromptOnNewContact && !newContact.registered) {
setTimeout(() => {
this.$notify(
{
group: "modal",
type: "confirm",
title: "Register",
text: "Do you want to register them?",
onCancel: async (stopAsking: boolean) => {
if (stopAsking) {
db.settings.update(MASTER_SETTINGS_KEY, {
hideRegisterPromptOnNewContact: stopAsking,
});
this.hideRegisterPromptOnNewContact = stopAsking;
}
},
onNo: async (stopAsking: boolean) => {
if (stopAsking) {
db.settings.update(MASTER_SETTINGS_KEY, {
hideRegisterPromptOnNewContact: stopAsking,
});
this.hideRegisterPromptOnNewContact = stopAsking;
}
},
onYes: async () => {
await this.register(newContact);
},
promptToStopAsking: true,
},
-1,
);
}, 500);
}
}
} catch (e) { } catch (e) {
console.error("Error saving contact info:", e); console.error("Error saving contact info:", e);
this.$notify( this.$notify(
@ -302,6 +346,79 @@ export default class ContactQRScanShow extends Vue {
} }
} }
async register(contact: Contact) {
this.$notify(
{
group: "alert",
type: "toast",
text: "",
title: "Registration submitted...",
},
1000,
);
try {
const regResult = await register(
this.activeDid,
this.apiServer,
this.axios,
contact,
);
if (regResult.success) {
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,
);
} else {
this.$notify(
{
group: "alert",
type: "danger",
title: "Registration Error",
text:
(regResult.error as string) ||
"Something went wrong during registration.",
},
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,
);
}
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
onScanError(error: any) { onScanError(error: any) {
console.error("Scan was invalid:", error); console.error("Scan was invalid:", error);

219
src/views/ContactsView.vue

@ -73,7 +73,7 @@
? "Confirmed Amounts" ? "Confirmed Amounts"
: "Unconfirmed Amounts" : "Unconfirmed Amounts"
}} }}
<fa icon="rotate" class="fa-fw" /> <fa icon="left-right" class="fa-fw" />
</button> </button>
</div> </div>
</div> </div>
@ -301,30 +301,25 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import { AxiosError } from "axios"; import {Axios, AxiosError} from "axios";
import { IndexableType } from "dexie"; import { IndexableType } from "dexie";
import * as didJwt from "did-jwt";
import * as R from "ramda"; import * as R from "ramda";
import { IIdentifier } from "@veramo/core"; import { IIdentifier } from "@veramo/core";
import { Component, Vue } from "vue-facing-decorator"; import { Component, Vue } from "vue-facing-decorator";
import { Router } from "vue-router";
import { AppString, NotificationIface } from "@/constants/app"; import { AppString, NotificationIface } from "@/constants/app";
import { accountsDB, db } from "@/db/index"; import {accountsDB, db, NonsensitiveDexie} from "@/db/index";
import { Contact } from "@/db/tables/contacts"; import { Contact } from "@/db/tables/contacts";
import { MASTER_SETTINGS_KEY, Settings } from "@/db/tables/settings"; import { MASTER_SETTINGS_KEY, Settings } from "@/db/tables/settings";
import { import { accessToken, getContactPayloadFromJwtUrl } from "@/libs/crypto";
accessToken,
getContactPayloadFromJwtUrl,
SimpleSigner,
} from "@/libs/crypto";
import { import {
CONTACT_CSV_HEADER, CONTACT_CSV_HEADER,
CONTACT_URL_PREFIX, CONTACT_URL_PREFIX,
GiverReceiverInputInfo, GiverReceiverInputInfo,
GiveSummaryRecord, GiveSummaryRecord,
isDid, isDid,
RegisterVerifiableCredential, register,
SERVICE_ID,
setVisibilityUtil, setVisibilityUtil,
} from "@/libs/endorserServer"; } from "@/libs/endorserServer";
import * as libsUtil from "@/libs/util"; import * as libsUtil from "@/libs/util";
@ -335,6 +330,7 @@ import OfferDialog from "@/components/OfferDialog.vue";
import { Account } from "@/db/tables/accounts"; import { Account } from "@/db/tables/accounts";
import { Buffer } from "buffer/"; import { Buffer } from "buffer/";
import {getIdentity} from "@/libs/util";
@Component({ @Component({
components: { GiftedDialog, EntityIcon, OfferDialog, QuickNav }, components: { GiftedDialog, EntityIcon, OfferDialog, QuickNav },
@ -360,6 +356,7 @@ export default class ContactsView extends Vue {
givenToMeConfirmed: Record<string, number> = {}; givenToMeConfirmed: Record<string, number> = {};
// { "did:...": amount } entry for each contact // { "did:...": amount } entry for each contact
givenToMeUnconfirmed: Record<string, number> = {}; givenToMeUnconfirmed: Record<string, number> = {};
hideRegisterPromptOnNewContact = false;
isRegistered = false; isRegistered = false;
showDidCopy = false; showDidCopy = false;
showGiveNumbers = false; showGiveNumbers = false;
@ -378,6 +375,9 @@ export default class ContactsView extends Vue {
this.isRegistered = !!settings?.isRegistered; this.isRegistered = !!settings?.isRegistered;
this.showGiveNumbers = !!settings?.showContactGivesInline; this.showGiveNumbers = !!settings?.showContactGivesInline;
this.hideRegisterPromptOnNewContact =
!!settings?.hideRegisterPromptOnNewContact;
if (this.showGiveNumbers) { if (this.showGiveNumbers) {
this.loadGives(); this.loadGives();
} }
@ -681,6 +681,7 @@ export default class ContactsView extends Vue {
nextPubKeyHashB64: payload.own.nextPublicEncKeyHash, nextPubKeyHashB64: payload.own.nextPublicEncKeyHash,
profileImageUrl: payload.own.profileImageUrl, profileImageUrl: payload.own.profileImageUrl,
publicKeyBase64: payload.own.publicEncKey, publicKeyBase64: payload.own.publicEncKey,
isRegistered: payload.own.isRegistered,
} as Contact); } as Contact);
} }
} }
@ -705,6 +706,7 @@ export default class ContactsView extends Vue {
let addedMessage; let addedMessage;
if (this.activeDid) { if (this.activeDid) {
this.setVisibility(newContact, true, false); this.setVisibility(newContact, true, false);
newContact.seesMe = true; // didn't work inside setVisibility
addedMessage = addedMessage =
"They were added, and your activity is visible to them."; "They were added, and your activity is visible to them.";
} else { } else {
@ -712,15 +714,39 @@ export default class ContactsView extends Vue {
} }
this.contactInput = ""; this.contactInput = "";
if (this.isRegistered) { if (this.isRegistered) {
this.$notify( if (!this.hideRegisterPromptOnNewContact && !newContact.registered) {
{ setTimeout(() => {
group: "alert", this.$notify(
type: "info", {
title: "New User?", group: "modal",
text: "If they are a new user, be sure to register to onboard them.", type: "confirm",
}, title: "Register",
-1, text: "Do you want to register them?",
); onCancel: async (stopAsking: boolean) => {
if (stopAsking) {
db.settings.update(MASTER_SETTINGS_KEY, {
hideRegisterPromptOnNewContact: stopAsking,
});
this.hideRegisterPromptOnNewContact = stopAsking;
}
},
onNo: async (stopAsking: boolean) => {
if (stopAsking) {
db.settings.update(MASTER_SETTINGS_KEY, {
hideRegisterPromptOnNewContact: stopAsking,
});
this.hideRegisterPromptOnNewContact = stopAsking;
}
},
onYes: async () => {
await this.register(newContact);
},
promptToStopAsking: true,
},
-1,
);
}, 500);
}
} }
this.$notify( this.$notify(
{ {
@ -809,99 +835,65 @@ export default class ContactsView extends Vue {
1000, 1000,
); );
const identity = await this.getIdentity(this.activeDid); try {
const regResult = await register(
const vcClaim: RegisterVerifiableCredential = { this.activeDid,
"@context": "https://schema.org", this.apiServer,
"@type": "RegisterAction", this.axios,
agent: { identifier: identity.did }, contact,
object: SERVICE_ID, );
participant: { identifier: contact.did }, if (regResult.success) {
}; contact.registered = true;
// Make a payload for the claim db.contacts.update(contact.did, { registered: true });
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 { this.$notify(
const resp = await this.axios.post(url, payload, { headers }); {
if (resp.data?.success?.embeddedRecordError) { group: "alert",
let message = "There was some problem with the registration."; type: "success",
if (typeof resp.data.success.embeddedRecordError == "string") { title: "Registration Success",
message += " " + resp.data.success.embeddedRecordError; text:
} (contact.name || "That unnamed person") + " has been registered.",
this.$notify( },
{ 5000,
group: "alert", );
type: "danger", } else {
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( this.$notify(
{ {
group: "alert", group: "alert",
type: "danger", type: "danger",
title: "Registration Error", title: "Registration Error",
text: userMessage, text:
(regResult.error as string) ||
"Something went wrong during registration.",
}, },
5000, 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,
);
} }
} }
@ -980,6 +972,13 @@ export default class ContactsView extends Vue {
if (resp.status === 200) { if (resp.status === 200) {
const visibility = resp.data; const visibility = resp.data;
contact.seesMe = visibility; contact.seesMe = visibility;
console.log(
"Visibility checked:",
visibility,
contact.did,
contact.name,
); // eslint-disable-line no-console
console.log(this.contacts); // eslint-disable-line no-console
db.contacts.update(contact.did, { seesMe: visibility }); db.contacts.update(contact.did, { seesMe: visibility });
this.$notify( this.$notify(
@ -1064,7 +1063,7 @@ export default class ContactsView extends Vue {
this.showGiftedDialog(giverDid, recipientDid); this.showGiftedDialog(giverDid, recipientDid);
}, },
onYes: async () => { onYes: async () => {
this.$router.push({ (this.$router as Router).push({
name: "contact-amounts", name: "contact-amounts",
query: { contactDid: giverDid }, query: { contactDid: giverDid },
}); });
@ -1159,6 +1158,18 @@ export default class ContactsView extends Vue {
); );
} }
this.showGiveNumbers = newShowValue; this.showGiveNumbers = newShowValue;
if (
newShowValue &&
Object.keys(this.givenByMeDescriptions).length === 0 &&
Object.keys(this.givenByMeConfirmed).length === 0 &&
Object.keys(this.givenByMeUnconfirmed).length === 0 &&
Object.keys(this.givenToMeDescriptions).length === 0 &&
Object.keys(this.givenToMeConfirmed).length === 0 &&
Object.keys(this.givenToMeUnconfirmed).length === 0
) {
// assume we should load it all
this.loadGives();
}
} }
public toggleShowGiveTotals() { public toggleShowGiveTotals() {
if (this.showGiveTotals) { if (this.showGiveTotals) {

2
src/views/DIDView.vue

@ -121,7 +121,7 @@
v-if="!isLoading && claims.length === 0" v-if="!isLoading && claims.length === 0"
class="flex justify-center mt-4" class="flex justify-center mt-4"
> >
<span>No Claims Visible to You Involve Them</span> <span>They Are in No Claims Visible to You</span>
</div> </div>
</section> </section>
</template> </template>

Loading…
Cancel
Save