forked from trent_larson/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;
|
||||
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
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
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,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(
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user