Browse Source

fix registration, separate ID creation to allow new random ones, and refactor warning and other verbiage

kb/add-usage-guide
Trent Larson 1 year ago
parent
commit
944b0ad759
  1. 1
      project.task.yaml
  2. 8
      src/router/index.ts
  3. 45
      src/views/AccountViewView.vue
  4. 2
      src/views/ContactQRScanShowView.vue
  5. 2
      src/views/ContactsView.vue
  6. 55
      src/views/HelpView.vue
  7. 112
      src/views/NewIdentifierView.vue
  8. 2
      src/views/StartView.vue

1
project.task.yaml

@ -4,6 +4,7 @@
- add infinite scroll assignee:matthew - add infinite scroll assignee:matthew
blocks: ref:https://raw.githubusercontent.com/trentlarson/lives-of-gifts/master/project.yaml#kickstarter%20for%20time blocks: ref:https://raw.githubusercontent.com/trentlarson/lives-of-gifts/master/project.yaml#kickstarter%20for%20time
- allow new (random) user creation, and make accurate message about registration
- allow type annotations in World.js & landmarks.js (since we get this error: "Types are not supported by current JavaScript version") - allow type annotations in World.js & landmarks.js (since we get this error: "Types are not supported by current JavaScript version")
- replace user-affecting console.log & console.error with error messages (eg. catches) - replace user-affecting console.log & console.error with error messages (eg. catches)

8
src/router/index.ts

