forked from trent_larson/crowd-funder-for-time-pwa
Compare commits
40 Commits
seed-backu
...
increment-
| Author | SHA1 | Date | |
|---|---|---|---|
| 97274a701d | |||
| 81a6d73f2f | |||
| 5804f692b7 | |||
| 257aa8d49e | |||
| 34806b514b | |||
| 0024238ca8 | |||
| 0af05b4b0d | |||
| b9d59eb642 | |||
| 0c05505c46 | |||
| 98c093f655 | |||
| 88112e0629 | |||
|
|
6ab92a83bd | ||
|
|
bfc52151c0 | ||
|
|
868b5413de | ||
|
|
50005a0dc3 | ||
|
|
9247b6ed1f | ||
|
|
75f26ccf2d | ||
|
|
bfd2498906 | ||
|
|
4933017e9c | ||
|
|
18c23451bb | ||
| 6d1756b4a5 | |||
| ac4c92d8e8 | |||
| 937a3cb6c6 | |||
| bf6830a1a8 | |||
|
|
5addc3c206 | ||
|
|
69f2f3cfd2 | ||
| be348461f1 | |||
| 6e2c596030 | |||
|
|
c502869c5f | ||
|
|
b7aacd63e6 | ||
|
|
5bc0e27b30 | ||
|
|
a4fe94f081 | ||
|
|
8de95566df | ||
|
|
97569697f6 | ||
|
|
b9ed9d748b | ||
|
|
790d44db81 | ||
| e2bf469dc1 | |||
| 592ffacebc | |||
| b706e65598 | |||
|
|
6e3066ae92 |
@@ -11,6 +11,9 @@ npm run serve
|
|||||||
```
|
```
|
||||||
|
|
||||||
### Compiles and minifies for production
|
### Compiles and minifies for production
|
||||||
|
|
||||||
|
If you are deploying in a subdirectory, add it to `publicPath` in vue.config.js, eg: `publicPath: "/app/time-tracker/",`
|
||||||
|
|
||||||
```
|
```
|
||||||
npm run build
|
npm run build
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -1,45 +1,55 @@
|
|||||||
|
|
||||||
tasks:
|
tasks:
|
||||||
|
- test alerts on all pages -- or refactor to new "notify" (since AlertMessage refactoring may require a change, et. ContactQRScanShowView)
|
||||||
- .2 bug - on contacts view, click on "to" & "from" and nothing happens
|
- .2 bug - on contacts view, click on "to" & "from" and nothing happens
|
||||||
- 01 add a location for a project via map pin :
|
- 01 add a location for a project via map pin :
|
||||||
- add with a "location" field containing this: { "geo":{ "@type":"GeoCoordinates", "latitude":40.883944, "longitude":-111.884787 } }
|
- add with a "location" field containing this: { "geo":{ "@type":"GeoCoordinates", "latitude":40.883944, "longitude":-111.884787 } }
|
||||||
- 04 search by a bounding box for local projects (see API by clicking on "Nearby")
|
|
||||||
- 01 Replace Gifted/Give in ContactsView with GiftedDialog assignee:jose
|
|
||||||
- 02 Fix images on projectview - allow choice of image from a pallete of images or a url image.
|
|
||||||
|
|
||||||
- 08 Scan QR code to import into contacts.
|
|
||||||
|
|
||||||
- 40 notifications :
|
- 40 notifications :
|
||||||
- push, where we trigger a ServiceWorker(?) in the app to reach out and check for new data
|
- push, where we trigger a ServiceWorker(?) in the app to reach out and check for new data assignee:matthew
|
||||||
|
|
||||||
- refactor UI :
|
- 01 add a location for a project via map pin
|
||||||
- .5 Alerts show at the top and can be missed if you've scrolled down on the page, eg. account data download
|
- 04 search by a bounding box for local projects (see API by clicking on "Nearby")
|
||||||
- .2 Make alerts at the top more visible (because they're currently a similar color and sometimes aren't seen)
|
- 01 Replace Gifted/Give in ContactsView with GiftedDialog assignee:matthew
|
||||||
|
- 02 Fix images on projectview - allow choice of image from a pallete of images or a url image (discovery page display also)
|
||||||
|
- SEE: https://github.com/dmester/jdenticon assignee:jose
|
||||||
|
|
||||||
- Show pop-up or some message confirming that settings & contacts download has been initiated/finished
|
- 08 Scan QR code to import into contacts assignee:matthew
|
||||||
|
- SEE: https://github.com/gruhn/vue-qrcode-reader
|
||||||
|
|
||||||
- Ensure each action sent to the server has a confirmation - eg registration
|
- 01 Show pop-up or some message confirming that settings & contacts download has been initiated/finished assignee:matthew
|
||||||
|
|
||||||
|
- 01 Ensure each action sent to the server has a confirmation - eg registration (ie a toast something that dismisses after 5-10s)
|
||||||
|
- SEE: https://github.com/emmanuelsw/notiwind assignee:jose
|
||||||
|
|
||||||
- Home Feed & Quick Give screen :
|
- Home Feed & Quick Give screen :
|
||||||
- 01 save the feed-viewed status in settings storage ("afterQuery")
|
- 01 save the feed-viewed status in settings storage ("afterQuery")
|
||||||
- 01 quick action - send action, maybe choose via canvas tool https://github.com/konvajs/vue-konva
|
- 01 quick action - send action, maybe choose via canvas tool
|
||||||
|
- SEE: https://github.com/konvajs/vue-konva
|
||||||
|
|
||||||
- 24 Move to Vite
|
- 24 Move to Vite assignee:matthew
|
||||||
|
|
||||||
|
- .5 include the hash of the latest commit, and maybe a version
|
||||||
- .5 add link to further project / people when a project pays ahead
|
- .5 add link to further project / people when a project pays ahead
|
||||||
- .5 add project ID to the URL, to make a project publicly-accessible
|
- .5 add project ID to the URL, to make a project publicly-accessible
|
||||||
- .5 remove edit from project page for projects owned by others
|
- .5 remove edit from project page for projects owned by others
|
||||||
- .5 fix where user 0 sees no txns from user 1 on contacts page but sees them on list page
|
- .5 fix where user 0 sees no txns from user 1 on contacts page but sees them on list page
|
||||||
- .2 there are three dots at the top of ProjectViewView that refreshes the page but doesn't do anything else
|
|
||||||
- 01 fix images on project page, on discovery page
|
|
||||||
- .2 on ProjectViewView, show different messages for "to" and "from" sections if none exist
|
- .2 on ProjectViewView, show different messages for "to" and "from" sections if none exist
|
||||||
- .2 fix static icon to the right on project page (Matthew - I've made "Rotary" into issuer?)
|
- .2 fix static icon to the right on project page (Matthew - I've made "Rotary" into issuer?) assignee:jose
|
||||||
- .2 fix rate limit verbiage (with the new one-per-day allowance) assignee:trent
|
- .2 fix rate limit verbiage (with the new one-per-day allowance) assignee:trent
|
||||||
- .2 move 'switch identity' to the advanced section
|
- .2 move 'switch identity' to the advanced section
|
||||||
- .1 remove the logic to exclude beforeId in list of plans after server has commit 26b25af605e715600d4f12b6416ed9fd7142d164
|
- .1 remove the logic to exclude beforeId in list of plans after server has commit 26b25af605e715600d4f12b6416ed9fd7142d164
|
||||||
|
- .2 in SeedBackupView, don't load the mnemonic and keep it in memory; only load it when they click "show"
|
||||||
|
|
||||||
- Discuss whether the remaining tasks are worthwhile before MVP release.
|
- Discuss whether the remaining tasks are worthwhile before MVP release.
|
||||||
|
|
||||||
|
- 04 allow user to download claims, mine + ones I can see about me from others
|
||||||
|
- .5 change the derivation path, and regenerate test IDs
|
||||||
|
- 02 allow user to create new DIDs from the same seed phrase (ie. increment derivation path)
|
||||||
|
- .5 on ProjectView page, show immediate feedback when a gift is given (on list?) -- and consider the same for Home & Contacts pages
|
||||||
|
- .5 customize favicon
|
||||||
|
- .5 Do we want to combine first name & last name?
|
||||||
|
- .2 Show a warning if both giver and recipient are the same (but still allow?)
|
||||||
|
|
||||||
- contacts v+ :
|
- contacts v+ :
|
||||||
- 01 Import all the non-sensitive data (ie. contacts & settings).
|
- 01 Import all the non-sensitive data (ie. contacts & settings).
|
||||||
- .2 show error to user when adding a duplicate contact
|
- .2 show error to user when adding a duplicate contact
|
||||||
@@ -52,12 +62,6 @@ tasks:
|
|||||||
- maybe - allow type annotations in World.js & landmarks.js (since we get this error - "Types are not supported by current JavaScript version")
|
- maybe - allow type annotations in World.js & landmarks.js (since we get this error - "Types are not supported by current JavaScript version")
|
||||||
- 08 convert to cleaner implementation (maybe Drie -- https://github.com/janvorisek/drie)
|
- 08 convert to cleaner implementation (maybe Drie -- https://github.com/janvorisek/drie)
|
||||||
|
|
||||||
- .5 on ProjectView page, show immediate feedback when a gift is given (on list?) -- and consider the same for Home & Contacts pages
|
|
||||||
- .5 customize favicon
|
|
||||||
- 04 allow user to download claims, mine + ones I can see about me from others
|
|
||||||
- Do we want to combine first name & last name?
|
|
||||||
- Show a warning if both giver and recipient are the same (but still allow?)
|
|
||||||
|
|
||||||
- Release Minimum Viable Product :
|
- Release Minimum Viable Product :
|
||||||
- 08 thorough testing for errors & edge cases
|
- 08 thorough testing for errors & edge cases
|
||||||
- Turn off stats-world or ensure it's usable (eg. cannot zoom out too far and lose world, cannot screenshot).
|
- Turn off stats-world or ensure it's usable (eg. cannot zoom out too far and lose world, cannot screenshot).
|
||||||
|
|||||||
58
src/App.vue
58
src/App.vue
@@ -1,6 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<router-view />
|
<router-view />
|
||||||
|
|
||||||
|
<!-- https://github.com/emmanuelsw/notiwind -->
|
||||||
<NotificationGroup group="alert">
|
<NotificationGroup group="alert">
|
||||||
<div
|
<div
|
||||||
class="fixed top-4 right-4 w-full max-w-sm flex flex-col items-start justify-end"
|
class="fixed top-4 right-4 w-full max-w-sm flex flex-col items-start justify-end"
|
||||||
@@ -127,6 +128,63 @@
|
|||||||
</Notification>
|
</Notification>
|
||||||
</div>
|
</div>
|
||||||
</NotificationGroup>
|
</NotificationGroup>
|
||||||
|
|
||||||
|
<NotificationGroup group="modal">
|
||||||
|
<div class="fixed z-[100] top-0 inset-x-0 w-full">
|
||||||
|
<Notification
|
||||||
|
v-slot="{ notifications, close }"
|
||||||
|
enter="transform ease-out duration-300 transition"
|
||||||
|
enter-from="translate-y-2 opacity-0 sm:translate-y-4"
|
||||||
|
enter-to="translate-y-0 opacity-100 sm:translate-y-0"
|
||||||
|
leave="transition ease-in duration-500"
|
||||||
|
leave-from="opacity-100"
|
||||||
|
leave-to="opacity-0"
|
||||||
|
move="transition duration-500"
|
||||||
|
move-delay="delay-300"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
v-for="notification in notifications"
|
||||||
|
:key="notification.id"
|
||||||
|
class="w-full"
|
||||||
|
role="alert"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
v-if="notification.type === 'notification-permission'"
|
||||||
|
class="absolute inset-0 h-screen flex flex-col items-center justify-center bg-slate-900/50"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="flex w-11/12 max-w-sm mx-auto mb-3 overflow-hidden bg-white rounded-lg shadow-lg"
|
||||||
|
>
|
||||||
|
<div class="w-full px-6 py-6 text-slate-900 text-center">
|
||||||
|
<p class="text-lg mb-4">
|
||||||
|
Would you like to turn on notifications for this app?
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<button
|
||||||
|
class="block w-full text-center text-md font-bold uppercase bg-blue-600 text-white px-2 py-2 rounded-md mb-2"
|
||||||
|
>
|
||||||
|
Turn on Notifications
|
||||||
|
</button>
|
||||||
|
<div class="grid grid-cols-2 gap-2">
|
||||||
|
<button
|
||||||
|
@click="close(notification.id)"
|
||||||
|
class="block w-full text-center text-md font-bold uppercase bg-slate-600 text-white px-2 py-2 rounded-md"
|
||||||
|
>
|
||||||
|
Maybe Later
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="block w-full text-center text-md font-bold uppercase bg-rose-600 text-white px-2 py-2 rounded-md"
|
||||||
|
>
|
||||||
|
Never
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Notification>
|
||||||
|
</div>
|
||||||
|
</NotificationGroup>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style></style>
|
<style></style>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
export enum AppString {
|
export enum AppString {
|
||||||
APP_NAME = "Kick-Start with Time",
|
APP_NAME = "Kick-Start with Time",
|
||||||
|
|
||||||
PROD_ENDORSER_API_SERVER = "https://endorser.ch:3000",
|
PROD_ENDORSER_API_SERVER = "https://api.endorser.ch",
|
||||||
TEST_ENDORSER_API_SERVER = "https://test.endorser.ch:8000",
|
TEST_ENDORSER_API_SERVER = "https://test.endorser.ch:8000",
|
||||||
LOCAL_ENDORSER_API_SERVER = "http://localhost:3000",
|
LOCAL_ENDORSER_API_SERVER = "http://localhost:3000",
|
||||||
|
|
||||||
|
|||||||
@@ -28,12 +28,12 @@ type NonsensitiveTables = {
|
|||||||
* https://9to5answer.com/how-to-bypass-warning-unexpected-any-specify-a-different-type-typescript-eslint-no-explicit-any
|
* https://9to5answer.com/how-to-bypass-warning-unexpected-any-specify-a-different-type-typescript-eslint-no-explicit-any
|
||||||
*/
|
*/
|
||||||
export type SensitiveDexie<T extends unknown = SensitiveTables> = BaseDexie & T;
|
export type SensitiveDexie<T extends unknown = SensitiveTables> = BaseDexie & T;
|
||||||
export const accountsDB = new BaseDexie("KickStartAccounts") as SensitiveDexie;
|
export const accountsDB = new BaseDexie("TimeSafariAccounts") as SensitiveDexie;
|
||||||
const SensitiveSchemas = Object.assign({}, AccountsSchema);
|
const SensitiveSchemas = Object.assign({}, AccountsSchema);
|
||||||
|
|
||||||
export type NonsensitiveDexie<T extends unknown = NonsensitiveTables> =
|
export type NonsensitiveDexie<T extends unknown = NonsensitiveTables> =
|
||||||
BaseDexie & T;
|
BaseDexie & T;
|
||||||
export const db = new BaseDexie("KickStart") as NonsensitiveDexie;
|
export const db = new BaseDexie("TimeSafari") as NonsensitiveDexie;
|
||||||
const NonsensitiveSchemas = Object.assign({}, ContactsSchema, SettingsSchema);
|
const NonsensitiveSchemas = Object.assign({}, ContactsSchema, SettingsSchema);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import { HDNode } from "@ethersproject/hdnode";
|
|||||||
import * as didJwt from "did-jwt";
|
import * as didJwt from "did-jwt";
|
||||||
import * as u8a from "uint8arrays";
|
import * as u8a from "uint8arrays";
|
||||||
|
|
||||||
|
export const DEFAULT_ROOT_DERIVATION_PATH = "m/76798669'/0'/0'/0'";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
@@ -47,17 +49,17 @@ export const newIdentifier = (
|
|||||||
*/
|
*/
|
||||||
export const deriveAddress = (
|
export const deriveAddress = (
|
||||||
mnemonic: string,
|
mnemonic: string,
|
||||||
|
derivationPath: string = DEFAULT_ROOT_DERIVATION_PATH,
|
||||||
): [string, string, string, string] => {
|
): [string, string, string, string] => {
|
||||||
const UPORT_ROOT_DERIVATION_PATH = "m/7696500'/0'/0'/0'";
|
|
||||||
mnemonic = mnemonic.trim().toLowerCase();
|
mnemonic = mnemonic.trim().toLowerCase();
|
||||||
|
|
||||||
const hdnode: HDNode = HDNode.fromMnemonic(mnemonic);
|
const hdnode: HDNode = HDNode.fromMnemonic(mnemonic);
|
||||||
const rootNode: HDNode = hdnode.derivePath(UPORT_ROOT_DERIVATION_PATH);
|
const rootNode: HDNode = hdnode.derivePath(derivationPath);
|
||||||
const privateHex = rootNode.privateKey.substring(2); // original starts with '0x'
|
const privateHex = rootNode.privateKey.substring(2); // original starts with '0x'
|
||||||
const publicHex = rootNode.publicKey.substring(2); // original starts with '0x'
|
const publicHex = rootNode.publicKey.substring(2); // original starts with '0x'
|
||||||
const address = rootNode.address;
|
const address = rootNode.address;
|
||||||
|
|
||||||
return [address, privateHex, publicHex, UPORT_ROOT_DERIVATION_PATH];
|
return [address, privateHex, publicHex, derivationPath];
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ export function didInfo(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For result, see https://endorser.ch:3000/api-docs/#/claims/post_api_v2_claim
|
* For result, see https://api.endorser.ch/api-docs/#/claims/post_api_v2_claim
|
||||||
*
|
*
|
||||||
* @param identity
|
* @param identity
|
||||||
* @param fromDid may be null
|
* @param fromDid may be null
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ import "./assets/styles/tailwind.css";
|
|||||||
|
|
||||||
import { library } from "@fortawesome/fontawesome-svg-core";
|
import { library } from "@fortawesome/fontawesome-svg-core";
|
||||||
import {
|
import {
|
||||||
|
faArrowLeft,
|
||||||
|
faArrowRight,
|
||||||
faBurst,
|
faBurst,
|
||||||
faCalendar,
|
faCalendar,
|
||||||
faChevronLeft,
|
faChevronLeft,
|
||||||
@@ -54,6 +56,8 @@ import {
|
|||||||
} from "@fortawesome/free-solid-svg-icons";
|
} from "@fortawesome/free-solid-svg-icons";
|
||||||
|
|
||||||
library.add(
|
library.add(
|
||||||
|
faArrowLeft,
|
||||||
|
faArrowRight,
|
||||||
faBurst,
|
faBurst,
|
||||||
faCalendar,
|
faCalendar,
|
||||||
faChevronLeft,
|
faChevronLeft,
|
||||||
|
|||||||
@@ -91,6 +91,14 @@ const routes: Array<RouteRecordRaw> = [
|
|||||||
/* webpackChunkName: "import-account" */ "../views/ImportAccountView.vue"
|
/* webpackChunkName: "import-account" */ "../views/ImportAccountView.vue"
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: "/import-derive",
|
||||||
|
name: "import-derive",
|
||||||
|
component: () =>
|
||||||
|
import(
|
||||||
|
/* webpackChunkName: "import-derive" */ "../views/ImportDerivedAccountView.vue"
|
||||||
|
),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: "/new-edit-account",
|
path: "/new-edit-account",
|
||||||
name: "new-edit-account",
|
name: "new-edit-account",
|
||||||
@@ -184,8 +192,7 @@ const router = createRouter({
|
|||||||
|
|
||||||
const errorHandler = (error, to, from) => {
|
const errorHandler = (error, to, from) => {
|
||||||
// Handle the error here
|
// Handle the error here
|
||||||
console.error(error, to, from);
|
console.error("Caught in top level error handler:", error, to, from);
|
||||||
console.log("XXXXX");
|
|
||||||
|
|
||||||
// You can also perform additional actions, such as displaying an error message or redirecting the user to a specific page
|
// You can also perform additional actions, such as displaying an error message or redirecting the user to a specific page
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -119,10 +119,24 @@
|
|||||||
</router-link>
|
</router-link>
|
||||||
<router-link
|
<router-link
|
||||||
:to="{ name: 'identity-switcher' }"
|
:to="{ name: 'identity-switcher' }"
|
||||||
class="block text-center text-md uppercase bg-slate-500 text-white px-1.5 py-2 rounded-md mb-8"
|
class="block text-center text-md uppercase bg-slate-500 text-white px-1.5 py-2 rounded-md mb-2"
|
||||||
>
|
>
|
||||||
Switch Identity / No Identity
|
Switch Identity / No Identity
|
||||||
</router-link>
|
</router-link>
|
||||||
|
<button
|
||||||
|
@click="
|
||||||
|
this.$notify(
|
||||||
|
{
|
||||||
|
group: 'modal',
|
||||||
|
type: 'notification-permission',
|
||||||
|
},
|
||||||
|
-1,
|
||||||
|
)
|
||||||
|
"
|
||||||
|
class="block w-full text-md uppercase bg-slate-500 text-white px-1.5 py-2 rounded-md mb-8"
|
||||||
|
>
|
||||||
|
Turn on Notifications
|
||||||
|
</button>
|
||||||
|
|
||||||
<h3 class="text-sm uppercase font-semibold mb-3">Data</h3>
|
<h3 class="text-sm uppercase font-semibold mb-3">Data</h3>
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,18 @@
|
|||||||
<template>
|
<template>
|
||||||
<QuickNav selected="Contacts"></QuickNav>
|
<QuickNav selected="Contacts"></QuickNav>
|
||||||
<section id="Content" class="p-6 pb-24">
|
<section id="Content" class="p-6 pb-24">
|
||||||
|
<!-- Breadcrumb -->
|
||||||
|
<div id="ViewBreadcrumb" class="mb-8">
|
||||||
|
<h1 class="text-lg text-center font-light relative px-7">
|
||||||
|
<!-- Back -->
|
||||||
|
<router-link
|
||||||
|
:to="{ name: 'contacts' }"
|
||||||
|
class="text-lg text-center px-2 py-1 absolute -left-2 -top-1"
|
||||||
|
><fa icon="chevron-left" class="fa-fw"></fa
|
||||||
|
></router-link>
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
<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">
|
||||||
Given with {{ contact?.name }}
|
Given with {{ contact?.name }}
|
||||||
</h1>
|
</h1>
|
||||||
@@ -11,66 +23,73 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Results List -->
|
<!-- Results List -->
|
||||||
<div>
|
<table
|
||||||
<div class="border-b border-slate-300 flex">
|
class="table-auto w-full border-t border-slate-300 text-sm sm:text-base text-center"
|
||||||
<div class="w-1/4"></div>
|
>
|
||||||
<div class="w-1/4">from them</div>
|
<thead class="bg-slate-100">
|
||||||
<div class="w-1/4"></div>
|
<tr class="border-b border-slate-300">
|
||||||
<div class="w-1/4">to them</div>
|
<th></th>
|
||||||
</div>
|
<th class="px-1 py-2">From Them</th>
|
||||||
<div
|
<th></th>
|
||||||
class="border-b border-slate-300 flex"
|
<th class="px-1 py-2">To Them</th>
|
||||||
v-for="record in giveRecords"
|
</tr>
|
||||||
:key="record.id"
|
</thead>
|
||||||
>
|
<tbody>
|
||||||
<div class="w-1/4">
|
<tr
|
||||||
{{ new Date(record.issuedAt).toLocaleString() }}
|
v-for="record in giveRecords"
|
||||||
</div>
|
:key="record.id"
|
||||||
<div class="w-1/4">
|
class="border-b border-slate-300"
|
||||||
<span v-if="record.agentDid == contact.did">
|
>
|
||||||
<div class="font-bold">
|
<td class="p-1 text-xs sm:text-sm text-left text-slate-500">
|
||||||
{{ record.amount }} {{ record.unit }}
|
{{ new Date(record.issuedAt).toLocaleString() }}
|
||||||
<span v-if="record.amountConfirmed" class="tooltip">
|
</td>
|
||||||
<fa icon="circle-check" class="text-green-600 fa-fw ml-1" />
|
<td class="p-1">
|
||||||
<span class="tooltiptext">Confirmed</span>
|
<span v-if="record.agentDid == contact.did">
|
||||||
</span>
|
<div class="font-bold">
|
||||||
<button v-else class="tooltip" @click="confirm(record)">
|
{{ record.amount }} {{ record.unit }}
|
||||||
<fa icon="circle" class="text-blue-600 fa-fw ml-1" />
|
<span v-if="record.amountConfirmed" title="Confirmed">
|
||||||
<span class="tooltiptext">Unconfirmed</span>
|
<fa icon="circle-check" class="text-green-600 fa-fw" />
|
||||||
</button>
|
</span>
|
||||||
</div>
|
<button v-else @click="confirm(record)" title="Unconfirmed">
|
||||||
<br />
|
<fa icon="circle" class="text-blue-600 fa-fw" />
|
||||||
{{ record.description }}
|
</button>
|
||||||
</span>
|
</div>
|
||||||
</div>
|
<div class="italic text-xs sm:text-sm text-slate-500">
|
||||||
<div class="w-1/8">
|
{{ record.description }}
|
||||||
<span v-if="record.agentDid == contact.did">
|
</div>
|
||||||
<fa icon="long-arrow-alt-left" class="text-slate-900 fa-fw ml-1" />
|
</span>
|
||||||
</span>
|
</td>
|
||||||
<span v-else>
|
<td class="p-1">
|
||||||
|
<span v-if="record.agentDid == contact.did">
|
||||||
<fa icon="long-arrow-alt-right" class="text-slate-900 fa-fw ml-1" />
|
<fa icon="arrow-left" class="text-slate-400 fa-fw" />
|
||||||
</span>
|
</span>
|
||||||
</div>
|
<span v-else>
|
||||||
<div class="w-1/4">
|
<fa icon="arrow-right" class="text-slate-400 fa-fw" />
|
||||||
<span v-if="record.agentDid != contact.did">
|
</span>
|
||||||
<div class="font-bold">
|
</td>
|
||||||
{{ record.amount }} {{ record.unit }}
|
<td class="p-1">
|
||||||
<span v-if="record.amountConfirmed" class="tooltip">
|
<span v-if="record.agentDid != contact.did">
|
||||||
<fa icon="circle-check" class="text-green-600 fa-fw ml-1" />
|
<div class="font-bold">
|
||||||
<span class="tooltiptext">Confirmed</span>
|
{{ record.amount }} {{ record.unit }}
|
||||||
</span>
|
<span v-if="record.amountConfirmed" title="Confirmed">
|
||||||
<button v-else class="tooltip" @click="cannotConfirmMessage()">
|
<fa icon="circle-check" class="text-green-600 fa-fw" />
|
||||||
<fa icon="circle" class="text-slate-600 fa-fw ml-1" />
|
</span>
|
||||||
<span class="tooltiptext">Unconfirmed</span>
|
<button
|
||||||
</button>
|
v-else
|
||||||
</div>
|
@click="cannotConfirmMessage()"
|
||||||
<br />
|
title="Unconfirmed"
|
||||||
{{ record.description }}
|
>
|
||||||
</span>
|
<fa icon="circle" class="text-slate-600 fa-fw" />
|
||||||
</div>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="italic text-xs sm:text-sm text-slate-500">
|
||||||
|
{{ record.description }}
|
||||||
|
</div>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
<AlertMessage
|
<AlertMessage
|
||||||
:alertTitle="alertTitle"
|
:alertTitle="alertTitle"
|
||||||
:alertMessage="alertMessage"
|
:alertMessage="alertMessage"
|
||||||
|
|||||||
@@ -17,10 +17,6 @@
|
|||||||
:dotsOptions="{ type: 'square' }"
|
:dotsOptions="{ type: 'square' }"
|
||||||
class="flex justify-center"
|
class="flex justify-center"
|
||||||
/>
|
/>
|
||||||
<AlertMessage
|
|
||||||
:alertTitle="alertTitle"
|
|
||||||
:alertMessage="alertMessage"
|
|
||||||
></AlertMessage>
|
|
||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -32,18 +28,15 @@ import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
|
|||||||
import * as R from "ramda";
|
import * as R from "ramda";
|
||||||
import { SimpleSigner } from "@/libs/crypto";
|
import { SimpleSigner } from "@/libs/crypto";
|
||||||
import * as didJwt from "did-jwt";
|
import * as didJwt from "did-jwt";
|
||||||
import AlertMessage from "@/components/AlertMessage";
|
|
||||||
import QuickNav from "@/components/QuickNav";
|
import QuickNav from "@/components/QuickNav";
|
||||||
|
import { Account } from "@/db/tables/accounts";
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||||
const Buffer = require("buffer/").Buffer;
|
const Buffer = require("buffer/").Buffer;
|
||||||
alertTitle = "";
|
|
||||||
alertMessage = "";
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
components: {
|
components: {
|
||||||
QRCodeVue3,
|
QRCodeVue3,
|
||||||
AlertMessage,
|
|
||||||
QuickNav,
|
QuickNav,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@@ -55,7 +48,10 @@ export default class ContactQRScanShow extends Vue {
|
|||||||
public async getIdentity(activeDid) {
|
public async getIdentity(activeDid) {
|
||||||
await accountsDB.open();
|
await accountsDB.open();
|
||||||
const accounts = await accountsDB.accounts.toArray();
|
const accounts = await accountsDB.accounts.toArray();
|
||||||
const account = R.find((acc) => acc.did === activeDid, accounts);
|
const account: Account | undefined = R.find(
|
||||||
|
(acc) => acc.did === activeDid,
|
||||||
|
accounts,
|
||||||
|
);
|
||||||
const identity = JSON.parse(account?.identity || "null");
|
const identity = JSON.parse(account?.identity || "null");
|
||||||
|
|
||||||
if (!identity) {
|
if (!identity) {
|
||||||
@@ -66,15 +62,6 @@ export default class ContactQRScanShow extends Vue {
|
|||||||
return identity;
|
return identity;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getHeaders(identity) {
|
|
||||||
const token = await accessToken(identity);
|
|
||||||
const headers = {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
Authorization: "Bearer " + token,
|
|
||||||
};
|
|
||||||
return headers;
|
|
||||||
}
|
|
||||||
|
|
||||||
async created() {
|
async created() {
|
||||||
await db.open();
|
await db.open();
|
||||||
const settings = await db.settings.get(MASTER_SETTINGS_KEY);
|
const settings = await db.settings.get(MASTER_SETTINGS_KEY);
|
||||||
|
|||||||
@@ -91,7 +91,6 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="grow">
|
<div class="grow">
|
||||||
<h2 class="text-base font-semibold">{{ project.name }}</h2>
|
|
||||||
<h2 class="text-base font-semibold">{{ project.name }}</h2>
|
<h2 class="text-base font-semibold">{{ project.name }}</h2>
|
||||||
<div class="text-sm">
|
<div class="text-sm">
|
||||||
<fa icon="user" class="fa-fw text-slate-400"></fa>
|
<fa icon="user" class="fa-fw text-slate-400"></fa>
|
||||||
|
|||||||
@@ -92,6 +92,21 @@
|
|||||||
>
|
>
|
||||||
Danger
|
Danger
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
<button
|
||||||
|
@click="
|
||||||
|
this.$notify(
|
||||||
|
{
|
||||||
|
group: 'modal',
|
||||||
|
type: 'notification-permission',
|
||||||
|
},
|
||||||
|
-1,
|
||||||
|
)
|
||||||
|
"
|
||||||
|
class="font-bold uppercase bg-slate-600 text-white px-3 py-2 rounded-md mr-2"
|
||||||
|
>
|
||||||
|
Notification Permission
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-8">
|
<div class="mb-8">
|
||||||
@@ -99,6 +114,18 @@
|
|||||||
<p class="mb-4">Show appreciation to a contact:</p>
|
<p class="mb-4">Show appreciation to a contact:</p>
|
||||||
|
|
||||||
<ul class="grid grid-cols-4 gap-x-3 gap-y-5 text-center mb-5">
|
<ul class="grid grid-cols-4 gap-x-3 gap-y-5 text-center mb-5">
|
||||||
|
<li @click="openDialog()">
|
||||||
|
<EntityIcon
|
||||||
|
:entityId="Anonymous"
|
||||||
|
:iconSize="64"
|
||||||
|
class="mx-auto border border-slate-300 rounded-md mb-1"
|
||||||
|
></EntityIcon>
|
||||||
|
<h3
|
||||||
|
class="text-xs italic font-medium text-ellipsis whitespace-nowrap overflow-hidden"
|
||||||
|
>
|
||||||
|
Anonymous
|
||||||
|
</h3>
|
||||||
|
</li>
|
||||||
<li
|
<li
|
||||||
v-for="contact in allContacts"
|
v-for="contact in allContacts"
|
||||||
:key="contact.did"
|
:key="contact.did"
|
||||||
@@ -112,7 +139,7 @@
|
|||||||
<h3
|
<h3
|
||||||
class="text-xs font-medium text-ellipsis whitespace-nowrap overflow-hidden"
|
class="text-xs font-medium text-ellipsis whitespace-nowrap overflow-hidden"
|
||||||
>
|
>
|
||||||
{{ contact.name || "(no name)" }}
|
{{ contact.name || contact.did }}
|
||||||
</h3>
|
</h3>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -129,6 +156,7 @@
|
|||||||
<!-- If there are no contacts, show this instead: -->
|
<!-- If there are no contacts, show this instead: -->
|
||||||
<div
|
<div
|
||||||
class="rounded border border-dashed border-slate-300 bg-slate-100 px-4 py-3 text-center italic text-slate-500"
|
class="rounded border border-dashed border-slate-300 bg-slate-100 px-4 py-3 text-center italic text-slate-500"
|
||||||
|
v-if="allContacts.length === 0"
|
||||||
>
|
>
|
||||||
(No contacts to show.)
|
(No contacts to show.)
|
||||||
</div>
|
</div>
|
||||||
@@ -350,8 +378,7 @@ export default class HomeView extends Vue {
|
|||||||
claim = claim.claim;
|
claim = claim.claim;
|
||||||
}
|
}
|
||||||
// agent.did is for legacy data, before March 2023
|
// agent.did is for legacy data, before March 2023
|
||||||
const giverDid =
|
const giverDid = claim.agent?.identifier || claim.agent?.did;
|
||||||
claim.agent?.identifier || claim.agent?.did;
|
|
||||||
const giverInfo = didInfo(
|
const giverInfo = didInfo(
|
||||||
giverDid,
|
giverDid,
|
||||||
this.activeDid,
|
this.activeDid,
|
||||||
@@ -390,7 +417,7 @@ export default class HomeView extends Vue {
|
|||||||
handleDialogResult(result) {
|
handleDialogResult(result) {
|
||||||
if (result.action === "confirm") {
|
if (result.action === "confirm") {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
this.recordGive(result.contact?.did, result.description, result.hours);
|
this.recordGive(result.giver?.did, result.description, result.hours);
|
||||||
resolve();
|
resolve();
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -24,6 +24,24 @@
|
|||||||
v-model="mnemonic"
|
v-model="mnemonic"
|
||||||
/>
|
/>
|
||||||
{{ mnemonic }}
|
{{ mnemonic }}
|
||||||
|
<h3
|
||||||
|
class="text-sm uppercase font-semibold mb-3"
|
||||||
|
@click="showAdvanced = !showAdvanced"
|
||||||
|
>
|
||||||
|
Advanced
|
||||||
|
</h3>
|
||||||
|
<div v-if="showAdvanced">
|
||||||
|
Enter a custom derivation path
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="block w-full rounded border border-slate-400 mb-4 px-3 py-2"
|
||||||
|
v-model="derivationPath"
|
||||||
|
/>
|
||||||
|
For previous uPort or Endorser users,
|
||||||
|
<a @click="derivationPath = UPORT_DERIVATION_PATH" class="text-blue-500">
|
||||||
|
click here to use that value.
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
<div class="mt-8">
|
<div class="mt-8">
|
||||||
<button
|
<button
|
||||||
@click="from_mnemonic()"
|
@click="from_mnemonic()"
|
||||||
@@ -44,7 +62,11 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Component, Vue } from "vue-facing-decorator";
|
import { Component, Vue } from "vue-facing-decorator";
|
||||||
import { deriveAddress, newIdentifier } from "../libs/crypto";
|
import {
|
||||||
|
DEFAULT_ROOT_DERIVATION_PATH,
|
||||||
|
deriveAddress,
|
||||||
|
newIdentifier,
|
||||||
|
} from "../libs/crypto";
|
||||||
import { accountsDB, db } from "@/db";
|
import { accountsDB, db } from "@/db";
|
||||||
import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
|
import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
|
||||||
|
|
||||||
@@ -52,11 +74,14 @@ import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
|
|||||||
components: {},
|
components: {},
|
||||||
})
|
})
|
||||||
export default class ImportAccountView extends Vue {
|
export default class ImportAccountView extends Vue {
|
||||||
|
UPORT_DERIVATION_PATH = "m/7696500'/0'/0'/0'";
|
||||||
|
|
||||||
mnemonic = "";
|
mnemonic = "";
|
||||||
address = "";
|
address = "";
|
||||||
privateHex = "";
|
privateHex = "";
|
||||||
publicHex = "";
|
publicHex = "";
|
||||||
derivationPath = "";
|
derivationPath = DEFAULT_ROOT_DERIVATION_PATH;
|
||||||
|
showAdvanced = false;
|
||||||
|
|
||||||
public onCancelClick() {
|
public onCancelClick() {
|
||||||
this.$router.back();
|
this.$router.back();
|
||||||
@@ -65,8 +90,10 @@ export default class ImportAccountView extends Vue {
|
|||||||
public async from_mnemonic() {
|
public async from_mnemonic() {
|
||||||
const mne: string = this.mnemonic.trim().toLowerCase();
|
const mne: string = this.mnemonic.trim().toLowerCase();
|
||||||
if (this.mnemonic.trim().length > 0) {
|
if (this.mnemonic.trim().length > 0) {
|
||||||
[this.address, this.privateHex, this.publicHex, this.derivationPath] =
|
[this.address, this.privateHex, this.publicHex] = deriveAddress(
|
||||||
deriveAddress(mne);
|
mne,
|
||||||
|
this.derivationPath,
|
||||||
|
);
|
||||||
|
|
||||||
const newId = newIdentifier(
|
const newId = newIdentifier(
|
||||||
this.address,
|
this.address,
|
||||||
|
|||||||
163
src/views/ImportDerivedAccountView.vue
Normal file
163
src/views/ImportDerivedAccountView.vue
Normal file
@@ -0,0 +1,163 @@
|
|||||||
|
<template>
|
||||||
|
<section id="Content" class="p-6 pb-24">
|
||||||
|
<!-- Breadcrumb -->
|
||||||
|
<div id="ViewBreadcrumb" class="mb-8">
|
||||||
|
<h1 class="text-lg text-center font-light relative px-7">
|
||||||
|
<!-- Cancel -->
|
||||||
|
<button
|
||||||
|
@click="$router.go(-1)"
|
||||||
|
class="text-lg text-center px-2 py-1 absolute -left-2 -top-1"
|
||||||
|
>
|
||||||
|
<fa icon="chevron-left"></fa>
|
||||||
|
</button>
|
||||||
|
Derive from Existing Identity
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
<!-- Import Account Form -->
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<p class="text-center text-xl mb-4 font-light">
|
||||||
|
Will increment the maximum derivation path from the existing seed.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p v-if="didArrays.length > 1">
|
||||||
|
Choose existing DIDs from same seed phrase to compute derivation.
|
||||||
|
</p>
|
||||||
|
<ul class="mb-4">
|
||||||
|
<li
|
||||||
|
class="block bg-slate-100 rounded-md flex items-center px-4 py-3 mb-2"
|
||||||
|
v-for="dids in didArrays"
|
||||||
|
:key="dids[0]"
|
||||||
|
@click="switchAccount(dids[0])"
|
||||||
|
>
|
||||||
|
<fa
|
||||||
|
v-if="dids[0] == selectedArrayFirstDid"
|
||||||
|
icon="circle"
|
||||||
|
class="fa-fw text-blue-400 text-xl mr-3"
|
||||||
|
></fa>
|
||||||
|
<fa
|
||||||
|
v-else
|
||||||
|
icon="circle"
|
||||||
|
class="fa-fw text-slate-400 text-xl mr-3"
|
||||||
|
></fa>
|
||||||
|
<span class="overflow-hidden">
|
||||||
|
<div class="text-sm text-slate-500 truncate">
|
||||||
|
<code>{{ dids.join(",") }}</code>
|
||||||
|
</div>
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="mt-8">
|
||||||
|
<button
|
||||||
|
@click="incrementDerivation()"
|
||||||
|
class="block w-full text-center text-lg font-bold uppercase bg-blue-600 text-white px-2 py-3 rounded-md mb-2"
|
||||||
|
>
|
||||||
|
Increment and Import
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
@click="onCancelClick()"
|
||||||
|
type="button"
|
||||||
|
class="block w-full text-center text-md uppercase bg-slate-500 text-white px-1.5 py-2 rounded-md"
|
||||||
|
>
|
||||||
|
Cancel
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { Component, Vue } from "vue-facing-decorator";
|
||||||
|
import {
|
||||||
|
DEFAULT_ROOT_DERIVATION_PATH,
|
||||||
|
deriveAddress,
|
||||||
|
newIdentifier,
|
||||||
|
} from "../libs/crypto";
|
||||||
|
import { accountsDB, db } from "@/db";
|
||||||
|
import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
components: {},
|
||||||
|
})
|
||||||
|
export default class ImportAccountView extends Vue {
|
||||||
|
derivationPath = DEFAULT_ROOT_DERIVATION_PATH;
|
||||||
|
didArrays: Array<Array<string>> = [];
|
||||||
|
selectedArrayFirstDid = "";
|
||||||
|
|
||||||
|
async mounted() {
|
||||||
|
await accountsDB.open();
|
||||||
|
const accounts = await accountsDB.accounts.toArray();
|
||||||
|
const seedDids = {};
|
||||||
|
accounts.forEach((account) => {
|
||||||
|
const prevDids = seedDids[account.mnemonic] || [];
|
||||||
|
seedDids[account.mnemonic] = prevDids.concat([account.did]);
|
||||||
|
});
|
||||||
|
this.didArrays = Object.values(seedDids);
|
||||||
|
this.selectedArrayFirstDid = this.didArrays[0][0];
|
||||||
|
}
|
||||||
|
|
||||||
|
public onCancelClick() {
|
||||||
|
this.$router.back();
|
||||||
|
}
|
||||||
|
|
||||||
|
public switchAccount(did: string) {
|
||||||
|
this.selectedArrayFirstDid = did;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async incrementDerivation() {
|
||||||
|
await accountsDB.open();
|
||||||
|
// find the maximum derivation path for the selected DIDs
|
||||||
|
const selectedArray: Array<string> = this.didArrays.find(
|
||||||
|
(dids) => dids[0] === this.selectedArrayFirstDid,
|
||||||
|
);
|
||||||
|
const allMatchingAccounts = await accountsDB.accounts
|
||||||
|
.where("did")
|
||||||
|
.anyOf(...selectedArray)
|
||||||
|
.toArray();
|
||||||
|
const accountWithMaxDeriv = allMatchingAccounts[0];
|
||||||
|
allMatchingAccounts.slice(1).forEach((account) => {
|
||||||
|
if (account.derivationPath > accountWithMaxDeriv.derivationPath) {
|
||||||
|
accountWithMaxDeriv.derivationPath = account.derivationPath;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// increment the last number in that max derivation path
|
||||||
|
let lastStr = accountWithMaxDeriv.derivationPath.split("/").slice(-1)[0];
|
||||||
|
if (lastStr.endsWith("'")) {
|
||||||
|
lastStr = lastStr.slice(0, -1);
|
||||||
|
}
|
||||||
|
const lastNum = parseInt(lastStr, 10);
|
||||||
|
const newLastNum = lastNum + 1;
|
||||||
|
const newDerivPath = accountWithMaxDeriv.derivationPath
|
||||||
|
.split("/")
|
||||||
|
.slice(0, -1)
|
||||||
|
.concat([newLastNum.toString() + "'"])
|
||||||
|
.join("/");
|
||||||
|
|
||||||
|
const mne: string = accountWithMaxDeriv.mnemonic;
|
||||||
|
|
||||||
|
const [address, privateHex, publicHex] = deriveAddress(mne, newDerivPath);
|
||||||
|
|
||||||
|
const newId = newIdentifier(address, publicHex, privateHex, newDerivPath);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await accountsDB.accounts.add({
|
||||||
|
dateCreated: new Date().toISOString(),
|
||||||
|
derivationPath: newDerivPath,
|
||||||
|
did: newId.did,
|
||||||
|
identity: JSON.stringify(newId),
|
||||||
|
mnemonic: mne,
|
||||||
|
publicKeyHex: newId.keys[0].publicKeyHex,
|
||||||
|
});
|
||||||
|
|
||||||
|
// record that as the active DID
|
||||||
|
await db.open();
|
||||||
|
db.settings.update(MASTER_SETTINGS_KEY, {
|
||||||
|
activeDid: newId.did,
|
||||||
|
});
|
||||||
|
this.$router.push({ name: "account" });
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Error saving mnemonic & updating settings:", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -218,13 +218,13 @@ export default class NewEditProjectView extends Vue {
|
|||||||
try {
|
try {
|
||||||
const resp = await this.axios.post(url, payload, { headers });
|
const resp = await this.axios.post(url, payload, { headers });
|
||||||
// handleId is new in server v release-1.6.0; remove fullIri when that
|
// handleId is new in server v release-1.6.0; remove fullIri when that
|
||||||
// version shows up here: https://endorser.ch:3000/api-docs/
|
// version shows up here: https://api.endorser.ch/api-docs/
|
||||||
if (resp.data?.success?.handleId || resp.data?.success?.fullIri) {
|
if (resp.data?.success?.handleId || resp.data?.success?.fullIri) {
|
||||||
this.errorMessage = "";
|
this.errorMessage = "";
|
||||||
this.alertTitle = "";
|
this.alertTitle = "";
|
||||||
this.alertMessage = "";
|
this.alertMessage = "";
|
||||||
// handleId is new in server v release-1.6.0; remove fullIri when that
|
// handleId is new in server v release-1.6.0; remove fullIri when that
|
||||||
// version shows up here: https://endorser.ch:3000/api-docs/
|
// version shows up here: https://api.endorser.ch/api-docs/
|
||||||
useAppStore().setProjectId(
|
useAppStore().setProjectId(
|
||||||
resp.data.success.handleId || resp.data.success.fullIri,
|
resp.data.success.handleId || resp.data.success.fullIri,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -12,13 +12,6 @@
|
|||||||
>
|
>
|
||||||
<fa icon="chevron-left" class="fa-fw"></fa>
|
<fa icon="chevron-left" class="fa-fw"></fa>
|
||||||
</button>
|
</button>
|
||||||
<!-- Context Menu -->
|
|
||||||
<a
|
|
||||||
href=""
|
|
||||||
class="text-lg text-center px-2 py-1 absolute -right-2 -top-1"
|
|
||||||
><fa icon="ellipsis-vertical" class="fa-fw"></fa
|
|
||||||
></a>
|
|
||||||
|
|
||||||
View Plan
|
View Plan
|
||||||
</h1>
|
</h1>
|
||||||
</div>
|
</div>
|
||||||
@@ -38,13 +31,13 @@
|
|||||||
<div class="overflow-hidden">
|
<div class="overflow-hidden">
|
||||||
<h2 class="text-xl font-semibold">{{ name }}</h2>
|
<h2 class="text-xl font-semibold">{{ name }}</h2>
|
||||||
<div class="text-sm mb-3">
|
<div class="text-sm mb-3">
|
||||||
<div class="truncate"
|
<div class="truncate">
|
||||||
><fa icon="user" class="fa-fw text-slate-400"></fa>
|
<fa icon="user" class="fa-fw text-slate-400"></fa>
|
||||||
{{ issuer }}</div
|
{{ issuer }}
|
||||||
>
|
</div>
|
||||||
<div
|
<div>
|
||||||
><fa icon="calendar" class="fa-fw text-slate-400"></fa
|
<fa icon="calendar" class="fa-fw text-slate-400"></fa>
|
||||||
>{{ timeSince }}
|
{{ timeSince }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -68,6 +61,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
|
v-if="issuer == activeDid"
|
||||||
type="button"
|
type="button"
|
||||||
class="block w-full text-center text-md uppercase bg-slate-500 text-white px-1.5 py-2 rounded-md"
|
class="block w-full text-center text-md uppercase bg-slate-500 text-white px-1.5 py-2 rounded-md"
|
||||||
@click="onEditClick()"
|
@click="onEditClick()"
|
||||||
@@ -90,9 +84,11 @@
|
|||||||
|
|
||||||
<ul class="grid grid-cols-4 gap-x-3 gap-y-5 text-center mb-5">
|
<ul class="grid grid-cols-4 gap-x-3 gap-y-5 text-center mb-5">
|
||||||
<li @click="openDialog()">
|
<li @click="openDialog()">
|
||||||
<div class="mb-1">
|
<EntityIcon
|
||||||
<fa icon="question-circle" class="fa-fw fa-xl text-slate-400"></fa>
|
:entityId="Anonymous"
|
||||||
</div>
|
:iconSize="64"
|
||||||
|
class="mx-auto border border-slate-300 rounded-md mb-1"
|
||||||
|
></EntityIcon>
|
||||||
<h3
|
<h3
|
||||||
class="text-xs italic font-medium text-ellipsis whitespace-nowrap overflow-hidden"
|
class="text-xs italic font-medium text-ellipsis whitespace-nowrap overflow-hidden"
|
||||||
>
|
>
|
||||||
@@ -104,9 +100,11 @@
|
|||||||
:key="contact.did"
|
:key="contact.did"
|
||||||
@click="openDialog(contact)"
|
@click="openDialog(contact)"
|
||||||
>
|
>
|
||||||
<div class="mb-1">
|
<EntityIcon
|
||||||
<fa icon="user" class="fa-fw fa-xl text-slate-400"></fa>
|
:entityId="contact.did"
|
||||||
</div>
|
:iconSize="64"
|
||||||
|
class="mx-auto border border-slate-300 rounded-md mb-1"
|
||||||
|
></EntityIcon>
|
||||||
<h3
|
<h3
|
||||||
class="text-xs font-medium text-ellipsis whitespace-nowrap overflow-hidden"
|
class="text-xs font-medium text-ellipsis whitespace-nowrap overflow-hidden"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -28,6 +28,14 @@
|
|||||||
<i>Don't take a screenshot or send it to any online service.</i>
|
<i>Don't take a screenshot or send it to any online service.</i>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<p v-if="numAccounts > 1">
|
||||||
|
<b class="text-orange-600">Note:</b> You have more than one identity
|
||||||
|
stored in this browser. If they are all based on the same seed as the
|
||||||
|
current identity, this one backup is sufficient; however, if you have
|
||||||
|
different seeds for other identities, you will have to back them up
|
||||||
|
separately.
|
||||||
|
</p>
|
||||||
|
|
||||||
<div class="bg-slate-100 rounded-md overflow-hidden p-4 mb-4">
|
<div class="bg-slate-100 rounded-md overflow-hidden p-4 mb-4">
|
||||||
<button
|
<button
|
||||||
class="block w-full text-center text-md uppercase bg-slate-500 text-white px-1.5 py-2 rounded-md"
|
class="block w-full text-center text-md uppercase bg-slate-500 text-white px-1.5 py-2 rounded-md"
|
||||||
@@ -60,6 +68,7 @@ import QuickNav from "@/components/QuickNav";
|
|||||||
@Component({ components: { AlertMessage, QuickNav } })
|
@Component({ components: { AlertMessage, QuickNav } })
|
||||||
export default class SeedBackupView extends Vue {
|
export default class SeedBackupView extends Vue {
|
||||||
activeAccount = null;
|
activeAccount = null;
|
||||||
|
numAccounts = 0;
|
||||||
showSeed = false;
|
showSeed = false;
|
||||||
alertMessage = "";
|
alertMessage = "";
|
||||||
alertTitle = "";
|
alertTitle = "";
|
||||||
@@ -73,6 +82,7 @@ export default class SeedBackupView extends Vue {
|
|||||||
|
|
||||||
await accountsDB.open();
|
await accountsDB.open();
|
||||||
const accounts = await accountsDB.accounts.toArray();
|
const accounts = await accountsDB.accounts.toArray();
|
||||||
|
this.numAccounts = accounts.length;
|
||||||
this.activeAccount = R.find((acc) => acc.did === activeDid, accounts);
|
this.activeAccount = R.find((acc) => acc.did === activeDid, accounts);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("Got an error loading an identity:", err);
|
console.error("Got an error loading an identity:", err);
|
||||||
|
|||||||
@@ -10,30 +10,46 @@
|
|||||||
|
|
||||||
<div class="mt-8">
|
<div class="mt-8">
|
||||||
<p class="text-center text-xl mb-4 font-light">
|
<p class="text-center text-xl mb-4 font-light">
|
||||||
Do you already have an identity to import?
|
Do you have an identity to import?
|
||||||
</p>
|
</p>
|
||||||
<a
|
<a
|
||||||
@click="onClickYes()"
|
@click="onClickYes()"
|
||||||
class="block w-full text-center text-lg font-bold uppercase bg-blue-600 text-white px-2 py-3 rounded-md mb-2"
|
class="block w-full text-center text-lg uppercase bg-blue-600 text-white px-2 py-3 rounded-md"
|
||||||
>
|
>
|
||||||
No
|
No
|
||||||
</a>
|
</a>
|
||||||
<a
|
<a
|
||||||
@click="onClickNo()"
|
@click="onClickNo()"
|
||||||
class="block w-full text-center text-md uppercase bg-slate-500 text-white px-1.5 py-2 rounded-md"
|
class="block w-full text-center text-md uppercase bg-slate-500 text-white px-1.5 py-2 rounded-md mt-2"
|
||||||
>Yes</a
|
|
||||||
>
|
>
|
||||||
|
Yes
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
v-if="numAccounts > 0"
|
||||||
|
@click="onClickDerive()"
|
||||||
|
class="block w-full text-center text-md uppercase bg-slate-500 text-white px-1.5 py-2 rounded-md mt-2"
|
||||||
|
>
|
||||||
|
Derive New Address from Seed Imported Previously
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Component, Vue } from "vue-facing-decorator";
|
import { Component, Vue } from "vue-facing-decorator";
|
||||||
|
import { accountsDB } from "@/db";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
components: {},
|
components: {},
|
||||||
})
|
})
|
||||||
export default class StartView extends Vue {
|
export default class StartView extends Vue {
|
||||||
|
numAccounts = 0;
|
||||||
|
|
||||||
|
async mounted() {
|
||||||
|
await accountsDB.open();
|
||||||
|
this.numAccounts = await accountsDB.accounts.count();
|
||||||
|
}
|
||||||
|
|
||||||
public onClickYes() {
|
public onClickYes() {
|
||||||
this.$router.push({ name: "new-identifier" });
|
this.$router.push({ name: "new-identifier" });
|
||||||
}
|
}
|
||||||
@@ -41,5 +57,9 @@ export default class StartView extends Vue {
|
|||||||
public onClickNo() {
|
public onClickNo() {
|
||||||
this.$router.push({ name: "import-account" });
|
this.$router.push({ name: "import-account" });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public onClickDerive() {
|
||||||
|
this.$router.push({ name: "import-derive" });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
Reference in New Issue
Block a user