forked from jsnbuchanan/crowd-funder-for-time-pwa
add a contact-edit page and allow saving of notes
This commit is contained in:
@@ -2,6 +2,7 @@ export interface Contact {
|
|||||||
did: string;
|
did: string;
|
||||||
name?: string;
|
name?: string;
|
||||||
nextPubKeyHashB64?: string; // base64-encoded SHA256 hash of next public key
|
nextPubKeyHashB64?: string; // base64-encoded SHA256 hash of next public key
|
||||||
|
notes?: string;
|
||||||
profileImageUrl?: string;
|
profileImageUrl?: string;
|
||||||
publicKeyBase64?: string;
|
publicKeyBase64?: string;
|
||||||
seesMe?: boolean; // cached value of the server setting
|
seesMe?: boolean; // cached value of the server setting
|
||||||
|
|||||||
@@ -64,6 +64,11 @@ const routes: Array<RouteRecordRaw> = [
|
|||||||
name: "contact-amounts",
|
name: "contact-amounts",
|
||||||
component: () => import("../views/ContactAmountsView.vue"),
|
component: () => import("../views/ContactAmountsView.vue"),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: "/contact-edit/:did",
|
||||||
|
name: "contact-edit",
|
||||||
|
component: () => import("../views/ContactEditView.vue"),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: "/contact-gift",
|
path: "/contact-gift",
|
||||||
name: "contact-gift",
|
name: "contact-gift",
|
||||||
|
|||||||
@@ -351,7 +351,7 @@
|
|||||||
>
|
>
|
||||||
Details
|
Details
|
||||||
<fa v-if="showVeriClaimDump" icon="chevron-up" />
|
<fa v-if="showVeriClaimDump" icon="chevron-up" />
|
||||||
<fa v-else icon="chevron-down" />
|
<fa v-else icon="chevron-right" />
|
||||||
</h2>
|
</h2>
|
||||||
<div v-if="showVeriClaimDump">
|
<div v-if="showVeriClaimDump">
|
||||||
<div
|
<div
|
||||||
|
|||||||
@@ -261,7 +261,7 @@
|
|||||||
>
|
>
|
||||||
Details
|
Details
|
||||||
<fa v-if="showVeriClaimDump" icon="chevron-up" />
|
<fa v-if="showVeriClaimDump" icon="chevron-up" />
|
||||||
<fa v-else icon="chevron-down" />
|
<fa v-else icon="chevron-right" />
|
||||||
</h2>
|
</h2>
|
||||||
<div v-if="showVeriClaimDump">
|
<div v-if="showVeriClaimDump">
|
||||||
<div
|
<div
|
||||||
|
|||||||
130
src/views/ContactEditView.vue
Normal file
130
src/views/ContactEditView.vue
Normal file
@@ -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>
|
||||||
@@ -170,14 +170,16 @@
|
|||||||
)
|
)
|
||||||
: contactsSelected.push(contact.did)
|
: contactsSelected.push(contact.did)
|
||||||
"
|
"
|
||||||
class="ml-2 h-6 w-6"
|
class="ml-2 h-6 w-6 flex-shrink-0"
|
||||||
data-testId="contactCheckOne"
|
data-testId="contactCheckOne"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<h2 class="text-base font-semibold ml-2">
|
<h2 class="text-base font-semibold ml-2 w-1/3 truncate flex-shrink-0">
|
||||||
{{ contact.name || AppString.NO_CONTACT_NAME }}
|
{{ contactNameNonBreakingSpace(contact.name) }}
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
|
<span>
|
||||||
|
<div class="flex items-center">
|
||||||
<router-link
|
<router-link
|
||||||
:to="{
|
:to="{
|
||||||
path: '/did/' + encodeURIComponent(contact.did),
|
path: '/did/' + encodeURIComponent(contact.did),
|
||||||
@@ -190,7 +192,12 @@
|
|||||||
<span class="ml-4 text-sm overflow-hidden">{{
|
<span class="ml-4 text-sm overflow-hidden">{{
|
||||||
shortDid(contact.did)
|
shortDid(contact.did)
|
||||||
}}</span
|
}}</span
|
||||||
><!-- The first 18 characters of did:peer are the same. -->
|
>
|
||||||
|
</div>
|
||||||
|
<div class="ml-4 text-sm">
|
||||||
|
{{ contact.notes }}
|
||||||
|
</div>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div id="ContactActions" class="flex gap-1.5 mt-2">
|
<div id="ContactActions" class="flex gap-1.5 mt-2">
|
||||||
<div
|
<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) {
|
private danger(message: string, title: string = "Error", timeout = 5000) {
|
||||||
this.$notify(
|
this.$notify(
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -26,15 +26,11 @@
|
|||||||
<div>
|
<div>
|
||||||
<h2 class="text-xl font-semibold">
|
<h2 class="text-xl font-semibold">
|
||||||
{{ contactFromDid?.name || "(no name)" }}
|
{{ contactFromDid?.name || "(no name)" }}
|
||||||
<button
|
<router-link
|
||||||
@click="
|
:to="{ name: 'contact-edit', params: { did: contactFromDid?.did } }"
|
||||||
contactEdit = true;
|
|
||||||
contactNewName = (contactFromDid?.name as string) || '';
|
|
||||||
"
|
|
||||||
title="Edit"
|
|
||||||
>
|
>
|
||||||
<fa icon="pen" class="text-sm text-blue-500 ml-2 mb-1" />
|
<fa icon="pen" class="text-sm text-blue-500 ml-2 mb-1" />
|
||||||
</button>
|
</router-link>
|
||||||
</h2>
|
</h2>
|
||||||
<button
|
<button
|
||||||
@click="showDidDetails = !showDidDetails"
|
@click="showDidDetails = !showDidDetails"
|
||||||
@@ -163,34 +159,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</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 -->
|
<!-- Loading Animation -->
|
||||||
<div
|
<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"
|
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 = "";
|
apiServer = "";
|
||||||
claims: Array<GenericCredWrapper<GenericVerifiableCredential>> = [];
|
claims: Array<GenericCredWrapper<GenericVerifiableCredential>> = [];
|
||||||
contactFromDid?: Contact;
|
contactFromDid?: Contact;
|
||||||
contactEdit = false;
|
|
||||||
contactNewName: string = "";
|
|
||||||
contactYaml = "";
|
contactYaml = "";
|
||||||
hitEnd = false;
|
hitEnd = false;
|
||||||
isLoading = false;
|
isLoading = false;
|
||||||
@@ -559,29 +525,6 @@ export default class DIDView extends Vue {
|
|||||||
return claim.claim.name || claim.claim.description || "";
|
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
|
// note that this is also in ContactView.vue
|
||||||
async confirmSetVisibility(contact: Contact, visibility: boolean) {
|
async confirmSetVisibility(contact: Contact, visibility: boolean) {
|
||||||
const visibilityPrompt = visibility
|
const visibilityPrompt = visibility
|
||||||
|
|||||||
Reference in New Issue
Block a user