@ -111,6 +111,14 @@ const routes: Array<RouteRecordRaw> = [
/* webpackChunkName: "new-edit-project" */ "../views/NewEditProjectView.vue" /* webpackChunkName: "new-edit-project" */ "../views/NewEditProjectView.vue"
), ),
}, },
{
path: "/new-identifier",
name: "new-identifier",
component: () =>
import(
/* webpackChunkName: "new-identifier" */ "../views/NewIdentifierView.vue"
),
},
{ {
path: "/project", path: "/project",
name: "project", name: "project",

45
src/views/AccountViewView.vue

@ -66,20 +66,22 @@
</span> </span>
</div> </div>
<!-- Friend referral requirement notice --> <!-- Registration notice -->
<!-- We won't show any loading indicator; we'll just pop the message in once we know they need it. -->
<div <div
v-if="!loadingLimits && !limits?.nextWeekBeginDateTime"
class="bg-amber-200 text-amber-900 border-amber-500 border-dashed border text-center rounded-md overflow-hidden px-4 py-3 mb-4" class="bg-amber-200 text-amber-900 border-amber-500 border-dashed border text-center rounded-md overflow-hidden px-4 py-3 mb-4"
> >
<p class="mb-4"> <p class="mb-4">
<b>Important:</b> before you can create a new project or commit time to <b>Note:</b> Before you can publicly announce a new project or time
one, you need a friend to register you. commitment, a friend needs to register you.
</p> </p>
<button <router-link
id="btnShowQR" :to="{ name: 'contact-qr' }"
class="inline-block text-md uppercase bg-amber-600 text-white px-4 py-2 rounded-md" class="inline-block text-md uppercase bg-amber-600 text-white px-4 py-2 rounded-md"
> >
Share Your ID Share Your Info
</button> </router-link>
</div> </div>
<!-- Identity Details --> <!-- Identity Details -->
@ -181,7 +183,7 @@
<div class="text-slate-500 text-center"> <div class="text-slate-500 text-center">
<b>ID:</b> <code>did:peer:kl45kj41lk451kl3</code> <b>ID:</b> <code>did:peer:kl45kj41lk451kl3</code>
</div> </div>
<img src="img/sample-qr-code.png" class="w-full mb-3" /> <img src="/img/sample-qr-code.png" class="w-full mb-3" />
<button <button
value="cancel" value="cancel"
@ -229,6 +231,13 @@
<button class="text-center text-md text-blue-500" @click="checkLimits()"> <button class="text-center text-md text-blue-500" @click="checkLimits()">
Check Limits Check Limits
</button> </button>
<!-- show spinner if loading limits -->
<div v-if="loadingLimits" class="ml-2">
Checking... <fa icon="spinner" class="fa-spin"></fa>
</div>
<div class="ml-2">
{{ limitsMessage }}
</div>
<div v-if="!!limits?.nextWeekBeginDateTime" class="px-9"> <div v-if="!!limits?.nextWeekBeginDateTime" class="px-9">
<span class="font-bold">Rate Limits</span> <span class="font-bold">Rate Limits</span>
<p> <p>
@ -280,7 +289,7 @@
</div> </div>
<div v-if="numAccounts > 0" class="flex py-2"> <div v-if="numAccounts > 0" class="flex py-2">
Switch Account Switch Identifier
<span v-for="accountNum in numAccounts" :key="accountNum"> <span v-for="accountNum in numAccounts" :key="accountNum">
<button class="text-blue-500 px-2" @click="switchAccount(accountNum)"> <button class="text-blue-500 px-2" @click="switchAccount(accountNum)">
#{{ accountNum }} #{{ accountNum }}
@ -357,6 +366,8 @@ export default class AccountViewView extends Vue {
publicHex = ""; publicHex = "";
publicBase64 = ""; publicBase64 = "";
limits: RateLimits | null = null; limits: RateLimits | null = null;
limitsMessage = "";
loadingLimits = true; // might as well now that we do it on mount, to avoid flashing the registration message
showContactGives = false; showContactGives = false;
showDidCopy = false; showDidCopy = false;
@ -388,6 +399,7 @@ export default class AccountViewView extends Vue {
// assign this to a class variable, eg. "registerThisUser = testServerRegisterUser", // assign this to a class variable, eg. "registerThisUser = testServerRegisterUser",
// select a component in the extension, and enter in the console: $vm.ctx.registerThisUser() // select a component in the extension, and enter in the console: $vm.ctx.registerThisUser()
//testServerRegisterUser(); //testServerRegisterUser();
try { try {
await db.open(); await db.open();
const settings = await db.settings.get(MASTER_SETTINGS_KEY); const settings = await db.settings.get(MASTER_SETTINGS_KEY);
@ -441,6 +453,8 @@ export default class AccountViewView extends Vue {
this.alertTitle = "Error Creating Account"; this.alertTitle = "Error Creating Account";
this.isAlertVisible = true; this.isAlertVisible = true;
} }
this.checkLimits();
} }
public async updateShowContactAmounts() { public async updateShowContactAmounts() {
@ -482,6 +496,9 @@ export default class AccountViewView extends Vue {
} }
async checkLimits() { async checkLimits() {
this.loadingLimits = true;
this.limitsMessage = "";
const url = this.apiServer + "/api/report/rateLimits"; const url = this.apiServer + "/api/report/rateLimits";
await accountsDB.open(); await accountsDB.open();
const accounts = await accountsDB.accounts.toArray(); const accounts = await accountsDB.accounts.toArray();
@ -502,18 +519,14 @@ export default class AccountViewView extends Vue {
} catch (error: unknown) { } catch (error: unknown) {
const serverError = error as AxiosError; const serverError = error as AxiosError;
this.alertTitle = "Error from Server";
console.error("Bad response retrieving limits: ", serverError); console.error("Bad response retrieving limits: ", serverError);
// Anybody know how to access items inside "response.data" without this? // Anybody know how to access items inside "response.data" without this?
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
const data: any = serverError.response?.data; const data: any = serverError.response?.data;
if (data.error.message) { this.limitsMessage = data?.error?.message || "Bad server response.";
this.alertMessage = data.error.message;
} else {
this.alertMessage = "Bad server response. See logs for details.";
}
this.isAlertVisible = true;
} }
this.loadingLimits = false;
} }
async switchAccount(accountNum: number) { async switchAccount(accountNum: number) {

2
src/views/ContactQRScanShowView.vue

@ -51,7 +51,7 @@
<section id="Content" class="p-6 pb-24"> <section id="Content" class="p-6 pb-24">
<!-- Heading --> <!-- Heading -->
<h1 id="ViewHeading" class="text-4xl text-center font-light pt-4 mb-8"> <h1 id="ViewHeading" class="text-4xl text-center font-light pt-4 mb-8">
Contact Info Your Contact Info
</h1> </h1>
<!-- <!--

2
src/views/ContactsView.vue

@ -495,7 +495,7 @@ export default class ContactsView extends Vue {
"@type": "RegisterAction", "@type": "RegisterAction",
agent: { identifier: identity.did }, agent: { identifier: identity.did },
object: SERVICE_ID, object: SERVICE_ID,
recipient: { identifier: contact.did }, participant: { identifier: contact.did },
}; };
// Make a payload for the claim // Make a payload for the claim
const vcPayload = { const vcPayload = {

55
src/views/HelpView.vue

@ -60,14 +60,14 @@
gifts and collaboration. gifts and collaboration.
</p> </p>
<h2 class="text-xl font-semibold">How is this app useful?</h2> <h2 class="text-xl font-semibold">What is the philosophy here?</h2>
<p> <p>
We are building networks of people who want to grow a gifting society. We are building networks of people who want to grow a gifting society.
First of all, you can record ways you've seen people give, and that First of all, you can record ways you've seen people give, and that
leaves a permanent record... one that they show came from you. This is leaves a permanent record -- one that came from you, and the recipient
personally gratifying, but it extends to broader work: volunteers can can prove it was for them. This is personally gratifying, but it extends
get confirmation of activity and selectively show off their to broader work: volunteers can get confirmation of activity and
contributions and network. selectively show off their contributions and network.
</p> </p>
<p> <p>
You can also record projects and plans and invite others to collaborate. You can also record projects and plans and invite others to collaborate.
@ -83,10 +83,25 @@
the control; this app gives you the control. the control; this app gives you the control.
</p> </p>
<h2 class="text-xl font-semibold">How do I take my first action?</h2>
<p>
You need someone to register you -- usually the person who told you
about this app, on the Contacts
<fa icon="circle-user" class="fa-fw" /> page. After they register you,
and after you have contacts, you can select any contact on the home page
and record your appreciation for... whatever. That is a claim recorded
on a custom ledger. The day after being registered, you'll be able to
register others; later, you can create projects, too.
</p>
<p>
Note that there are limits to how many each person can register, so you
may have to wait.
</p>
<h2 class="text-xl font-semibold">How do I backup all my data?</h2> <h2 class="text-xl font-semibold">How do I backup all my data?</h2>
<p> <p>
There are two parts to backup your data: the identifier secrets and the There are two sets of data to backup: the identifier secrets and the
other data such as settings, contacts, etc. other data that isn't quite a secret such as settings, contacts, etc.
</p> </p>
<div class="px-4"> <div class="px-4">
@ -100,6 +115,10 @@
<li> <li>
Click on "Backup Identifier Seed" and follow the instructions. Click on "Backup Identifier Seed" and follow the instructions.
</li> </li>
<li>
If you have other identifiers, switch to each one and repeat those
steps.
</li>
</ul> </ul>
<h2 class="text-xl font-semibold"> <h2 class="text-xl font-semibold">
@ -156,28 +175,6 @@
key. key.
</p> </p>
<h2 class="text-xl font-semibold">
How do I get permission to store claims on the server?
</h2>
<p>
Get registered by someone else with the app; they can register you on
the Contacts <fa icon="circle-user" class="fa-fw" /> page. There are
limits to how many each person can register, so you may have to wait.
</p>
<h2 class="text-xl font-semibold">What do you mean by "claims"?</h2>
<p>
Certain actions in this app are signed by your private keys, and these
are often called "claims". For example, when you give time to a person
or project, you sign a claim declaring that you gave that time. When you
declare a project, you sign a claim declaring it to the world. When you
confirm someone else's claim, you sign a claim of agreement.
</p>
<p>
Some of the data in this app does not involve claims, such as your
contact list and your identifier.
</p>
<h2 class="text-xl font-semibold"> <h2 class="text-xl font-semibold">
I know there is a record from someone, so why can't I see that info? I know there is a record from someone, so why can't I see that info?
</h2> </h2>

112
src/views/NewIdentifierView.vue

@ -0,0 +1,112 @@
<template>
<!-- QUICK NAV -->
<nav id="QuickNav" class="fixed bottom-0 left-0 right-0 bg-slate-200 z-50">
<ul class="flex text-2xl p-2 gap-2">
<!-- Home Feed -->
<li class="basis-1/5 rounded-md text-slate-500">
<router-link :to="{ name: 'home' }" class="block text-center py-3 px-1">
<fa icon="house-chimney" class="fa-fw"></fa>
</router-link>
</li>
<!-- Search -->
<li class="basis-1/5 rounded-md text-slate-500">
<router-link
:to="{ name: 'discover' }"
class="block text-center py-3 px-1"
>
<fa icon="magnifying-glass" class="fa-fw"></fa>
</router-link>
</li>
<!-- Projects -->
<li class="basis-1/5 rounded-md text-slate-500">
<router-link
:to="{ name: 'projects' }"
class="block text-center py-3 px-1"
>
<fa icon="folder-open" class="fa-fw"></fa>
</router-link>
</li>
<!-- Contacts -->
<li class="basis-1/5 rounded-md text-slate-500">
<router-link
:to="{ name: 'contacts' }"
class="block text-center py-3 px-1"
>
<fa icon="users" class="fa-fw"></fa>
</router-link>
</li>
<!-- Profile -->
<li class="basis-1/5 rounded-md bg-slate-400 text-white">
<router-link
:to="{ name: 'account' }"
class="block text-center py-3 px-1"
>
<fa icon="circle-user" class="fa-fw"></fa>
</router-link>
</li>
</ul>
</nav>
<!-- CONTENT -->
<section id="Content" class="p-6 pb-24">
<!-- Heading -->
<h1 id="ViewHeading" class="text-4xl text-center font-light pt-4 mb-8">
Your Identity
</h1>
<div class="flex justify-between py-2">
<span />
<span v-if="loading">
Creating... <i class="fa-solid fa-loader fa-spin"></i>
</span>
<span v-else>
Created!
<i
class="fa-solid fa-burst fa-beat"
style="--fa-animation-duration: 3s"
></i>
</span>
</div>
</section>
</template>
<script lang="ts">
import "dexie-export-import";
import { Component, Vue } from "vue-facing-decorator";
import { accountsDB, db } from "@/db";
import { deriveAddress, generateSeed, newIdentifier } from "@/libs/crypto";
import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
@Component
export default class AccountViewView extends Vue {
loading = true;
async mounted() {
await accountsDB.open();
const mnemonic = generateSeed();
// address is 0x... ETH address, without "did:eth:"
const [address, privateHex, publicHex, derivationPath] =
deriveAddress(mnemonic);
const newId = newIdentifier(address, publicHex, privateHex, derivationPath);
const identity = JSON.stringify(newId);
await accountsDB.accounts.add({
dateCreated: new Date().toISOString(),
derivationPath: derivationPath,
did: newId.did,
identity: identity,
mnemonic: mnemonic,
publicKeyHex: newId.keys[0].publicKeyHex,
});
await db.settings.update(MASTER_SETTINGS_KEY, {
activeDid: newId.did,
});
this.loading = false;
setTimeout(() => {
this.$router.push({ name: "account" });
}, 3000);
}
}
</script>

2
src/views/StartView.vue

@ -35,7 +35,7 @@ import { Options, Vue } from "vue-class-component";
}) })
export default class StartView extends Vue { export default class StartView extends Vue {
public onClickYes() { public onClickYes() {
this.$router.push({ name: "account" }); this.$router.push({ name: "new-identifier" });
} }
public onClickNo() { public onClickNo() {

Loading…
Cancel
Save