Browse Source

add a contact-edit page and allow saving of notes

master
Trent Larson 2 weeks ago
parent
commit
086ccce0bb
  1. 1
      src/db/tables/contacts.ts
  2. 5
      src/router/index.ts
  3. 2
      src/views/ClaimView.vue
  4. 2
      src/views/ConfirmGiftView.vue
  5. 130
      src/views/ContactEditView.vue
  6. 41
      src/views/ContactsView.vue
  7. 63
      src/views/DIDView.vue

1
src/db/tables/contacts.ts

@ -2,6 +2,7 @@ export interface Contact {
did: string;
name?: string;
nextPubKeyHashB64?: string; // base64-encoded SHA256 hash of next public key
notes?: string;
profileImageUrl?: string;
publicKeyBase64?: string;
seesMe?: boolean; // cached value of the server setting

5
src/router/index.ts

@ -64,6 +64,11 @@ const routes: Array<RouteRecordRaw> = [
name: "contact-amounts",
component: () => import("../views/ContactAmountsView.vue"),
},
{
path: "/contact-edit/:did",
name: "contact-edit",
component: () => import("../views/ContactEditView.vue"),
},
{
path: "/contact-gift",
name: "contact-gift",

2
src/views/ClaimView.vue

@ -351,7 +351,7 @@
>
Details
<fa v-if="showVeriClaimDump" icon="chevron-up" />
<fa v-else icon="chevron-down" />
<fa v-else icon="chevron-right" />
</h2>
<div v-if="showVeriClaimDump">
<div

2
src/views/ConfirmGiftView.vue

@ -261,7 +261,7 @@
>
Details
<fa v-if="showVeriClaimDump" icon="chevron-up" />
<fa v-else icon="chevron-down" />
<fa v-else icon="chevron-right" />
</h2>
<div v-if="showVeriClaimDump">
<div

130
src/views/ContactEditView.vue

@ -0,0 +1,130 @@
<template>
<QuickNav selected="Contacts" />
<TopMessage />
<section id="ContactEdit" class="p-6 max-w-3xl mx-auto">
<div id="ViewBreadcrumb" class="mb-8">
<h1 class="text-4xl text-center font-light relative px-7">
<!-- Back -->
<button
@click="$router.go(-1)"
class="text-lg text-center px-2 py-1 absolute -left-2 -top-1"
>
<fa icon="chevron-left" class="fa-fw" />
</button>
{{ contact.name || AppString.NO_CONTACT_NAME }}
</h1>
</div>
<!-- Contact Name -->
<div class="mt-4 flex">
<label
for="contactName"
class="block text-sm font-medium text-gray-700 mt-2"
>
Name
</label>
<input
type="text"
class="block w-full ml-2 mt-1 border border-gray-300 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500"
v-model="contactName"
/>
</div>
<!-- Contact Notes -->
<div class="mt-4">
<label for="contactNotes" class="block text-sm font-medium text-gray-700">
Notes
</label>
<textarea
id="contactNotes"
rows="4"
class="block w-full mt-1 border border-gray-300 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500"
v-model="contactNotes"
></textarea>
</div>
<!-- Save Button -->
<div class="mt-4 flex justify-between">
<button
class="px-4 py-2 bg-blue-500 text-white rounded-md"
@click="saveEdit"
>
Save
</button>
<button
class="ml-4 px-4 py-2 bg-slate-500 text-white rounded-md"
@click="$router.go(-1)"
>
Cancel
</button>
</div>
</section>
</template>
<script lang="ts">
import { Component, Vue } from "vue-facing-decorator";
import { RouteLocation, Router } from "vue-router";
import QuickNav from "@/components/QuickNav.vue";
import TopMessage from "@/components/TopMessage.vue";
import { AppString, NotificationIface } from "@/constants/app";
import { db } from "@/db/index";
import { Contact } from "@/db/tables/contacts";
@Component({
components: {
QuickNav,
TopMessage,
},
})
export default class ContactEditView extends Vue {
$notify!: (notification: NotificationIface, timeout?: number) => void;
contact: Contact = {
did: "",
name: "",
notes: "",
};
contactName = "";
contactNotes = "";
AppString = AppString;
async created() {
const contactDid = (this.$route as RouteLocation).params.did;
if (!contactDid) {
this.$notify({
group: "alert",
type: "error",
title: "Contact Not Found",
text: "There is no contact with that DID.",
});
(this.$router as Router).push({ path: "/contacts" });
return;
}
const contact = await db.contacts.get(contactDid);
if (contact) {
this.contact = contact;
this.contactName = contact.name || "";
this.contactNotes = contact.notes || "";
}
}
async saveEdit() {
await db.contacts.update(this.contact.did, {
name: this.contactName,
notes: this.contactNotes,
});
this.$notify({
group: "alert",
type: "success",
title: "Notes Saved",
text: "The contact notes have been updated successfully.",
});
(this.$router as Router).push({
path: "/did/" + encodeURIComponent(this.contact.did),
});
}
}
</script>

41
src/views/ContactsView.vue

@ -170,27 +170,34 @@
)
: contactsSelected.push(contact.did)
"
class="ml-2 h-6 w-6"
class="ml-2 h-6 w-6 flex-shrink-0"
data-testId="contactCheckOne"
/>
<h2 class="text-base font-semibold ml-2">
{{ contact.name || AppString.NO_CONTACT_NAME }}
<h2 class="text-base font-semibold ml-2 w-1/3 truncate flex-shrink-0">
{{ contactNameNonBreakingSpace(contact.name) }}
</h2>
<router-link
:to="{
path: '/did/' + encodeURIComponent(contact.did),
}"
title="See more about this person"
>
<fa icon="circle-info" class="text-xl text-blue-500 ml-4" />
</router-link>
<span>
<div class="flex items-center">
<router-link
:to="{
path: '/did/' + encodeURIComponent(contact.did),
}"
title="See more about this person"
>
<fa icon="circle-info" class="text-xl text-blue-500 ml-4" />
</router-link>
<span class="ml-4 text-sm overflow-hidden">{{
shortDid(contact.did)
}}</span
><!-- The first 18 characters of did:peer are the same. -->
<span class="ml-4 text-sm overflow-hidden">{{
shortDid(contact.did)
}}</span
>
</div>
<div class="ml-4 text-sm">
{{ contact.notes }}
</div>
</span>
</div>
<div id="ContactActions" class="flex gap-1.5 mt-2">
<div
@ -542,6 +549,10 @@ export default class ContactsView extends Vue {
}
}
private contactNameNonBreakingSpace(contactName?: string) {
return (contactName || AppString.NO_CONTACT_NAME).replace(/\s/g, "\u00A0");
}
private danger(message: string, title: string = "Error", timeout = 5000) {
this.$notify(
{

63
src/views/DIDView.vue

@ -26,15 +26,11 @@
<div>
<h2 class="text-xl font-semibold">
{{ contactFromDid?.name || "(no name)" }}
<button
@click="
contactEdit = true;
contactNewName = (contactFromDid?.name as string) || '';
"
title="Edit"
<router-link
:to="{ name: 'contact-edit', params: { did: contactFromDid?.did } }"
>
<fa icon="pen" class="text-sm text-blue-500 ml-2 mb-1" />
</button>
</router-link>
</h2>
<button
@click="showDidDetails = !showDidDetails"
@ -163,34 +159,6 @@
</div>
</div>
<!-- Edit Name Dialog, maybe should be replaced by ContactNameDialog -->
<div v-if="contactEdit" class="dialog-overlay">
<div class="dialog">
<h1 class="text-xl font-bold text-center mb-4">Edit Name</h1>
<input
type="text"
class="block w-full rounded border border-slate-400 mb-2 px-3 py-2"
placeholder="Name"
v-model="contactNewName"
/>
<div class="flex justify-between">
<button
class="text-sm bg-blue-600 text-white px-2 py-1.5 rounded -ml-1.5 border-l border-blue-400"
@click="onClickSaveName(contactNewName)"
>
<fa icon="save" />
</button>
<span class="inline-block w-2" />
<button
class="text-sm bg-blue-600 text-white px-2 py-1.5 rounded -ml-1.5 border-l border-blue-400"
@click="onClickCancelName()"
>
<fa icon="ban" />
</button>
</div>
</div>
</div>
<!-- Loading Animation -->
<div
class="fixed left-6 bottom-24 text-center text-4xl leading-none bg-slate-400 text-white w-14 py-2.5 rounded-full"
@ -290,8 +258,6 @@ export default class DIDView extends Vue {
apiServer = "";
claims: Array<GenericCredWrapper<GenericVerifiableCredential>> = [];
contactFromDid?: Contact;
contactEdit = false;
contactNewName: string = "";
contactYaml = "";
hitEnd = false;
isLoading = false;
@ -559,29 +525,6 @@ export default class DIDView extends Vue {
return claim.claim.name || claim.claim.description || "";
}
private async onClickCancelName() {
this.contactEdit = false;
}
private async onClickSaveName(newName: string) {
if (!this.contactFromDid) {
this.$notify(
{
group: "alert",
type: "danger",
title: "Not A Contact",
text: "First add this on the contact page, then you can edit here.",
},
5000,
);
return;
}
this.contactFromDid.name = newName;
return db.contacts
.update(this.contactFromDid.did, { name: newName })
.then(() => (this.contactEdit = false));
}
// note that this is also in ContactView.vue
async confirmSetVisibility(contact: Contact, visibility: boolean) {
const visibilityPrompt = visibility

Loading…
Cancel
Save