forked from trent_larson/crowd-funder-for-time-pwa
Compare commits
1 Commits
notificati
...
no-account
| Author | SHA1 | Date | |
|---|---|---|---|
| f269f5fa77 |
@@ -11,9 +11,6 @@ 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
|
||||||
```
|
```
|
||||||
|
|||||||
40
package-lock.json
generated
40
package-lock.json
generated
@@ -33,13 +33,11 @@
|
|||||||
"ethereum-cryptography": "^2.0.0",
|
"ethereum-cryptography": "^2.0.0",
|
||||||
"ethereumjs-util": "^7.1.5",
|
"ethereumjs-util": "^7.1.5",
|
||||||
"ethr-did-resolver": "^8.0.0",
|
"ethr-did-resolver": "^8.0.0",
|
||||||
"jdenticon": "^3.2.0",
|
|
||||||
"js-generate-password": "^0.1.9",
|
"js-generate-password": "^0.1.9",
|
||||||
"localstorage-slim": "^2.4.0",
|
"localstorage-slim": "^2.4.0",
|
||||||
"luxon": "^3.3.0",
|
"luxon": "^3.3.0",
|
||||||
"merkletreejs": "^0.3.10",
|
"merkletreejs": "^0.3.10",
|
||||||
"moment": "^2.29.4",
|
"moment": "^2.29.4",
|
||||||
"notiwind": "^2.0.2",
|
|
||||||
"papaparse": "^5.4.1",
|
"papaparse": "^5.4.1",
|
||||||
"pina": "^0.20.2204228",
|
"pina": "^0.20.2204228",
|
||||||
"pinia-plugin-persistedstate": "^3.1.0",
|
"pinia-plugin-persistedstate": "^3.1.0",
|
||||||
@@ -12050,14 +12048,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/canonicalize/-/canonicalize-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/canonicalize/-/canonicalize-2.0.0.tgz",
|
||||||
"integrity": "sha512-ulDEYPv7asdKvqahuAY35c1selLdzDwHqugK92hfkzvlDCwXRRelDkR+Er33md/PtnpqHemgkuDPanZ4fiYZ8w=="
|
"integrity": "sha512-ulDEYPv7asdKvqahuAY35c1selLdzDwHqugK92hfkzvlDCwXRRelDkR+Er33md/PtnpqHemgkuDPanZ4fiYZ8w=="
|
||||||
},
|
},
|
||||||
"node_modules/canvas-renderer": {
|
|
||||||
"version": "2.2.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/canvas-renderer/-/canvas-renderer-2.2.1.tgz",
|
|
||||||
"integrity": "sha512-RrBgVL5qCEDIXpJ6NrzyRNoTnXxYarqm/cS/W6ERhUJts5UQtt/XPEosGN3rqUkZ4fjBArlnCbsISJ+KCFnIAg==",
|
|
||||||
"dependencies": {
|
|
||||||
"@types/node": "*"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/case-sensitive-paths-webpack-plugin": {
|
"node_modules/case-sensitive-paths-webpack-plugin": {
|
||||||
"version": "2.4.0",
|
"version": "2.4.0",
|
||||||
"resolved": "https://registry.npmmirror.com/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.4.0.tgz",
|
"resolved": "https://registry.npmmirror.com/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.4.0.tgz",
|
||||||
@@ -17807,20 +17797,6 @@
|
|||||||
"integrity": "sha512-JVAfqNPTvNq3sB/VHQJAFxN/sPgKnsKrCwyRt15zwNCdrMMJDdcEOdubuy+DuJYYdm0ox1J4uzEuYKkN+9yhVg==",
|
"integrity": "sha512-JVAfqNPTvNq3sB/VHQJAFxN/sPgKnsKrCwyRt15zwNCdrMMJDdcEOdubuy+DuJYYdm0ox1J4uzEuYKkN+9yhVg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/jdenticon": {
|
|
||||||
"version": "3.2.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/jdenticon/-/jdenticon-3.2.0.tgz",
|
|
||||||
"integrity": "sha512-z6Iq3fTODUMSOiR2nNYrqigS6Y0GvdXfyQWrUby7htDHvX7GNEwaWR4hcaL+FmhEgBe08Xkup/BKxXQhDJByPA==",
|
|
||||||
"dependencies": {
|
|
||||||
"canvas-renderer": "~2.2.0"
|
|
||||||
},
|
|
||||||
"bin": {
|
|
||||||
"jdenticon": "bin/jdenticon.js"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=6.4.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/jest-environment-node": {
|
"node_modules/jest-environment-node": {
|
||||||
"version": "29.5.0",
|
"version": "29.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.5.0.tgz",
|
||||||
@@ -20952,11 +20928,6 @@
|
|||||||
"node": ">= 8"
|
"node": ">= 8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/mitt": {
|
|
||||||
"version": "3.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz",
|
|
||||||
"integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw=="
|
|
||||||
},
|
|
||||||
"node_modules/mkdirp": {
|
"node_modules/mkdirp": {
|
||||||
"version": "0.5.6",
|
"version": "0.5.6",
|
||||||
"resolved": "https://registry.npmmirror.com/mkdirp/-/mkdirp-0.5.6.tgz",
|
"resolved": "https://registry.npmmirror.com/mkdirp/-/mkdirp-0.5.6.tgz",
|
||||||
@@ -21304,17 +21275,6 @@
|
|||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/notiwind": {
|
|
||||||
"version": "2.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/notiwind/-/notiwind-2.0.2.tgz",
|
|
||||||
"integrity": "sha512-wMCf+07E093d0Q78C5UHroT9GQHm4mIGerhg7dGLJ0GN6zONqKj8nTR3clkq/Y44On9k28/0DtDNwOX7FT5p/A==",
|
|
||||||
"dependencies": {
|
|
||||||
"mitt": "^3.0.1"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"vue": "^3.3.4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/npm-package-arg": {
|
"node_modules/npm-package-arg": {
|
||||||
"version": "7.0.0",
|
"version": "7.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-7.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-7.0.0.tgz",
|
||||||
|
|||||||
@@ -33,13 +33,11 @@
|
|||||||
"ethereum-cryptography": "^2.0.0",
|
"ethereum-cryptography": "^2.0.0",
|
||||||
"ethereumjs-util": "^7.1.5",
|
"ethereumjs-util": "^7.1.5",
|
||||||
"ethr-did-resolver": "^8.0.0",
|
"ethr-did-resolver": "^8.0.0",
|
||||||
"jdenticon": "^3.2.0",
|
|
||||||
"js-generate-password": "^0.1.9",
|
"js-generate-password": "^0.1.9",
|
||||||
"localstorage-slim": "^2.4.0",
|
"localstorage-slim": "^2.4.0",
|
||||||
"luxon": "^3.3.0",
|
"luxon": "^3.3.0",
|
||||||
"merkletreejs": "^0.3.10",
|
"merkletreejs": "^0.3.10",
|
||||||
"moment": "^2.29.4",
|
"moment": "^2.29.4",
|
||||||
"notiwind": "^2.0.2",
|
|
||||||
"papaparse": "^5.4.1",
|
"papaparse": "^5.4.1",
|
||||||
"pina": "^0.20.2204228",
|
"pina": "^0.20.2204228",
|
||||||
"pinia-plugin-persistedstate": "^3.1.0",
|
"pinia-plugin-persistedstate": "^3.1.0",
|
||||||
|
|||||||
@@ -1,54 +1,39 @@
|
|||||||
|
|
||||||
tasks:
|
tasks:
|
||||||
- .2 bug - on contacts view, click on "to" & "from" and nothing happens
|
|
||||||
- 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 } }
|
|
||||||
- 40 notifications :
|
|
||||||
- push, where we trigger a ServiceWorker(?) in the app to reach out and check for new data assignee:matthew
|
|
||||||
|
|
||||||
- 01 add a location for a project via map pin
|
- 01 add a location for a project via map pin
|
||||||
- 04 search by a bounding box for local projects (see API by clicking on "Nearby")
|
- 04 search by a bounding box for local projects (see API by clicking on "Nearby")
|
||||||
- 01 Replace Gifted/Give in ContactsView with GiftedDialog assignee:matthew
|
- 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 (discovery page display also)
|
- 02 Fix images on projectview - allow choice of image from a pallete of images or a url image.
|
||||||
- SEE: https://github.com/dmester/jdenticon assignee:jose
|
|
||||||
|
|
||||||
- 08 Scan QR code to import into contacts assignee:matthew
|
- 08 Scan QR code to import into contacts.
|
||||||
- SEE: https://github.com/gruhn/vue-qrcode-reader
|
|
||||||
|
|
||||||
- 01 Show pop-up or some message confirming that settings & contacts download has been initiated/finished assignee:matthew
|
- 40 notifications :
|
||||||
|
- push, where we trigger a ServiceWorker(?) in the app to reach out and check for new data
|
||||||
|
|
||||||
- 01 Ensure each action sent to the server has a confirmation - eg registration (ie a toast something that dismisses after 5-10s)
|
- refactor UI :
|
||||||
- SEE: https://github.com/emmanuelsw/notiwind assignee:jose
|
- .5 Alerts show at the top and can be missed if you've scrolled down on the page, eg. account data download
|
||||||
|
- .2 Make alerts at the top more visible (because they're currently a similar color and sometimes aren't seen)
|
||||||
|
|
||||||
|
- Show pop-up or some message confirming that settings & contacts download has been initiated/finished
|
||||||
|
|
||||||
|
- Ensure each action sent to the server has a confirmation - eg registration
|
||||||
|
|
||||||
- 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
|
- 01 quick action - send action, maybe choose via canvas tool https://github.com/konvajs/vue-konva
|
||||||
- SEE: https://github.com/konvajs/vue-konva
|
|
||||||
|
|
||||||
- 24 Move to Vite assignee:matthew
|
- 24 Move to Vite
|
||||||
|
|
||||||
- .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 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?) assignee:jose
|
- .2 fix static icon to the right on project page (Matthew - I've made "Rotary" into issuer?)
|
||||||
- .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
|
|
||||||
- .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
|
||||||
@@ -61,6 +46,12 @@ 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).
|
||||||
|
|||||||
211
src/App.vue
211
src/App.vue
@@ -1,216 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<router-view />
|
<router-view />
|
||||||
|
|
||||||
<!-- https://github.com/emmanuelsw/notiwind -->
|
|
||||||
<NotificationGroup group="alert">
|
|
||||||
<div
|
|
||||||
class="fixed top-4 right-4 w-full max-w-sm flex flex-col items-start justify-end"
|
|
||||||
>
|
|
||||||
<Notification
|
|
||||||
v-slot="{ notifications, close }"
|
|
||||||
enter="transform ease-out duration-300 transition"
|
|
||||||
enter-from="translate-y-2 opacity-0 sm:translate-y-0 sm:translate-x-4"
|
|
||||||
enter-to="translate-y-0 opacity-100 sm:translate-x-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 === 'toast'"
|
|
||||||
class="w-full max-w-sm mx-auto mb-3 overflow-hidden bg-slate-900/90 text-white rounded-lg shadow-md"
|
|
||||||
>
|
|
||||||
<div class="w-full px-4 py-3">
|
|
||||||
<span class="font-semibold">{{ notification.title }}</span>
|
|
||||||
<p class="text-sm">{{ notification.text }}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
|
||||||
v-if="notification.type === 'info'"
|
|
||||||
class="flex w-full max-w-sm mx-auto mb-3 overflow-hidden bg-slate-100 rounded-lg shadow-md"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="flex items-center justify-center w-12 bg-slate-600 text-slate-100"
|
|
||||||
>
|
|
||||||
<fa icon="circle-info" class="fa-fw fa-xl"></fa>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="relative w-full pl-4 pr-8 py-2 text-slate-900">
|
|
||||||
<span class="font-semibold">{{ notification.title }}</span>
|
|
||||||
<p class="text-sm">{{ notification.text }}</p>
|
|
||||||
|
|
||||||
<button
|
|
||||||
@click="close(notification.id)"
|
|
||||||
class="absolute top-2 right-2 px-0.5 py-0 rounded-full bg-slate-200 text-slate-600"
|
|
||||||
>
|
|
||||||
<fa icon="xmark" class="fa-fw"></fa>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
|
||||||
v-if="notification.type === 'success'"
|
|
||||||
class="flex w-full max-w-sm mx-auto mb-3 overflow-hidden bg-emerald-100 rounded-lg shadow-md"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="flex items-center justify-center w-12 bg-emerald-600 text-emerald-100"
|
|
||||||
>
|
|
||||||
<fa icon="circle-info" class="fa-fw fa-xl"></fa>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="relative w-full pl-4 pr-8 py-2 text-emerald-900">
|
|
||||||
<span class="font-semibold">{{ notification.title }}</span>
|
|
||||||
<p class="text-sm">{{ notification.text }}</p>
|
|
||||||
|
|
||||||
<button
|
|
||||||
@click="close(notification.id)"
|
|
||||||
class="absolute top-2 right-2 px-0.5 py-0 rounded-full bg-emerald-200 text-emerald-600"
|
|
||||||
>
|
|
||||||
<fa icon="xmark" class="fa-fw"></fa>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
|
||||||
v-if="notification.type === 'warning'"
|
|
||||||
class="flex w-full max-w-sm mx-auto mb-3 overflow-hidden bg-amber-100 rounded-lg shadow-md"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="flex items-center justify-center w-12 bg-amber-600 text-amber-100"
|
|
||||||
>
|
|
||||||
<fa icon="triangle-exclamation" class="fa-fw fa-xl"></fa>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="relative w-full pl-4 pr-8 py-2 text-amber-900">
|
|
||||||
<span class="font-semibold">{{ notification.title }}</span>
|
|
||||||
<p class="text-sm">{{ notification.text }}</p>
|
|
||||||
|
|
||||||
<button
|
|
||||||
@click="close(notification.id)"
|
|
||||||
class="absolute top-2 right-2 px-0.5 py-0 rounded-full bg-amber-200 text-amber-600"
|
|
||||||
>
|
|
||||||
<fa icon="xmark" class="fa-fw"></fa>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
|
||||||
v-if="notification.type === 'danger'"
|
|
||||||
class="flex w-full max-w-sm mx-auto mb-3 overflow-hidden bg-rose-100 rounded-lg shadow-md"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="flex items-center justify-center w-12 bg-rose-600 text-rose-100"
|
|
||||||
>
|
|
||||||
<fa icon="triangle-exclamation" class="fa-fw fa-xl"></fa>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="relative w-full pl-4 pr-8 py-2 text-rose-900">
|
|
||||||
<span class="font-semibold">{{ notification.title }}</span>
|
|
||||||
<p class="text-sm">{{ notification.text }}</p>
|
|
||||||
|
|
||||||
<button
|
|
||||||
@click="close(notification.id)"
|
|
||||||
class="absolute top-2 right-2 px-0.5 py-0 rounded-full bg-rose-200 text-rose-600"
|
|
||||||
>
|
|
||||||
<fa icon="xmark" class="fa-fw"></fa>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Notification>
|
|
||||||
</div>
|
|
||||||
</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 <b>turn on</b> 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
|
|
||||||
v-if="notification.type === 'notification-mute'"
|
|
||||||
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 <b>turn off</b> notifications for this app?
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<button
|
|
||||||
class="block w-full text-center text-md font-bold uppercase bg-rose-600 text-white px-2 py-2 rounded-md mb-2"
|
|
||||||
>
|
|
||||||
Turn off Notifications
|
|
||||||
</button>
|
|
||||||
<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"
|
|
||||||
>
|
|
||||||
Keep it On
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Notification>
|
|
||||||
</div>
|
|
||||||
</NotificationGroup>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style></style>
|
<style></style>
|
||||||
|
|||||||
@@ -1,19 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div v-html="generateIdenticon()" class="w-fit"></div>
|
|
||||||
</template>
|
|
||||||
<script lang="ts">
|
|
||||||
import { Vue, Component, Prop } from "vue-facing-decorator";
|
|
||||||
import { toSvg } from "jdenticon";
|
|
||||||
|
|
||||||
@Component
|
|
||||||
export default class EntityIcon extends Vue {
|
|
||||||
@Prop entityId = "";
|
|
||||||
@Prop iconSize = "";
|
|
||||||
|
|
||||||
generateIdenticon() {
|
|
||||||
const svgString = toSvg(this.entityId, this.iconSize);
|
|
||||||
return svgString;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<style scoped></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://api.endorser.ch",
|
PROD_ENDORSER_API_SERVER = "https://endorser.ch:3000",
|
||||||
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("TimeSafariAccounts") as SensitiveDexie;
|
export const accountsDB = new BaseDexie("KickStartAccounts") 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("TimeSafari") as NonsensitiveDexie;
|
export const db = new BaseDexie("KickStart") as NonsensitiveDexie;
|
||||||
const NonsensitiveSchemas = Object.assign({}, ContactsSchema, SettingsSchema);
|
const NonsensitiveSchemas = Object.assign({}, ContactsSchema, SettingsSchema);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -7,8 +7,6 @@ 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'";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
@@ -49,17 +47,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(derivationPath);
|
const rootNode: HDNode = hdnode.derivePath(UPORT_ROOT_DERIVATION_PATH);
|
||||||
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, derivationPath];
|
return [address, privateHex, publicHex, UPORT_ROOT_DERIVATION_PATH];
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -82,15 +82,10 @@ export function isHiddenDid(did) {
|
|||||||
/**
|
/**
|
||||||
always returns text, maybe UNNAMED_VISIBLE or UNKNOWN_ENTITY
|
always returns text, maybe UNNAMED_VISIBLE or UNKNOWN_ENTITY
|
||||||
**/
|
**/
|
||||||
export function didInfo(
|
export function didInfo(did, activeDid, allMyDids, contacts) {
|
||||||
did: string,
|
const myId: string | undefined = R.find(R.identity, allMyDids);
|
||||||
activeDid: string,
|
|
||||||
allMyDids: Array<string>,
|
|
||||||
contacts: Array<Contact>,
|
|
||||||
): string {
|
|
||||||
const myId: string | undefined = R.find(R.equals(did), allMyDids, did);
|
|
||||||
if (myId) {
|
if (myId) {
|
||||||
return "You" + (myId !== activeDid ? " (Alt ID)" : "");
|
return "You" + (myId.did !== activeDid ? " (Alt ID)" : "");
|
||||||
} else {
|
} else {
|
||||||
const contact: Contact | undefined = R.find((c) => c.did === did, contacts);
|
const contact: Contact | undefined = R.find((c) => c.did === did, contacts);
|
||||||
if (contact) {
|
if (contact) {
|
||||||
@@ -106,7 +101,7 @@ export function didInfo(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For result, see https://api.endorser.ch/api-docs/#/claims/post_api_v2_claim
|
* For result, see https://endorser.ch:3000/api-docs/#/claims/post_api_v2_claim
|
||||||
*
|
*
|
||||||
* @param identity
|
* @param identity
|
||||||
* @param fromDid may be null
|
* @param fromDid may be null
|
||||||
|
|||||||
10
src/main.ts
10
src/main.ts
@@ -5,21 +5,17 @@ import "./registerServiceWorker";
|
|||||||
import router from "./router";
|
import router from "./router";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import VueAxios from "vue-axios";
|
import VueAxios from "vue-axios";
|
||||||
import Notifications from "notiwind";
|
|
||||||
|
|
||||||
import "./assets/styles/tailwind.css";
|
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,
|
||||||
faChevronRight,
|
faChevronRight,
|
||||||
faCircle,
|
faCircle,
|
||||||
faCircleCheck,
|
faCircleCheck,
|
||||||
faCircleInfo,
|
|
||||||
faCircleQuestion,
|
faCircleQuestion,
|
||||||
faCircleUser,
|
faCircleUser,
|
||||||
faClock,
|
faClock,
|
||||||
@@ -49,22 +45,18 @@ import {
|
|||||||
faSquareCaretDown,
|
faSquareCaretDown,
|
||||||
faSquareCaretUp,
|
faSquareCaretUp,
|
||||||
faTrashCan,
|
faTrashCan,
|
||||||
faTriangleExclamation,
|
|
||||||
faUser,
|
faUser,
|
||||||
faUsers,
|
faUsers,
|
||||||
faXmark,
|
faXmark,
|
||||||
} from "@fortawesome/free-solid-svg-icons";
|
} from "@fortawesome/free-solid-svg-icons";
|
||||||
|
|
||||||
library.add(
|
library.add(
|
||||||
faArrowLeft,
|
|
||||||
faArrowRight,
|
|
||||||
faBurst,
|
faBurst,
|
||||||
faCalendar,
|
faCalendar,
|
||||||
faChevronLeft,
|
faChevronLeft,
|
||||||
faChevronRight,
|
faChevronRight,
|
||||||
faCircle,
|
faCircle,
|
||||||
faCircleCheck,
|
faCircleCheck,
|
||||||
faCircleInfo,
|
|
||||||
faCircleQuestion,
|
faCircleQuestion,
|
||||||
faCircleUser,
|
faCircleUser,
|
||||||
faClock,
|
faClock,
|
||||||
@@ -94,7 +86,6 @@ library.add(
|
|||||||
faSquareCaretDown,
|
faSquareCaretDown,
|
||||||
faSquareCaretUp,
|
faSquareCaretUp,
|
||||||
faTrashCan,
|
faTrashCan,
|
||||||
faTriangleExclamation,
|
|
||||||
faUser,
|
faUser,
|
||||||
faUsers,
|
faUsers,
|
||||||
faXmark,
|
faXmark,
|
||||||
@@ -107,5 +98,4 @@ createApp(App)
|
|||||||
.use(createPinia())
|
.use(createPinia())
|
||||||
.use(VueAxios, axios)
|
.use(VueAxios, axios)
|
||||||
.use(router)
|
.use(router)
|
||||||
.use(Notifications)
|
|
||||||
.mount("#app");
|
.mount("#app");
|
||||||
|
|||||||
@@ -91,14 +91,6 @@ 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",
|
||||||
@@ -190,14 +182,4 @@ const router = createRouter({
|
|||||||
routes,
|
routes,
|
||||||
});
|
});
|
||||||
|
|
||||||
const errorHandler = (error, to, from) => {
|
|
||||||
// Handle the error here
|
|
||||||
console.error(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
|
|
||||||
};
|
|
||||||
|
|
||||||
router.onError(errorHandler); // Assign the error handler to the router instance
|
|
||||||
|
|
||||||
export default router;
|
export default router;
|
||||||
|
|||||||
@@ -119,37 +119,10 @@
|
|||||||
</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-2"
|
class="block text-center text-md uppercase bg-slate-500 text-white px-1.5 py-2 rounded-md mb-8"
|
||||||
>
|
>
|
||||||
Switch Identity / No Identity
|
Switch Identity / No Identity
|
||||||
</router-link>
|
</router-link>
|
||||||
<label
|
|
||||||
for="toggleNotifications"
|
|
||||||
class="flex items-center cursor-pointer mt-4 mb-8"
|
|
||||||
@click="
|
|
||||||
this.$notify(
|
|
||||||
{
|
|
||||||
group: 'modal',
|
|
||||||
type: 'notification-permission',
|
|
||||||
},
|
|
||||||
-1,
|
|
||||||
)
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<!-- toggle -->
|
|
||||||
<div class="relative">
|
|
||||||
<!-- input -->
|
|
||||||
<input type="checkbox" name="toggleNotifications" class="sr-only" />
|
|
||||||
<!-- line -->
|
|
||||||
<div class="block bg-slate-500 w-14 h-8 rounded-full"></div>
|
|
||||||
<!-- dot -->
|
|
||||||
<div
|
|
||||||
class="dot absolute left-1 top-1 bg-slate-400 w-6 h-6 rounded-full transition"
|
|
||||||
></div>
|
|
||||||
</div>
|
|
||||||
<!-- label -->
|
|
||||||
<div class="ml-2">App Notifications</div>
|
|
||||||
</label>
|
|
||||||
|
|
||||||
<h3 class="text-sm uppercase font-semibold mb-3">Data</h3>
|
<h3 class="text-sm uppercase font-semibold mb-3">Data</h3>
|
||||||
|
|
||||||
@@ -427,19 +400,13 @@ export default class AccountViewView extends Vue {
|
|||||||
this.limitsMessage = "No identity.";
|
this.limitsMessage = "No identity.";
|
||||||
this.loadingLimits = false;
|
this.loadingLimits = false;
|
||||||
} else {
|
} else {
|
||||||
this.$notify(
|
this.alertMessage =
|
||||||
{
|
"Clear your cache and start over (after data backup).";
|
||||||
group: "alert",
|
|
||||||
type: "danger",
|
|
||||||
title: "Error Creating Account",
|
|
||||||
text: "Clear your cache and start over (after data backup).",
|
|
||||||
},
|
|
||||||
-1,
|
|
||||||
);
|
|
||||||
console.error(
|
console.error(
|
||||||
"Telling user to clear cache at page create because:",
|
"Telling user to clear cache at page create because:",
|
||||||
err,
|
err,
|
||||||
);
|
);
|
||||||
|
this.alertTitle = "Error Creating Account";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -451,19 +418,13 @@ export default class AccountViewView extends Vue {
|
|||||||
showContactGivesInline: this.showContactGives,
|
showContactGivesInline: this.showContactGives,
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.$notify(
|
this.alertMessage =
|
||||||
{
|
"Clear your cache and start over (after data backup).";
|
||||||
group: "alert",
|
|
||||||
type: "danger",
|
|
||||||
title: "Error Updating Contact Setting",
|
|
||||||
text: "Clear your cache and start over (after data backup).",
|
|
||||||
},
|
|
||||||
-1,
|
|
||||||
);
|
|
||||||
console.error(
|
console.error(
|
||||||
"Telling user to clear cache after contact setting update because:",
|
"Telling user to clear cache after contact setting update because:",
|
||||||
err,
|
err,
|
||||||
);
|
);
|
||||||
|
this.alertTitle = "Error Updating Contact Setting";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -479,25 +440,11 @@ export default class AccountViewView extends Vue {
|
|||||||
|
|
||||||
URL.revokeObjectURL(url);
|
URL.revokeObjectURL(url);
|
||||||
|
|
||||||
this.$notify(
|
this.alertTitle = "Download Started";
|
||||||
{
|
this.alertMessage = "See your downloads directory for the backup.";
|
||||||
group: "alert",
|
|
||||||
type: "toast",
|
|
||||||
title: "Download Started",
|
|
||||||
text: "See your downloads directory for the backup.",
|
|
||||||
},
|
|
||||||
5000,
|
|
||||||
);
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.$notify(
|
this.alertTitle = "Export Error";
|
||||||
{
|
this.alertMessage = "See console logs for more info.";
|
||||||
group: "alert",
|
|
||||||
type: "danger",
|
|
||||||
title: "Export Error",
|
|
||||||
text: "See console logs for more info.",
|
|
||||||
},
|
|
||||||
-1,
|
|
||||||
);
|
|
||||||
console.error("Export Error:", error);
|
console.error("Export Error:", error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,95 +1,71 @@
|
|||||||
<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>
|
||||||
<div class="flex justify-around">
|
|
||||||
<span />
|
|
||||||
<span class="justify-around">(Only 50 most recent)</span>
|
|
||||||
<span />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Results List -->
|
<!-- Results List -->
|
||||||
<table
|
<div>
|
||||||
class="table-auto w-full border-t border-slate-300 text-sm sm:text-base text-center"
|
<div class="border-b border-slate-300 flex">
|
||||||
>
|
<div class="w-1/4"></div>
|
||||||
<thead class="bg-slate-100">
|
<div class="w-1/4">from them</div>
|
||||||
<tr class="border-b border-slate-300">
|
<div class="w-1/4"></div>
|
||||||
<th></th>
|
<div class="w-1/4">to them</div>
|
||||||
<th class="px-1 py-2">From Them</th>
|
</div>
|
||||||
<th></th>
|
<div
|
||||||
<th class="px-1 py-2">To Them</th>
|
class="border-b border-slate-300 flex"
|
||||||
</tr>
|
v-for="record in giveRecords"
|
||||||
</thead>
|
:key="record.id"
|
||||||
<tbody>
|
>
|
||||||
<tr
|
<div class="w-1/4">
|
||||||
v-for="record in giveRecords"
|
{{ new Date(record.issuedAt).toLocaleString() }}
|
||||||
:key="record.id"
|
</div>
|
||||||
class="border-b border-slate-300"
|
<div class="w-1/4">
|
||||||
>
|
<span v-if="record.agentDid == contact.did">
|
||||||
<td class="p-1 text-xs sm:text-sm text-left text-slate-500">
|
<div class="font-bold">
|
||||||
{{ new Date(record.issuedAt).toLocaleString() }}
|
{{ record.amount }} {{ record.unit }}
|
||||||
</td>
|
<span v-if="record.amountConfirmed" class="tooltip">
|
||||||
<td class="p-1">
|
<fa icon="circle-check" class="text-green-600 fa-fw ml-1" />
|
||||||
<span v-if="record.agentDid == contact.did">
|
<span class="tooltiptext">Confirmed</span>
|
||||||
<div class="font-bold">
|
</span>
|
||||||
{{ record.amount }} {{ record.unit }}
|
<button v-else class="tooltip" @click="confirm(record)">
|
||||||
<span v-if="record.amountConfirmed" title="Confirmed">
|
<fa icon="circle" class="text-blue-600 fa-fw ml-1" />
|
||||||
<fa icon="circle-check" class="text-green-600 fa-fw" />
|
<span class="tooltiptext">Unconfirmed</span>
|
||||||
</span>
|
</button>
|
||||||
<button v-else @click="confirm(record)" title="Unconfirmed">
|
</div>
|
||||||
<fa icon="circle" class="text-blue-600 fa-fw" />
|
<br />
|
||||||
</button>
|
{{ record.description }}
|
||||||
</div>
|
</span>
|
||||||
<div class="italic text-xs sm:text-sm text-slate-500">
|
</div>
|
||||||
{{ record.description }}
|
<div class="w-1/8">
|
||||||
</div>
|
<span v-if="record.agentDid == contact.did">
|
||||||
</span>
|
<fa icon="long-arrow-alt-left" class="text-slate-900 fa-fw ml-1" />
|
||||||
</td>
|
</span>
|
||||||
<td class="p-1">
|
<span v-else>
|
||||||
<span v-if="record.agentDid == contact.did">
|
|
||||||
<fa icon="arrow-left" class="text-slate-400 fa-fw" />
|
<fa icon="long-arrow-alt-right" class="text-slate-900 fa-fw ml-1" />
|
||||||
</span>
|
</span>
|
||||||
<span v-else>
|
</div>
|
||||||
<fa icon="arrow-right" class="text-slate-400 fa-fw" />
|
<div class="w-1/4">
|
||||||
</span>
|
<span v-if="record.agentDid != contact.did">
|
||||||
</td>
|
<div class="font-bold">
|
||||||
<td class="p-1">
|
{{ record.amount }} {{ record.unit }}
|
||||||
<span v-if="record.agentDid != contact.did">
|
<span v-if="record.amountConfirmed" class="tooltip">
|
||||||
<div class="font-bold">
|
<fa icon="circle-check" class="text-green-600 fa-fw ml-1" />
|
||||||
{{ record.amount }} {{ record.unit }}
|
<span class="tooltiptext">Confirmed</span>
|
||||||
<span v-if="record.amountConfirmed" title="Confirmed">
|
</span>
|
||||||
<fa icon="circle-check" class="text-green-600 fa-fw" />
|
<button v-else class="tooltip" @click="cannotConfirmMessage()">
|
||||||
</span>
|
<fa icon="circle" class="text-slate-600 fa-fw ml-1" />
|
||||||
<button
|
<span class="tooltiptext">Unconfirmed</span>
|
||||||
v-else
|
</button>
|
||||||
@click="cannotConfirmMessage()"
|
</div>
|
||||||
title="Unconfirmed"
|
<br />
|
||||||
>
|
{{ record.description }}
|
||||||
<fa icon="circle" class="text-slate-600 fa-fw" />
|
</span>
|
||||||
</button>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="italic text-xs sm:text-sm text-slate-500">
|
</div>
|
||||||
{{ record.description }}
|
|
||||||
</div>
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<AlertMessage
|
<AlertMessage
|
||||||
:alertTitle="alertTitle"
|
:alertTitle="alertTitle"
|
||||||
:alertMessage="alertMessage"
|
:alertMessage="alertMessage"
|
||||||
@@ -170,17 +146,10 @@ export default class ContactsView extends Vue {
|
|||||||
this.loadGives(this.activeDid, this.contact);
|
this.loadGives(this.activeDid, this.contact);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.$notify(
|
this.alertTitle = "Error";
|
||||||
{
|
this.alertMessage =
|
||||||
group: "alert",
|
err.userMessage ||
|
||||||
type: "danger",
|
"There was an error retrieving the latest sweet, sweet action.";
|
||||||
title: "Error",
|
|
||||||
text:
|
|
||||||
err.userMessage ||
|
|
||||||
"There was an error retrieving the latest sweet, sweet action.",
|
|
||||||
},
|
|
||||||
-1,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -194,7 +163,7 @@ export default class ContactsView extends Vue {
|
|||||||
encodeURIComponent(identity.did) +
|
encodeURIComponent(identity.did) +
|
||||||
"&recipientDid=" +
|
"&recipientDid=" +
|
||||||
encodeURIComponent(contact.did);
|
encodeURIComponent(contact.did);
|
||||||
const headers = await this.getHeaders(identity);
|
const headers = this.getHeaders(identity);
|
||||||
const resp = await this.axios.get(url, { headers });
|
const resp = await this.axios.get(url, { headers });
|
||||||
if (resp.status === 200) {
|
if (resp.status === 200) {
|
||||||
result = resp.data.data;
|
result = resp.data.data;
|
||||||
@@ -204,15 +173,9 @@ export default class ContactsView extends Vue {
|
|||||||
resp.status,
|
resp.status,
|
||||||
resp.data,
|
resp.data,
|
||||||
);
|
);
|
||||||
this.$notify(
|
this.alertTitle = "Error With Server";
|
||||||
{
|
this.alertMessage =
|
||||||
group: "alert",
|
"Got an error retrieving your given time from the server.";
|
||||||
type: "danger",
|
|
||||||
title: "Error With Server",
|
|
||||||
text: "Got an error retrieving your given time from the server.",
|
|
||||||
},
|
|
||||||
-1,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const url2 =
|
const url2 =
|
||||||
@@ -231,15 +194,9 @@ export default class ContactsView extends Vue {
|
|||||||
resp2.status,
|
resp2.status,
|
||||||
resp2.data,
|
resp2.data,
|
||||||
);
|
);
|
||||||
this.$notify(
|
this.alertTitle = "Error With Server";
|
||||||
{
|
this.alertMessage =
|
||||||
group: "alert",
|
"Got an error retrieving your given time from the server.";
|
||||||
type: "danger",
|
|
||||||
title: "Error With Server",
|
|
||||||
text: "Got an error retrieving your given time from the server.",
|
|
||||||
},
|
|
||||||
-1,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const sortedResult: Array<GiveServerRecord> = R.sort(
|
const sortedResult: Array<GiveServerRecord> = R.sort(
|
||||||
@@ -249,15 +206,8 @@ export default class ContactsView extends Vue {
|
|||||||
);
|
);
|
||||||
this.giveRecords = sortedResult;
|
this.giveRecords = sortedResult;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.$notify(
|
this.alertTitle = "Error With Server";
|
||||||
{
|
this.alertMessage = error as string;
|
||||||
group: "alert",
|
|
||||||
type: "danger",
|
|
||||||
title: "Error With Server",
|
|
||||||
text: error as string,
|
|
||||||
},
|
|
||||||
-1,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -326,29 +276,15 @@ export default class ContactsView extends Vue {
|
|||||||
userMessage = error as string;
|
userMessage = error as string;
|
||||||
}
|
}
|
||||||
// Now set that error for the user to see.
|
// Now set that error for the user to see.
|
||||||
this.$notify(
|
this.alertTitle = "Error With Server";
|
||||||
{
|
this.alertMessage = userMessage;
|
||||||
group: "alert",
|
|
||||||
type: "danger",
|
|
||||||
title: "Error With Server",
|
|
||||||
text: userMessage,
|
|
||||||
},
|
|
||||||
-1,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cannotConfirmMessage() {
|
cannotConfirmMessage() {
|
||||||
this.$notify(
|
this.alertTitle = "Not Allowed";
|
||||||
{
|
this.alertMessage = "Only the recipient can confirm final receipt.";
|
||||||
group: "alert",
|
|
||||||
type: "danger",
|
|
||||||
title: "Not Allowed",
|
|
||||||
text: "Only the recipient can confirm final receipt.",
|
|
||||||
},
|
|
||||||
-1,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -24,12 +24,8 @@
|
|||||||
<ul class="border-t border-slate-300">
|
<ul class="border-t border-slate-300">
|
||||||
<li class="border-b border-slate-300 py-3">
|
<li class="border-b border-slate-300 py-3">
|
||||||
<h2 class="text-base flex gap-4 items-center">
|
<h2 class="text-base flex gap-4 items-center">
|
||||||
<span class="grow italic text-slate-500"
|
<span class="grow italic"
|
||||||
><EntityIcon
|
><fa icon="question-circle" class="fa-fw fa-xl text-slate-400"></fa>
|
||||||
entityId="Anonymous"
|
|
||||||
:iconSize="32"
|
|
||||||
class="opacity-50 inline-block align-middle border border-dashed border-slate-400 bg-slate-200 rounded-md mr-1"
|
|
||||||
></EntityIcon>
|
|
||||||
Anonymous
|
Anonymous
|
||||||
</span>
|
</span>
|
||||||
<span class="text-right">
|
<span class="text-right">
|
||||||
@@ -50,11 +46,7 @@
|
|||||||
>
|
>
|
||||||
<h2 class="text-base flex gap-4 items-center">
|
<h2 class="text-base flex gap-4 items-center">
|
||||||
<span class="grow font-semibold"
|
<span class="grow font-semibold"
|
||||||
><EntityIcon
|
><fa icon="user" class="fa-fw fa-xl text-slate-400"></fa>
|
||||||
:entityId="contact.did"
|
|
||||||
:iconSize="32"
|
|
||||||
class="inline-block align-middle border border-slate-300 rounded-md mr-1"
|
|
||||||
></EntityIcon>
|
|
||||||
{{ contact.name || "(no name)" }}
|
{{ contact.name || "(no name)" }}
|
||||||
</span>
|
</span>
|
||||||
<span class="text-right">
|
<span class="text-right">
|
||||||
@@ -95,10 +87,9 @@ import { Account } from "@/db/tables/accounts";
|
|||||||
import { Contact } from "@/db/tables/contacts";
|
import { Contact } from "@/db/tables/contacts";
|
||||||
import AlertMessage from "@/components/AlertMessage";
|
import AlertMessage from "@/components/AlertMessage";
|
||||||
import QuickNav from "@/components/QuickNav";
|
import QuickNav from "@/components/QuickNav";
|
||||||
import EntityIcon from "@/components/EntityIcon";
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
components: { GiftedDialog, AlertMessage, QuickNav, EntityIcon },
|
components: { GiftedDialog, AlertMessage, QuickNav },
|
||||||
})
|
})
|
||||||
export default class HomeView extends Vue {
|
export default class HomeView extends Vue {
|
||||||
activeDid = "";
|
activeDid = "";
|
||||||
@@ -154,17 +145,10 @@ export default class HomeView extends Vue {
|
|||||||
this.feedLastViewedId = settings?.lastViewedClaimId;
|
this.feedLastViewedId = settings?.lastViewedClaimId;
|
||||||
this.updateAllFeed();
|
this.updateAllFeed();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.$notify(
|
this.alertTitle = "Error";
|
||||||
{
|
this.alertMessage =
|
||||||
group: "alert",
|
err.userMessage ||
|
||||||
type: "danger",
|
"There was an error retrieving the latest sweet, sweet action.";
|
||||||
title: "Error",
|
|
||||||
text:
|
|
||||||
err.userMessage ||
|
|
||||||
"There was an error retrieving the latest sweet, sweet action.",
|
|
||||||
},
|
|
||||||
-1,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -213,27 +197,17 @@ export default class HomeView extends Vue {
|
|||||||
*/
|
*/
|
||||||
public async recordGive(giverDid, description, hours) {
|
public async recordGive(giverDid, description, hours) {
|
||||||
if (!this.activeDid) {
|
if (!this.activeDid) {
|
||||||
this.$notify(
|
this.setAlert(
|
||||||
{
|
"Error",
|
||||||
group: "alert",
|
"You must select an identity before you can record a give.",
|
||||||
type: "danger",
|
|
||||||
title: "Error",
|
|
||||||
text: "You must select an identity before you can record a give.",
|
|
||||||
},
|
|
||||||
-1,
|
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!description && !hours) {
|
if (!description && !hours) {
|
||||||
this.$notify(
|
this.setAlert(
|
||||||
{
|
"Error",
|
||||||
group: "alert",
|
"You must enter a description or some number of hours.",
|
||||||
type: "danger",
|
|
||||||
title: "Error",
|
|
||||||
text: "You must enter a description or some number of hours.",
|
|
||||||
},
|
|
||||||
-1,
|
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -253,38 +227,18 @@ export default class HomeView extends Vue {
|
|||||||
if (isGiveCreationError(result)) {
|
if (isGiveCreationError(result)) {
|
||||||
const errorMessage = getGiveCreationErrorMessage(result);
|
const errorMessage = getGiveCreationErrorMessage(result);
|
||||||
console.log("Error with give result:", result);
|
console.log("Error with give result:", result);
|
||||||
this.$notify(
|
this.setAlert(
|
||||||
{
|
"Error",
|
||||||
group: "alert",
|
errorMessage || "There was an error recording the give.",
|
||||||
type: "danger",
|
|
||||||
title: "Error",
|
|
||||||
text: errorMessage || "There was an error recording the give.",
|
|
||||||
},
|
|
||||||
-1,
|
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
this.$notify(
|
this.setAlert("Success", "That gift was recorded.");
|
||||||
{
|
|
||||||
group: "alert",
|
|
||||||
type: "success",
|
|
||||||
title: "Success",
|
|
||||||
text: "That gift was recorded.",
|
|
||||||
},
|
|
||||||
-1,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log("Error with give caught:", error);
|
console.log("Error with give caught:", error);
|
||||||
this.$notify(
|
this.setAlert(
|
||||||
{
|
"Error",
|
||||||
group: "alert",
|
getGiveErrorMessage(error) || "There was an error recording the give.",
|
||||||
type: "danger",
|
|
||||||
title: "Error",
|
|
||||||
text:
|
|
||||||
getGiveErrorMessage(error) ||
|
|
||||||
"There was an error recording the give.",
|
|
||||||
},
|
|
||||||
-1,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -85,15 +85,7 @@ export default class ContactQRScanShow extends Vue {
|
|||||||
const accounts = await accountsDB.accounts.toArray();
|
const accounts = await accountsDB.accounts.toArray();
|
||||||
const account = R.find((acc) => acc.did === this.activeDid, accounts);
|
const account = R.find((acc) => acc.did === this.activeDid, accounts);
|
||||||
if (!account) {
|
if (!account) {
|
||||||
this.$notify(
|
this.alertMessage = "You have no identity yet.";
|
||||||
{
|
|
||||||
group: "alert",
|
|
||||||
type: "warning",
|
|
||||||
title: "",
|
|
||||||
text: "You have no identity yet.",
|
|
||||||
},
|
|
||||||
-1,
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
const identity = await this.getIdentity(this.activeDid);
|
const identity = await this.getIdentity(this.activeDid);
|
||||||
const publicKeyHex = identity.keys[0].publicKeyHex;
|
const publicKeyHex = identity.keys[0].publicKeyHex;
|
||||||
|
|||||||
@@ -66,27 +66,18 @@
|
|||||||
: "Unconfirmed"
|
: "Unconfirmed"
|
||||||
}}
|
}}
|
||||||
</button>
|
</button>
|
||||||
<br />
|
|
||||||
(Only hours shown)
|
|
||||||
<br />
|
|
||||||
(Only recent shown)
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Results List -->
|
<!-- Results List -->
|
||||||
<ul v-if="contacts.length > 0" class="border-t border-slate-300">
|
<ul v-if="contacts.length > 0">
|
||||||
<li
|
<li
|
||||||
class="border-b border-slate-300 pt-2.5 pb-4"
|
class="border-b border-slate-300"
|
||||||
v-for="contact in contacts"
|
v-for="contact in contacts"
|
||||||
:key="contact.did"
|
:key="contact.did"
|
||||||
>
|
>
|
||||||
<div class="grow overflow-hidden">
|
<div class="grow overflow-hidden">
|
||||||
<h2 class="text-base font-semibold">
|
<h2 class="text-base font-semibold">
|
||||||
<EntityIcon
|
|
||||||
:entityId="contact.did"
|
|
||||||
:iconSize="24"
|
|
||||||
class="inline-block align-text-bottom border border-slate-300 rounded"
|
|
||||||
></EntityIcon>
|
|
||||||
{{ contact.name || "(no name)" }}
|
{{ contact.name || "(no name)" }}
|
||||||
</h2>
|
</h2>
|
||||||
<div class="text-sm truncate">{{ contact.did }}</div>
|
<div class="text-sm truncate">{{ contact.did }}</div>
|
||||||
@@ -94,85 +85,70 @@
|
|||||||
Public Key (base 64): {{ contact.publicKeyBase64 }}
|
Public Key (base 64): {{ contact.publicKeyBase64 }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="ContactActions" class="flex gap-1.5 mt-2">
|
<button
|
||||||
<button
|
v-if="contact.seesMe"
|
||||||
v-if="contact.seesMe"
|
class="tooltip"
|
||||||
class="text-sm uppercase bg-slate-500 text-white px-2 py-1.5 rounded-md"
|
@click="setVisibility(contact, false)"
|
||||||
@click="setVisibility(contact, false)"
|
>
|
||||||
title="They can see you"
|
<fa icon="eye" class="text-slate-900 fa-fw ml-1" />
|
||||||
>
|
<span class="tooltiptext">They can see you</span>
|
||||||
<fa icon="eye" class="fa-fw" />
|
</button>
|
||||||
</button>
|
<button v-else class="tooltip" @click="setVisibility(contact, true)">
|
||||||
<button
|
<span class="tooltiptext">They cannot see you</span>
|
||||||
v-else
|
<fa icon="eye-slash" class="text-slate-900 fa-fw ml-1" />
|
||||||
class="text-sm uppercase bg-slate-500 text-white px-2 py-1.5 rounded-md"
|
</button>
|
||||||
@click="setVisibility(contact, true)"
|
|
||||||
title="They cannot see you"
|
|
||||||
>
|
|
||||||
<fa icon="eye-slash" class="fa-fw" />
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button
|
<button class="tooltip" @click="checkVisibility(contact)">
|
||||||
class="text-sm uppercase bg-slate-500 text-white px-2 py-1.5 rounded-md"
|
<span class="tooltiptext">Check Visibility</span>
|
||||||
@click="checkVisibility(contact)"
|
<fa icon="rotate" class="text-slate-900 fa-fw ml-1" />
|
||||||
title="Check Visibility"
|
</button>
|
||||||
>
|
|
||||||
<fa icon="rotate" class="fa-fw" />
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button
|
<button v-if="contact.registered" class="tooltip">
|
||||||
v-if="contact.registered"
|
<span class="tooltiptext">Registered</span>
|
||||||
class="text-sm uppercase bg-slate-500 text-white px-2 py-1.5 rounded-md"
|
<fa icon="person-circle-check" class="text-slate-900 fa-fw ml-1" />
|
||||||
title="Registered"
|
</button>
|
||||||
>
|
<button v-else @click="register(contact)" class="tooltip">
|
||||||
<fa icon="person-circle-check" class="fa-fw" />
|
<span class="tooltiptext">Registration Unknown</span>
|
||||||
</button>
|
<fa
|
||||||
<button
|
icon="person-circle-question"
|
||||||
v-else
|
class="text-slate-900 fa-fw ml-1"
|
||||||
@click="register(contact)"
|
/>
|
||||||
class="text-sm uppercase bg-slate-500 text-white px-2 py-1.5 rounded-md"
|
</button>
|
||||||
title="Registration unknown"
|
|
||||||
>
|
|
||||||
<fa icon="person-circle-question" class="fa-fw" />
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button
|
<button @click="deleteContact(contact)" class="px-9 tooltip">
|
||||||
@click="deleteContact(contact)"
|
<span class="tooltiptext">Delete!</span>
|
||||||
class="text-sm uppercase bg-red-600 text-white px-2 py-1.5 rounded-md"
|
<fa icon="trash-can" class="text-red-600 fa-fw ml-1" />
|
||||||
title="Delete"
|
</button>
|
||||||
>
|
|
||||||
<fa icon="trash-can" class="fa-fw" />
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<div
|
<div v-if="showGiveNumbers" class="float-right">
|
||||||
v-if="showGiveNumbers && contact.did != activeDid"
|
<div class="float-right">
|
||||||
class="ml-auto flex gap-1.5"
|
<div class="tooltip">
|
||||||
>
|
to:
|
||||||
<button
|
|
||||||
class="text-sm bg-blue-600 text-white px-2 py-1.5 rounded-l-md"
|
|
||||||
@click="onClickAddGive(activeDid, contact.did)"
|
|
||||||
title="givenByMeDescriptions[contact.did]"
|
|
||||||
>
|
|
||||||
To:
|
|
||||||
{{
|
{{
|
||||||
/* eslint-disable prettier/prettier */
|
/* eslint-disable prettier/prettier */
|
||||||
this.showGiveTotals
|
this.showGiveTotals
|
||||||
? ((givenByMeConfirmed[contact.did] || 0)
|
? ((givenByMeConfirmed[contact.did] || 0)
|
||||||
+ (givenByMeUnconfirmed[contact.did] || 0))
|
+ (givenByMeUnconfirmed[contact.did] || 0))
|
||||||
: this.showGiveConfirmed
|
: this.showGiveConfirmed
|
||||||
? (givenByMeConfirmed[contact.did] || 0)
|
? (givenByMeConfirmed[contact.did] || 0)
|
||||||
: (givenByMeUnconfirmed[contact.did] || 0)
|
: (givenByMeUnconfirmed[contact.did] || 0)
|
||||||
/* eslint-enable prettier/prettier */
|
/* eslint-enable prettier/prettier */
|
||||||
}}
|
}}
|
||||||
<fa icon="plus" />
|
<span
|
||||||
</button>
|
v-if="givenByMeDescriptions[contact.did]"
|
||||||
|
class="tooltiptext-left"
|
||||||
<button
|
>
|
||||||
class="text-sm bg-blue-600 text-white px-2 py-1.5 rounded-r-md -ml-1.5 border-l border-blue-400"
|
{{ givenByMeDescriptions[contact.did] }}
|
||||||
@click="onClickAddGive(contact.did, activeDid)"
|
</span>
|
||||||
title="givenToMeDescriptions[contact.did]"
|
<button
|
||||||
>
|
class="text-md uppercase bg-slate-500 text-white px-1.5 py-2 rounded-md mb-6"
|
||||||
From:
|
@click="onClickAddGive(activeDid, contact.did)"
|
||||||
|
>
|
||||||
|
+
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="tooltip px-2">
|
||||||
|
from:
|
||||||
{{
|
{{
|
||||||
/* eslint-disable prettier/prettier */
|
/* eslint-disable prettier/prettier */
|
||||||
this.showGiveTotals
|
this.showGiveTotals
|
||||||
@@ -183,18 +159,28 @@
|
|||||||
: (givenToMeUnconfirmed[contact.did] || 0)
|
: (givenToMeUnconfirmed[contact.did] || 0)
|
||||||
/* eslint-enable prettier/prettier */
|
/* eslint-enable prettier/prettier */
|
||||||
}}
|
}}
|
||||||
<fa icon="plus" />
|
<span
|
||||||
</button>
|
v-if="givenToMeDescriptions[contact.did]"
|
||||||
|
class="tooltiptext-left"
|
||||||
|
>
|
||||||
|
{{ givenToMeDescriptions[contact.did] }}
|
||||||
|
</span>
|
||||||
|
<button
|
||||||
|
class="text-md uppercase bg-slate-500 text-white px-1.5 py-2 rounded-md mb-6"
|
||||||
|
@click="onClickAddGive(contact.did, activeDid)"
|
||||||
|
>
|
||||||
|
+
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
<router-link
|
<router-link
|
||||||
:to="{
|
:to="{
|
||||||
name: 'contact-amounts',
|
name: 'contact-amounts',
|
||||||
query: { contactDid: contact.did },
|
query: { contactDid: contact.did },
|
||||||
}"
|
}"
|
||||||
class="text-sm uppercase bg-slate-500 text-white px-2 py-1.5 rounded-md"
|
class="tooltip"
|
||||||
title="See all given activity"
|
|
||||||
>
|
>
|
||||||
<fa icon="file-lines" class="fa-fw" />
|
<fa icon="file-lines" class="text-slate-600 fa-fw ml-1" />
|
||||||
|
<span class="tooltiptext-left">See All Given Activity</span>
|
||||||
</router-link>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -226,13 +212,12 @@ import {
|
|||||||
import { Component, Vue } from "vue-facing-decorator";
|
import { Component, Vue } from "vue-facing-decorator";
|
||||||
import AlertMessage from "@/components/AlertMessage";
|
import AlertMessage from "@/components/AlertMessage";
|
||||||
import QuickNav from "@/components/QuickNav";
|
import QuickNav from "@/components/QuickNav";
|
||||||
import EntityIcon from "@/components/EntityIcon";
|
|
||||||
|
|
||||||
// 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;
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
components: { AlertMessage, QuickNav, EntityIcon },
|
components: { AlertMessage, QuickNav },
|
||||||
})
|
})
|
||||||
export default class ContactsView extends Vue {
|
export default class ContactsView extends Vue {
|
||||||
activeDid = "";
|
activeDid = "";
|
||||||
@@ -307,27 +292,20 @@ export default class ContactsView extends Vue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async loadGives() {
|
async loadGives() {
|
||||||
const handleResponse = (
|
const handleResponse = (resp, descriptions, confirmed, unconfirmed) => {
|
||||||
resp,
|
|
||||||
descriptions,
|
|
||||||
confirmed,
|
|
||||||
unconfirmed,
|
|
||||||
useRecipient,
|
|
||||||
) => {
|
|
||||||
if (resp.status === 200) {
|
if (resp.status === 200) {
|
||||||
const allData = resp.data.data;
|
const allData = resp.data.data;
|
||||||
for (const give of allData) {
|
for (const give of allData) {
|
||||||
const otherDid = useRecipient ? give.recipientDid : give.agentDid;
|
|
||||||
if (give.unit === "HUR") {
|
if (give.unit === "HUR") {
|
||||||
if (give.amountConfirmed) {
|
if (give.amountConfirmed) {
|
||||||
const prevAmount = confirmed[otherDid] || 0;
|
const prevAmount = confirmed[give.agentDid] || 0;
|
||||||
confirmed[otherDid] = prevAmount + give.amount;
|
confirmed[give.agentDid] = prevAmount + give.amount;
|
||||||
} else {
|
} else {
|
||||||
const prevAmount = unconfirmed[otherDid] || 0;
|
const prevAmount = unconfirmed[give.agentDid] || 0;
|
||||||
unconfirmed[otherDid] = prevAmount + give.amount;
|
unconfirmed[give.agentDid] = prevAmount + give.amount;
|
||||||
}
|
}
|
||||||
if (!descriptions[otherDid] && give.description) {
|
if (!descriptions[give.agentDid] && give.description) {
|
||||||
descriptions[otherDid] = give.description;
|
descriptions[give.agentDid] = give.description;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -337,32 +315,27 @@ export default class ContactsView extends Vue {
|
|||||||
resp.status,
|
resp.status,
|
||||||
resp.data,
|
resp.data,
|
||||||
);
|
);
|
||||||
this.$notify(
|
this.alertTitle = "Error With Server";
|
||||||
{
|
this.alertMessage =
|
||||||
group: "alert",
|
"Got an error retrieving your " +
|
||||||
type: "danger",
|
resp.config.url.includes("recipientDid")
|
||||||
title: "Error With Server",
|
? "received"
|
||||||
text:
|
: "given" + " time from the server.";
|
||||||
"Got an error retrieving your " +
|
|
||||||
resp.config.url.includes("recipientDid")
|
|
||||||
? "received"
|
|
||||||
: "given" + " time from the server.",
|
|
||||||
},
|
|
||||||
-1,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { headers } = await this.getHeadersAndIdentity(this.activeDid);
|
const { headers, identity } = await this.getHeadersAndIdentity(
|
||||||
|
this.activeDid,
|
||||||
|
);
|
||||||
const givenByUrl =
|
const givenByUrl =
|
||||||
this.apiServer +
|
this.apiServer +
|
||||||
"/api/v2/report/gives?agentDid=" +
|
"/api/v2/report/gives?agentDid=" +
|
||||||
encodeURIComponent(this.activeDid);
|
encodeURIComponent(identity.did);
|
||||||
const givenToUrl =
|
const givenToUrl =
|
||||||
this.apiServer +
|
this.apiServer +
|
||||||
"/api/v2/report/gives?recipientDid=" +
|
"/api/v2/report/gives?recipientDid=" +
|
||||||
encodeURIComponent(this.activeDid);
|
encodeURIComponent(identity.did);
|
||||||
|
|
||||||
const [givenByMeResp, givenToMeResp] = await Promise.all([
|
const [givenByMeResp, givenToMeResp] = await Promise.all([
|
||||||
this.axios.get(givenByUrl, { headers }),
|
this.axios.get(givenByUrl, { headers }),
|
||||||
@@ -377,7 +350,6 @@ export default class ContactsView extends Vue {
|
|||||||
givenByMeDescriptions,
|
givenByMeDescriptions,
|
||||||
givenByMeConfirmed,
|
givenByMeConfirmed,
|
||||||
givenByMeUnconfirmed,
|
givenByMeUnconfirmed,
|
||||||
true,
|
|
||||||
);
|
);
|
||||||
this.givenByMeDescriptions = givenByMeDescriptions;
|
this.givenByMeDescriptions = givenByMeDescriptions;
|
||||||
this.givenByMeConfirmed = givenByMeConfirmed;
|
this.givenByMeConfirmed = givenByMeConfirmed;
|
||||||
@@ -391,21 +363,13 @@ export default class ContactsView extends Vue {
|
|||||||
givenToMeDescriptions,
|
givenToMeDescriptions,
|
||||||
givenToMeConfirmed,
|
givenToMeConfirmed,
|
||||||
givenToMeUnconfirmed,
|
givenToMeUnconfirmed,
|
||||||
false,
|
|
||||||
);
|
);
|
||||||
this.givenToMeDescriptions = givenToMeDescriptions;
|
this.givenToMeDescriptions = givenToMeDescriptions;
|
||||||
this.givenToMeConfirmed = givenToMeConfirmed;
|
this.givenToMeConfirmed = givenToMeConfirmed;
|
||||||
this.givenToMeUnconfirmed = givenToMeUnconfirmed;
|
this.givenToMeUnconfirmed = givenToMeUnconfirmed;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.$notify(
|
this.alertTitle = "Error With Server";
|
||||||
{
|
this.alertMessage = error as string;
|
||||||
group: "alert",
|
|
||||||
type: "danger",
|
|
||||||
title: "Error With Server",
|
|
||||||
text: error as string,
|
|
||||||
},
|
|
||||||
-1,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -498,32 +462,18 @@ export default class ContactsView extends Vue {
|
|||||||
try {
|
try {
|
||||||
const resp = await this.axios.post(url, payload, { headers });
|
const resp = await this.axios.post(url, payload, { headers });
|
||||||
if (resp.data?.success?.embeddedRecordError) {
|
if (resp.data?.success?.embeddedRecordError) {
|
||||||
|
this.alertTitle = "Registration Still Unknown";
|
||||||
let message = "There was some problem with the registration.";
|
let message = "There was some problem with the registration.";
|
||||||
if (typeof resp.data.success.embeddedRecordError == "string") {
|
if (typeof resp.data.success.embeddedRecordError == "string") {
|
||||||
message += " " + resp.data.success.embeddedRecordError;
|
message += " " + resp.data.success.embeddedRecordError;
|
||||||
}
|
}
|
||||||
this.$notify(
|
this.alertMessage = message;
|
||||||
{
|
|
||||||
group: "alert",
|
|
||||||
type: "danger",
|
|
||||||
title: "Registration Still Unknown",
|
|
||||||
text: message,
|
|
||||||
},
|
|
||||||
-1,
|
|
||||||
);
|
|
||||||
} else if (resp.data?.success?.handleId) {
|
} else if (resp.data?.success?.handleId) {
|
||||||
contact.registered = true;
|
contact.registered = true;
|
||||||
db.contacts.update(contact.did, { registered: true });
|
db.contacts.update(contact.did, { registered: true });
|
||||||
|
|
||||||
this.$notify(
|
this.alertTitle = "Registration Success";
|
||||||
{
|
this.alertMessage = contact.name + " has been registered.";
|
||||||
group: "alert",
|
|
||||||
type: "info",
|
|
||||||
title: "Registration Success",
|
|
||||||
text: contact.name + " has been registered.",
|
|
||||||
},
|
|
||||||
-1,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
let userMessage = "There was an error. See logs for more info.";
|
let userMessage = "There was an error. See logs for more info.";
|
||||||
@@ -538,15 +488,8 @@ export default class ContactsView extends Vue {
|
|||||||
userMessage = error as string;
|
userMessage = error as string;
|
||||||
}
|
}
|
||||||
// Now set that error for the user to see.
|
// Now set that error for the user to see.
|
||||||
this.$notify(
|
this.alertTitle = "Error With Server";
|
||||||
{
|
this.alertMessage = userMessage;
|
||||||
group: "alert",
|
|
||||||
type: "danger",
|
|
||||||
title: "Error With Server",
|
|
||||||
text: userMessage,
|
|
||||||
},
|
|
||||||
-1,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -567,39 +510,17 @@ export default class ContactsView extends Vue {
|
|||||||
contact.seesMe = visibility;
|
contact.seesMe = visibility;
|
||||||
db.contacts.update(contact.did, { seesMe: visibility });
|
db.contacts.update(contact.did, { seesMe: visibility });
|
||||||
} else {
|
} else {
|
||||||
|
this.alertTitle = "Error With Server";
|
||||||
console.error("Bad response setting visibility: ", resp.data);
|
console.error("Bad response setting visibility: ", resp.data);
|
||||||
if (resp.data.error?.message) {
|
if (resp.data.error?.message) {
|
||||||
this.$notify(
|
this.alertMessage = resp.data.error?.message;
|
||||||
{
|
|
||||||
group: "alert",
|
|
||||||
type: "danger",
|
|
||||||
title: "Error With Server",
|
|
||||||
text: resp.data.error?.message,
|
|
||||||
},
|
|
||||||
-1,
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
this.$notify(
|
this.alertMessage = "Bad server response of " + resp.status;
|
||||||
{
|
|
||||||
group: "alert",
|
|
||||||
type: "danger",
|
|
||||||
title: "Error With Server",
|
|
||||||
text: "Bad server response of " + resp.status,
|
|
||||||
},
|
|
||||||
-1,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.$notify(
|
this.alertTitle = "Error With Server";
|
||||||
{
|
this.alertMessage = err as string;
|
||||||
group: "alert",
|
|
||||||
type: "danger",
|
|
||||||
title: "Error With Server",
|
|
||||||
text: err as string,
|
|
||||||
},
|
|
||||||
-1,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -616,52 +537,23 @@ export default class ContactsView extends Vue {
|
|||||||
contact.seesMe = visibility;
|
contact.seesMe = visibility;
|
||||||
db.contacts.update(contact.did, { seesMe: visibility });
|
db.contacts.update(contact.did, { seesMe: visibility });
|
||||||
|
|
||||||
this.$notify(
|
this.alertTitle = "Refreshed";
|
||||||
{
|
this.alertMessage =
|
||||||
group: "alert",
|
this.nameForContact(contact, true) +
|
||||||
type: "toast",
|
" can " +
|
||||||
title: "Refreshed",
|
(visibility ? "" : "not ") +
|
||||||
text:
|
"see your activity.";
|
||||||
this.nameForContact(contact, true) +
|
|
||||||
" can " +
|
|
||||||
(visibility ? "" : "not ") +
|
|
||||||
"see your activity.",
|
|
||||||
},
|
|
||||||
5000,
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
|
this.alertTitle = "Error With Server";
|
||||||
if (resp.data.error?.message) {
|
if (resp.data.error?.message) {
|
||||||
this.$notify(
|
this.alertMessage = resp.data.error?.message;
|
||||||
{
|
|
||||||
group: "alert",
|
|
||||||
type: "danger",
|
|
||||||
title: "Error With Server",
|
|
||||||
text: resp.data.error?.message,
|
|
||||||
},
|
|
||||||
-1,
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
this.$notify(
|
this.alertMessage = "Bad server response of " + resp.status;
|
||||||
{
|
|
||||||
group: "alert",
|
|
||||||
type: "danger",
|
|
||||||
title: "Error With Server",
|
|
||||||
text: "Bad server response of " + resp.status,
|
|
||||||
},
|
|
||||||
-1,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.$notify(
|
this.alertTitle = "Error With Server";
|
||||||
{
|
this.alertMessage = err as string;
|
||||||
group: "alert",
|
|
||||||
type: "danger",
|
|
||||||
title: "Error With Server",
|
|
||||||
text: err as string,
|
|
||||||
},
|
|
||||||
-1,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -700,35 +592,15 @@ export default class ContactsView extends Vue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!this.isNumeric(this.hourInput)) {
|
if (!this.isNumeric(this.hourInput)) {
|
||||||
this.$notify(
|
this.alertTitle = "Input Error";
|
||||||
{
|
this.alertMessage =
|
||||||
group: "alert",
|
"This is not a valid number of hours: " + this.hourInput;
|
||||||
type: "danger",
|
|
||||||
title: "Input Error",
|
|
||||||
text: "This is not a valid number of hours: " + this.hourInput,
|
|
||||||
},
|
|
||||||
-1,
|
|
||||||
);
|
|
||||||
} else if (!parseFloat(this.hourInput)) {
|
} else if (!parseFloat(this.hourInput)) {
|
||||||
this.$notify(
|
this.alertTitle = "Input Error";
|
||||||
{
|
this.alertMessage = "Giving 0 hours does nothing.";
|
||||||
group: "alert",
|
|
||||||
type: "danger",
|
|
||||||
title: "Input Error",
|
|
||||||
text: "Giving 0 hours does nothing.",
|
|
||||||
},
|
|
||||||
-1,
|
|
||||||
);
|
|
||||||
} else if (!identity) {
|
} else if (!identity) {
|
||||||
this.$notify(
|
this.alertTitle = "Status Error";
|
||||||
{
|
this.alertMessage = "No identity is available.";
|
||||||
group: "alert",
|
|
||||||
type: "danger",
|
|
||||||
title: "Status Error",
|
|
||||||
text: "No identity is available.",
|
|
||||||
},
|
|
||||||
-1,
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
// ask to confirm amount
|
// ask to confirm amount
|
||||||
let toFrom;
|
let toFrom;
|
||||||
@@ -812,15 +684,8 @@ export default class ContactsView extends Vue {
|
|||||||
try {
|
try {
|
||||||
const resp = await this.axios.post(url, payload, { headers });
|
const resp = await this.axios.post(url, payload, { headers });
|
||||||
if (resp.data?.success?.handleId) {
|
if (resp.data?.success?.handleId) {
|
||||||
this.$notify(
|
this.alertTitle = "Done";
|
||||||
{
|
this.alertMessage = "Successfully logged time to the server.";
|
||||||
group: "alert",
|
|
||||||
type: "success",
|
|
||||||
title: "Done",
|
|
||||||
text: "Successfully logged time to the server.",
|
|
||||||
},
|
|
||||||
-1,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (fromDid === identity.did) {
|
if (fromDid === identity.did) {
|
||||||
const newList = R.clone(this.givenByMeUnconfirmed);
|
const newList = R.clone(this.givenByMeUnconfirmed);
|
||||||
@@ -845,15 +710,8 @@ export default class ContactsView extends Vue {
|
|||||||
userMessage = error as string;
|
userMessage = error as string;
|
||||||
}
|
}
|
||||||
// Now set that error for the user to see.
|
// Now set that error for the user to see.
|
||||||
this.$notify(
|
this.alertTitle = "Error With Server";
|
||||||
{
|
this.alertMessage = userMessage;
|
||||||
group: "alert",
|
|
||||||
type: "danger",
|
|
||||||
title: "Error With Server",
|
|
||||||
text: userMessage,
|
|
||||||
},
|
|
||||||
-1,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -83,20 +83,17 @@
|
|||||||
class="block py-4 flex gap-4"
|
class="block py-4 flex gap-4"
|
||||||
>
|
>
|
||||||
<div class="w-12">
|
<div class="w-12">
|
||||||
<EntityIcon
|
<img
|
||||||
:entityId="project.handleId"
|
src="https://picsum.photos/200/200?random=1"
|
||||||
:iconSize="48"
|
class="w-full rounded"
|
||||||
class="block border border-slate-300 rounded-md"
|
/>
|
||||||
></EntityIcon>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="grow">
|
<div class="grow">
|
||||||
<h2 class="text-base font-semibold">{{ project.name }}</h2>
|
<h2 class="text-base font-semibold">Canyon cleanup</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>
|
||||||
{{
|
{{ project.name }}
|
||||||
didInfo(project.issuerDid, activeDid, allMyDids, allContacts)
|
|
||||||
}}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
@@ -114,22 +111,17 @@
|
|||||||
import { Component, Vue } from "vue-facing-decorator";
|
import { Component, Vue } from "vue-facing-decorator";
|
||||||
|
|
||||||
import { accountsDB, db } from "@/db";
|
import { accountsDB, db } from "@/db";
|
||||||
import { Contact } from "@/db/tables/contacts";
|
|
||||||
import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
|
import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
|
||||||
import { accessToken } from "@/libs/crypto";
|
import { accessToken } from "@/libs/crypto";
|
||||||
import { didInfo } from "@/libs/endorserServer";
|
|
||||||
import AlertMessage from "@/components/AlertMessage";
|
import AlertMessage from "@/components/AlertMessage";
|
||||||
import QuickNav from "@/components/QuickNav";
|
import QuickNav from "@/components/QuickNav";
|
||||||
import InfiniteScroll from "@/components/InfiniteScroll";
|
import InfiniteScroll from "@/components/InfiniteScroll";
|
||||||
import EntityIcon from "@/components/EntityIcon";
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
components: { AlertMessage, QuickNav, InfiniteScroll, EntityIcon },
|
components: { AlertMessage, QuickNav, InfiniteScroll },
|
||||||
})
|
})
|
||||||
export default class DiscoverView extends Vue {
|
export default class DiscoverView extends Vue {
|
||||||
activeDid = "";
|
activeDid = "";
|
||||||
allContacts: Array<Contact> = [];
|
|
||||||
allMyDids: Array<string> = [];
|
|
||||||
apiServer = "";
|
apiServer = "";
|
||||||
searchTerms = "";
|
searchTerms = "";
|
||||||
alertMessage = "";
|
alertMessage = "";
|
||||||
@@ -141,20 +133,11 @@ export default class DiscoverView extends Vue {
|
|||||||
remoteCount = 0;
|
remoteCount = 0;
|
||||||
isLoading = false;
|
isLoading = false;
|
||||||
|
|
||||||
// make this function available to the Vue template
|
|
||||||
didInfo = didInfo;
|
|
||||||
|
|
||||||
async mounted() {
|
async mounted() {
|
||||||
await db.open();
|
await db.open();
|
||||||
const settings = await db.settings.get(MASTER_SETTINGS_KEY);
|
const settings = await db.settings.get(MASTER_SETTINGS_KEY);
|
||||||
this.activeDid = settings?.activeDid || "";
|
this.activeDid = settings?.activeDid || "";
|
||||||
this.apiServer = settings?.apiServer || "";
|
this.apiServer = settings?.apiServer || "";
|
||||||
this.allContacts = await db.contacts.toArray();
|
|
||||||
|
|
||||||
await accountsDB.open();
|
|
||||||
const allAccounts = await accountsDB.accounts.toArray();
|
|
||||||
this.allMyDids = allAccounts.map((acc) => acc.did);
|
|
||||||
|
|
||||||
this.searchLocal();
|
this.searchLocal();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -183,6 +166,7 @@ export default class DiscoverView extends Vue {
|
|||||||
public async search(beforeId?: string) {
|
public async search(beforeId?: string) {
|
||||||
let queryParams = "claimContents=" + encodeURIComponent(this.searchTerms);
|
let queryParams = "claimContents=" + encodeURIComponent(this.searchTerms);
|
||||||
|
|
||||||
|
console.log(beforeId);
|
||||||
if (beforeId) {
|
if (beforeId) {
|
||||||
queryParams = queryParams + `&beforeId=${beforeId}`;
|
queryParams = queryParams + `&beforeId=${beforeId}`;
|
||||||
}
|
}
|
||||||
@@ -202,16 +186,6 @@ export default class DiscoverView extends Vue {
|
|||||||
|
|
||||||
if (response.status !== 200) {
|
if (response.status !== 200) {
|
||||||
const details = await response.text();
|
const details = await response.text();
|
||||||
this.$notify(
|
|
||||||
{
|
|
||||||
group: "alert",
|
|
||||||
type: "danger",
|
|
||||||
title: "Error",
|
|
||||||
text: `There was a problem accessing the server. Please try again later. (${details})`,
|
|
||||||
},
|
|
||||||
-1,
|
|
||||||
);
|
|
||||||
|
|
||||||
throw details;
|
throw details;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -220,8 +194,9 @@ export default class DiscoverView extends Vue {
|
|||||||
const plans: ProjectData[] = results.data;
|
const plans: ProjectData[] = results.data;
|
||||||
if (plans) {
|
if (plans) {
|
||||||
for (const plan of plans) {
|
for (const plan of plans) {
|
||||||
const { name, description, handleId, rowid, issuerDid } = plan;
|
const { name, description, handleId = plan.handleId, rowid } = plan;
|
||||||
this.projects.push({ name, description, handleId, rowid, issuerDid });
|
console.log("here");
|
||||||
|
this.projects.push({ name, description, handleId, rowid });
|
||||||
}
|
}
|
||||||
this.remoteCount = this.projects.length;
|
this.remoteCount = this.projects.length;
|
||||||
} else {
|
} else {
|
||||||
@@ -229,15 +204,9 @@ export default class DiscoverView extends Vue {
|
|||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log("Error with feed load:", e);
|
console.log("Error with feed load:", e);
|
||||||
this.$notify(
|
this.alertMessage =
|
||||||
{
|
e.userMessage || "There was an error retrieving projects.";
|
||||||
group: "alert",
|
this.alertTitle = "Error";
|
||||||
type: "danger",
|
|
||||||
title: "Error",
|
|
||||||
text: e.userMessage || "There was a problem retrieving projects.",
|
|
||||||
},
|
|
||||||
-1,
|
|
||||||
);
|
|
||||||
} finally {
|
} finally {
|
||||||
this.isLoading = false;
|
this.isLoading = false;
|
||||||
}
|
}
|
||||||
@@ -271,16 +240,6 @@ export default class DiscoverView extends Vue {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (response.status !== 200) {
|
if (response.status !== 200) {
|
||||||
const details = await response.text();
|
|
||||||
this.$notify(
|
|
||||||
{
|
|
||||||
group: "alert",
|
|
||||||
type: "danger",
|
|
||||||
title: "Error",
|
|
||||||
text: `There was a problem accessing the server. Please try again later. (${details})`,
|
|
||||||
},
|
|
||||||
-1,
|
|
||||||
);
|
|
||||||
throw await response.text();
|
throw await response.text();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -304,15 +263,9 @@ export default class DiscoverView extends Vue {
|
|||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log("Error with feed load:", e);
|
console.log("Error with feed load:", e);
|
||||||
this.$notify(
|
this.alertMessage =
|
||||||
{
|
e.userMessage || "There was an error retrieving projects.";
|
||||||
group: "alert",
|
this.alertTitle = "Error";
|
||||||
type: "danger",
|
|
||||||
title: "Error",
|
|
||||||
text: e.userMessage || "There was a problem retrieving projects.",
|
|
||||||
},
|
|
||||||
-1,
|
|
||||||
);
|
|
||||||
} finally {
|
} finally {
|
||||||
this.isLoading = false;
|
this.isLoading = false;
|
||||||
}
|
}
|
||||||
@@ -325,6 +278,8 @@ export default class DiscoverView extends Vue {
|
|||||||
async loadMoreData(payload: boolean) {
|
async loadMoreData(payload: boolean) {
|
||||||
if (this.projects.length > 0 && payload) {
|
if (this.projects.length > 0 && payload) {
|
||||||
const latestProject = this.projects[this.projects.length - 1];
|
const latestProject = this.projects[this.projects.length - 1];
|
||||||
|
console.log("rowid", latestProject, payload);
|
||||||
|
console.log(Object.keys(latestProject));
|
||||||
if (this.isLocalActive) {
|
if (this.isLocalActive) {
|
||||||
this.searchLocal(latestProject["rowid"]);
|
this.searchLocal(latestProject["rowid"]);
|
||||||
} else if (this.isRemoteActive) {
|
} else if (this.isRemoteActive) {
|
||||||
|
|||||||
@@ -128,14 +128,6 @@
|
|||||||
key.
|
key.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h2 class="text-xl font-semibold">How do I create another identity?</h2>
|
|
||||||
<p>
|
|
||||||
Go
|
|
||||||
<router-link to="start" class="text-blue-500">
|
|
||||||
create another identity here.
|
|
||||||
</router-link>
|
|
||||||
</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>
|
||||||
@@ -154,6 +146,14 @@
|
|||||||
page.
|
page.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<h2 class="text-xl font-semibold">How do I create another identity?</h2>
|
||||||
|
<p>
|
||||||
|
Go
|
||||||
|
<router-link to="start" class="text-blue-500">
|
||||||
|
create another identity here.
|
||||||
|
</router-link>
|
||||||
|
</p>
|
||||||
|
|
||||||
<h2 class="text-xl font-semibold">What is your privacy policy?</h2>
|
<h2 class="text-xl font-semibold">What is your privacy policy?</h2>
|
||||||
<p>
|
<p>
|
||||||
See
|
See
|
||||||
|
|||||||
@@ -6,140 +6,23 @@
|
|||||||
Time Safari
|
Time Safari
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<div class="mb-8">
|
|
||||||
<h2 class="text-xl font-bold mb-4">Notiwind Alert Test Suite</h2>
|
|
||||||
|
|
||||||
<button
|
|
||||||
@click="
|
|
||||||
this.$notify(
|
|
||||||
{
|
|
||||||
group: 'alert',
|
|
||||||
type: 'toast',
|
|
||||||
text: 'I\'m a toast. Don\'t mind me.',
|
|
||||||
},
|
|
||||||
5000,
|
|
||||||
)
|
|
||||||
"
|
|
||||||
class="font-bold uppercase bg-slate-400 text-white px-3 py-2 rounded-md mr-2"
|
|
||||||
>
|
|
||||||
Toast (self-dismiss)
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button
|
|
||||||
@click="
|
|
||||||
this.$notify(
|
|
||||||
{
|
|
||||||
group: 'alert',
|
|
||||||
type: 'info',
|
|
||||||
title: 'Information Alert',
|
|
||||||
text: 'Just wanted you to know.',
|
|
||||||
},
|
|
||||||
-1,
|
|
||||||
)
|
|
||||||
"
|
|
||||||
class="font-bold uppercase bg-slate-600 text-white px-3 py-2 rounded-md mr-2"
|
|
||||||
>
|
|
||||||
Info
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button
|
|
||||||
@click="
|
|
||||||
this.$notify(
|
|
||||||
{
|
|
||||||
group: 'alert',
|
|
||||||
type: 'success',
|
|
||||||
title: 'Success Alert',
|
|
||||||
text: 'Congratulations!',
|
|
||||||
},
|
|
||||||
-1,
|
|
||||||
)
|
|
||||||
"
|
|
||||||
class="font-bold uppercase bg-emerald-600 text-white px-3 py-2 rounded-md mr-2"
|
|
||||||
>
|
|
||||||
Success
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button
|
|
||||||
@click="
|
|
||||||
this.$notify(
|
|
||||||
{
|
|
||||||
group: 'alert',
|
|
||||||
type: 'warning',
|
|
||||||
title: 'Warning Alert',
|
|
||||||
text: 'You might wanna look at this.',
|
|
||||||
},
|
|
||||||
-1,
|
|
||||||
)
|
|
||||||
"
|
|
||||||
class="font-bold uppercase bg-amber-600 text-white px-3 py-2 rounded-md mr-2"
|
|
||||||
>
|
|
||||||
Warning
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button
|
|
||||||
@click="
|
|
||||||
this.$notify(
|
|
||||||
{
|
|
||||||
group: 'alert',
|
|
||||||
type: 'danger',
|
|
||||||
title: 'Danger Alert',
|
|
||||||
text: 'Something terrible has happened!',
|
|
||||||
},
|
|
||||||
-1,
|
|
||||||
)
|
|
||||||
"
|
|
||||||
class="font-bold uppercase bg-rose-600 text-white px-3 py-2 rounded-md mr-2"
|
|
||||||
>
|
|
||||||
Danger
|
|
||||||
</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 class="mb-8">
|
<div class="mb-8">
|
||||||
<h2 class="text-xl font-bold">Quick Action</h2>
|
<h2 class="text-xl font-bold">Quick Action</h2>
|
||||||
<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"
|
||||||
@click="openDialog(contact)"
|
@click="openDialog(contact)"
|
||||||
>
|
>
|
||||||
<EntityIcon
|
<div class="mb-1">
|
||||||
:entityId="contact.did"
|
<fa icon="user" class="fa-fw fa-xl text-slate-400"></fa>
|
||||||
:iconSize="64"
|
</div>
|
||||||
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"
|
||||||
>
|
>
|
||||||
{{ contact.name || contact.did }}
|
{{ contact.name || "(no name)" }}
|
||||||
</h3>
|
</h3>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -156,7 +39,6 @@
|
|||||||
<!-- 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>
|
||||||
@@ -213,10 +95,9 @@ import { createAndSubmitGive, didInfo } from "@/libs/endorserServer";
|
|||||||
import { Contact } from "@/db/tables/contacts";
|
import { Contact } from "@/db/tables/contacts";
|
||||||
import AlertMessage from "@/components/AlertMessage";
|
import AlertMessage from "@/components/AlertMessage";
|
||||||
import QuickNav from "@/components/QuickNav";
|
import QuickNav from "@/components/QuickNav";
|
||||||
import EntityIcon from "@/components/EntityIcon";
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
components: { GiftedDialog, AlertMessage, QuickNav, EntityIcon },
|
components: { GiftedDialog, AlertMessage, QuickNav },
|
||||||
})
|
})
|
||||||
export default class HomeView extends Vue {
|
export default class HomeView extends Vue {
|
||||||
activeDid = "";
|
activeDid = "";
|
||||||
@@ -276,17 +157,10 @@ export default class HomeView extends Vue {
|
|||||||
this.feedLastViewedId = settings?.lastViewedClaimId;
|
this.feedLastViewedId = settings?.lastViewedClaimId;
|
||||||
this.updateAllFeed();
|
this.updateAllFeed();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.$notify(
|
this.alertTitle = "Error";
|
||||||
{
|
this.alertMessage =
|
||||||
group: "alert",
|
err.userMessage ||
|
||||||
type: "danger",
|
"There was an error retrieving the latest sweet, sweet action.";
|
||||||
title: "Error",
|
|
||||||
text:
|
|
||||||
err.userMessage ||
|
|
||||||
"There was an error retrieving the latest sweet, sweet action.",
|
|
||||||
},
|
|
||||||
-1,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -335,15 +209,9 @@ export default class HomeView extends Vue {
|
|||||||
})
|
})
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
console.log("Error with feed load:", e);
|
console.log("Error with feed load:", e);
|
||||||
this.$notify(
|
this.alertMessage =
|
||||||
{
|
e.userMessage || "There was an error retrieving feed data.";
|
||||||
group: "alert",
|
this.alertTitle = "Error";
|
||||||
type: "danger",
|
|
||||||
title: "Export Error",
|
|
||||||
text: e.userMessage || "There was an error retrieving feed data.",
|
|
||||||
},
|
|
||||||
-1,
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this.isHiddenSpinner = true;
|
this.isHiddenSpinner = true;
|
||||||
@@ -378,7 +246,8 @@ 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 = claim.agent?.identifier || claim.agent?.did;
|
const giverDid =
|
||||||
|
claim.agent?.identifier || claim.agent?.did || giveRecord.issuer;
|
||||||
const giverInfo = didInfo(
|
const giverInfo = didInfo(
|
||||||
giverDid,
|
giverDid,
|
||||||
this.activeDid,
|
this.activeDid,
|
||||||
@@ -417,7 +286,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.giver?.did, result.description, result.hours);
|
this.recordGive(result.contact?.did, result.description, result.hours);
|
||||||
resolve();
|
resolve();
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@@ -433,27 +302,17 @@ export default class HomeView extends Vue {
|
|||||||
*/
|
*/
|
||||||
public async recordGive(giverDid, description, hours) {
|
public async recordGive(giverDid, description, hours) {
|
||||||
if (!this.activeDid) {
|
if (!this.activeDid) {
|
||||||
this.$notify(
|
this.setAlert(
|
||||||
{
|
"Error",
|
||||||
group: "alert",
|
"You must select an identity before you can record a give.",
|
||||||
type: "danger",
|
|
||||||
title: "Error",
|
|
||||||
text: "You must select an identity before you can record a give.",
|
|
||||||
},
|
|
||||||
-1,
|
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!description && !hours) {
|
if (!description && !hours) {
|
||||||
this.$notify(
|
this.setAlert(
|
||||||
{
|
"Error",
|
||||||
group: "alert",
|
"You must enter a description or some number of hours.",
|
||||||
type: "danger",
|
|
||||||
title: "Error",
|
|
||||||
text: "You must enter a description or some number of hours.",
|
|
||||||
},
|
|
||||||
-1,
|
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -473,38 +332,19 @@ export default class HomeView extends Vue {
|
|||||||
if (this.isGiveCreationError(result)) {
|
if (this.isGiveCreationError(result)) {
|
||||||
const errorMessage = this.getGiveCreationErrorMessage(result);
|
const errorMessage = this.getGiveCreationErrorMessage(result);
|
||||||
console.log("Error with give result:", result);
|
console.log("Error with give result:", result);
|
||||||
this.$notify(
|
this.setAlert(
|
||||||
{
|
"Error",
|
||||||
group: "alert",
|
errorMessage || "There was an error recording the give.",
|
||||||
type: "danger",
|
|
||||||
title: "Error",
|
|
||||||
text: errorMessage || "There was an error recording the give.",
|
|
||||||
},
|
|
||||||
-1,
|
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
this.$notify(
|
this.setAlert("Success", "That gift was recorded.");
|
||||||
{
|
|
||||||
group: "alert",
|
|
||||||
type: "success",
|
|
||||||
title: "Success",
|
|
||||||
text: "That gift was recorded.",
|
|
||||||
},
|
|
||||||
-1,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log("Error with give caught:", error);
|
console.log("Error with give caught:", error);
|
||||||
this.$notify(
|
this.setAlert(
|
||||||
{
|
"Error",
|
||||||
group: "alert",
|
this.getGiveErrorMessage(error) ||
|
||||||
type: "danger",
|
"There was an error recording the give.",
|
||||||
title: "Error",
|
|
||||||
text:
|
|
||||||
this.getGiveErrorMessage(error) ||
|
|
||||||
"There was an error recording the give.",
|
|
||||||
},
|
|
||||||
-1,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -133,19 +133,13 @@ export default class IdentitySwitcherView extends Vue {
|
|||||||
this.limitsMessage = "No identity.";
|
this.limitsMessage = "No identity.";
|
||||||
this.loadingLimits = false;
|
this.loadingLimits = false;
|
||||||
} else {
|
} else {
|
||||||
this.$notify(
|
this.alertMessage =
|
||||||
{
|
"Clear your cache and start over (after data backup).";
|
||||||
group: "alert",
|
|
||||||
type: "danger",
|
|
||||||
title: "Error Creating Account",
|
|
||||||
text: "Clear your cache and start over (after data backup).",
|
|
||||||
},
|
|
||||||
-1,
|
|
||||||
);
|
|
||||||
console.error(
|
console.error(
|
||||||
"Telling user to clear cache at page create because:",
|
"Telling user to clear cache at page create because:",
|
||||||
err,
|
err,
|
||||||
);
|
);
|
||||||
|
this.alertTitle = "Error Creating Account";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,24 +24,6 @@
|
|||||||
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()"
|
||||||
@@ -62,11 +44,7 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Component, Vue } from "vue-facing-decorator";
|
import { Component, Vue } from "vue-facing-decorator";
|
||||||
import {
|
import { deriveAddress, newIdentifier } from "../libs/crypto";
|
||||||
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";
|
||||||
|
|
||||||
@@ -74,14 +52,11 @@ 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 = DEFAULT_ROOT_DERIVATION_PATH;
|
derivationPath = "";
|
||||||
showAdvanced = false;
|
|
||||||
|
|
||||||
public onCancelClick() {
|
public onCancelClick() {
|
||||||
this.$router.back();
|
this.$router.back();
|
||||||
@@ -90,10 +65,8 @@ 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] = deriveAddress(
|
[this.address, this.privateHex, this.publicHex, this.derivationPath] =
|
||||||
mne,
|
deriveAddress(mne);
|
||||||
this.derivationPath,
|
|
||||||
);
|
|
||||||
|
|
||||||
const newId = newIdentifier(
|
const newId = newIdentifier(
|
||||||
this.address,
|
this.address,
|
||||||
|
|||||||
@@ -1,163 +0,0 @@
|
|||||||
<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://api.endorser.ch/api-docs/
|
// version shows up here: https://endorser.ch:3000/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://api.endorser.ch/api-docs/
|
// version shows up here: https://endorser.ch:3000/api-docs/
|
||||||
useAppStore().setProjectId(
|
useAppStore().setProjectId(
|
||||||
resp.data.success.handleId || resp.data.success.fullIri,
|
resp.data.success.handleId || resp.data.success.fullIri,
|
||||||
);
|
);
|
||||||
@@ -245,41 +245,20 @@ export default class NewEditProjectView extends Vue {
|
|||||||
if (serverError) {
|
if (serverError) {
|
||||||
if (Object.prototype.hasOwnProperty.call(serverError, "message")) {
|
if (Object.prototype.hasOwnProperty.call(serverError, "message")) {
|
||||||
console.log(serverError);
|
console.log(serverError);
|
||||||
|
this.alertTitle = "User Message";
|
||||||
userMessage = serverError.response.data.error.message; // This is info for the user.
|
userMessage = serverError.response.data.error.message; // This is info for the user.
|
||||||
this.$notify(
|
this.alertMessage = userMessage;
|
||||||
{
|
|
||||||
group: "alert",
|
|
||||||
type: "danger",
|
|
||||||
title: "User Message",
|
|
||||||
text: userMessage,
|
|
||||||
},
|
|
||||||
-1,
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
this.$notify(
|
this.alertTitle = "Server Message";
|
||||||
{
|
this.alertMessage = JSON.stringify(serverError.toJSON());
|
||||||
group: "alert",
|
|
||||||
type: "danger",
|
|
||||||
title: "Server Message",
|
|
||||||
text: JSON.stringify(serverError.toJSON()),
|
|
||||||
},
|
|
||||||
-1,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
console.error(
|
console.error(
|
||||||
"Here's the full error trying to save the claim:",
|
"Here's the full error trying to save the claim:",
|
||||||
error,
|
error,
|
||||||
);
|
);
|
||||||
this.$notify(
|
this.alertTitle = "Claim Error";
|
||||||
{
|
this.alertMessage = error as string;
|
||||||
group: "alert",
|
|
||||||
type: "danger",
|
|
||||||
title: "Claim Error",
|
|
||||||
text: error as string,
|
|
||||||
},
|
|
||||||
-1,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
// Now set that error for the user to see.
|
// Now set that error for the user to see.
|
||||||
this.errorMessage = userMessage;
|
this.errorMessage = userMessage;
|
||||||
|
|||||||
@@ -12,6 +12,13 @@
|
|||||||
>
|
>
|
||||||
<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>
|
||||||
@@ -19,28 +26,16 @@
|
|||||||
<!-- Project Details -->
|
<!-- Project Details -->
|
||||||
<div class="bg-slate-100 rounded-md overflow-hidden px-4 py-3 mb-4">
|
<div class="bg-slate-100 rounded-md overflow-hidden px-4 py-3 mb-4">
|
||||||
<div>
|
<div>
|
||||||
<div class="block pb-4 flex gap-4">
|
<h2 class="text-xl font-semibold">{{ name }}</h2>
|
||||||
<div class="flex-none w-16 pt-1">
|
<div class="flex justify-between gap-4 text-sm mb-3">
|
||||||
<EntityIcon
|
<span
|
||||||
:entityId="projectId"
|
><fa icon="user" class="fa-fw text-slate-400"></fa>
|
||||||
:iconSize="64"
|
{{ issuer }}</span
|
||||||
class="block border border-slate-300 rounded-md"
|
>
|
||||||
></EntityIcon>
|
<span
|
||||||
</div>
|
><fa icon="calendar" class="fa-fw text-slate-400"></fa
|
||||||
|
>{{ timeSince }}
|
||||||
<div class="overflow-hidden">
|
</span>
|
||||||
<h2 class="text-xl font-semibold">{{ name }}</h2>
|
|
||||||
<div class="text-sm mb-3">
|
|
||||||
<div class="truncate">
|
|
||||||
<fa icon="user" class="fa-fw text-slate-400"></fa>
|
|
||||||
{{ issuer }}
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<fa icon="calendar" class="fa-fw text-slate-400"></fa>
|
|
||||||
{{ timeSince }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="text-sm text-slate-500">
|
<div class="text-sm text-slate-500">
|
||||||
@@ -61,7 +56,6 @@
|
|||||||
</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()"
|
||||||
@@ -71,119 +65,83 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<div v-if="activeDid" class="text-center">
|
<div v-if="activeDid">
|
||||||
<button
|
<button
|
||||||
@click="openDialog({ name: 'you', did: activeDid })"
|
@click="openDialog({ name: 'you', did: activeDid })"
|
||||||
class="block w-full text-lg font-bold uppercase bg-blue-600 text-white px-2 py-3 rounded-md"
|
class="text-center text-lg font-bold uppercase bg-blue-600 text-white px-2 py-3 rounded-md"
|
||||||
>
|
>
|
||||||
I gave…
|
I gave...
|
||||||
</button>
|
</button>
|
||||||
<p class="mt-2 mb-4 text-center">Or, record a gift from:</p>
|
― or:
|
||||||
</div>
|
</div>
|
||||||
<p v-if="!activeDid" class="mt-2 mb-4">Record a gift from:</p>
|
<!-- similar contact selection code is in multiple places -->
|
||||||
|
Record a gift from
|
||||||
<ul class="grid grid-cols-4 gap-x-3 gap-y-5 text-center mb-5">
|
<span v-for="contact in allContacts" :key="contact.did">
|
||||||
<li @click="openDialog()">
|
<button @click="openDialog(contact)" class="text-blue-500">
|
||||||
<EntityIcon
|
{{ contact.name }}</button
|
||||||
:entityId="Anonymous"
|
>,
|
||||||
:iconSize="64"
|
</span>
|
||||||
class="mx-auto border border-slate-300 rounded-md mb-1"
|
<span v-if="allContacts.length > 0"> or </span>
|
||||||
></EntityIcon>
|
<button @click="openDialog()" class="text-blue-500">
|
||||||
<h3
|
someone not specified
|
||||||
class="text-xs italic font-medium text-ellipsis whitespace-nowrap overflow-hidden"
|
</button>
|
||||||
>
|
|
||||||
Anonymous
|
|
||||||
</h3>
|
|
||||||
</li>
|
|
||||||
<li
|
|
||||||
v-for="contact in allContacts"
|
|
||||||
:key="contact.did"
|
|
||||||
@click="openDialog(contact)"
|
|
||||||
>
|
|
||||||
<EntityIcon
|
|
||||||
:entityId="contact.did"
|
|
||||||
:iconSize="64"
|
|
||||||
class="mx-auto border border-slate-300 rounded-md mb-1"
|
|
||||||
></EntityIcon>
|
|
||||||
<h3
|
|
||||||
class="text-xs font-medium text-ellipsis whitespace-nowrap overflow-hidden"
|
|
||||||
>
|
|
||||||
{{ contact.name || "(no name)" }}
|
|
||||||
</h3>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<!-- Ideally, this button should only be visible when the active account has more than 7 or 11 contacts in their list (we want to limit the grid count above to 8 or 12 accounts to keep it compact) -->
|
|
||||||
<router-link
|
|
||||||
v-if="allContacts.length > 7"
|
|
||||||
:to="{ name: 'contact-gives' }"
|
|
||||||
class="block text-center text-md font-bold uppercase bg-slate-500 text-white px-2 py-3 rounded-md"
|
|
||||||
>
|
|
||||||
Show More Contacts…
|
|
||||||
</router-link>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Gifts to & from this -->
|
<!-- Gifts to & from this -->
|
||||||
<div class="grid items-start grid-cols-1 sm:grid-cols-2 gap-4">
|
<div class="mt-8 flex justify-around">
|
||||||
<div class="bg-slate-100 px-4 py-3 rounded-md">
|
<div>
|
||||||
<h3 class="text-sm uppercase font-semibold mb-3">
|
<h1 class="text-xl">Given to this Project</h1>
|
||||||
Given to this Project
|
|
||||||
</h3>
|
|
||||||
|
|
||||||
<ul class="text-sm border-t border-slate-300">
|
|
||||||
<li
|
|
||||||
v-for="give in givesToThis"
|
|
||||||
:key="give.id"
|
|
||||||
class="py-1.5 border-b border-slate-300"
|
|
||||||
>
|
|
||||||
<div class="flex justify-between gap-4">
|
|
||||||
<span
|
|
||||||
><fa icon="user" class="fa-fw text-slate-400"></fa>
|
|
||||||
{{ didInfo(give.agentDid, activeDid, allMyDids, allContacts) }}
|
|
||||||
</span>
|
|
||||||
<span v-if="give.amount"
|
|
||||||
><fa icon="coins" class="fa-fw text-slate-400"></fa>
|
|
||||||
{{ give.amount }}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div v-if="give.description" class="text-slate-500">
|
|
||||||
<fa icon="comment" class="fa-fw text-slate-400"></fa>
|
|
||||||
{{ give.description }}
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
<div class="bg-slate-100 px-4 py-3 rounded-md">
|
<h1 class="text-xl">... and from this Project</h1>
|
||||||
<h3 class="text-sm uppercase font-semibold mb-3">
|
</div>
|
||||||
…and from this Project
|
</div>
|
||||||
</h3>
|
<div class="flex justify-around">
|
||||||
|
<div class="w-1/2">
|
||||||
<ul class="text-sm border-t border-slate-300">
|
<div v-for="give in givesToThis" :key="give.id">
|
||||||
<li
|
<div class="flex justify-between">
|
||||||
v-for="give in givesByThis"
|
<div class="flex gap-3">
|
||||||
:key="give.id"
|
<div class="flex gap-2">
|
||||||
class="py-1.5 border-b border-slate-300"
|
<fa icon="user" class="fa-fw text-slate-400"></fa>
|
||||||
>
|
<span>{{
|
||||||
<div class="flex justify-between gap-4">
|
didInfo(give.agentDid, activeDid, allMyDids, allContacts)
|
||||||
<span
|
}}</span>
|
||||||
><fa icon="user" class="fa-fw text-slate-400"></fa>
|
</div>
|
||||||
{{ didInfo(give.agentDid, activeDid, allMyDids, allContacts) }}
|
<div class="flex gap-2" v-if="give.amount">
|
||||||
</span>
|
<fa icon="coins" class="fa-fw text-slate-400"></fa>
|
||||||
<span v-if="give.amount"
|
<span>{{ give.amount }}</span>
|
||||||
><fa icon="coins" class="fa-fw text-slate-400"></fa>
|
</div>
|
||||||
{{ give.amount }}
|
<div class="flex gap-2" v-if="give.description">
|
||||||
</span>
|
<fa icon="comment" class="fa-fw text-slate-400"></fa>
|
||||||
</div>
|
<span>{{ give.description }}</span>
|
||||||
<div v-if="give.description" class="text-slate-500">
|
</div>
|
||||||
<fa icon="comment" class="fa-fw text-slate-400"></fa>
|
</div>
|
||||||
{{ give.description }}
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</div>
|
||||||
</ul>
|
<div class="w-1/2">
|
||||||
|
<div v-for="give in givesByThis" :key="give.id">
|
||||||
|
<div class="flex justify-between">
|
||||||
|
<div class="flex gap-3">
|
||||||
|
<div class="flex gap-2">
|
||||||
|
<fa icon="user" class="fa-fw text-slate-400"></fa>
|
||||||
|
<span>{{
|
||||||
|
didInfo(give.agentDid, activeDid, allMyDids, allContacts)
|
||||||
|
}}</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex gap-2" v-if="give.amount">
|
||||||
|
<fa icon="coins" class="fa-fw text-slate-400"></fa>
|
||||||
|
<span>{{ give.amount }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex gap-2">
|
||||||
|
<fa icon="comment" class="fa-fw text-slate-400"></fa>
|
||||||
|
<span>{{ give.description }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<GiftedDialog
|
<GiftedDialog
|
||||||
ref="customDialog"
|
ref="customDialog"
|
||||||
@dialog-result="handleDialogResult"
|
@dialog-result="handleDialogResult"
|
||||||
@@ -215,10 +173,9 @@ import {
|
|||||||
} from "@/libs/endorserServer";
|
} from "@/libs/endorserServer";
|
||||||
import AlertMessage from "@/components/AlertMessage";
|
import AlertMessage from "@/components/AlertMessage";
|
||||||
import QuickNav from "@/components/QuickNav";
|
import QuickNav from "@/components/QuickNav";
|
||||||
import EntityIcon from "@/components/EntityIcon";
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
components: { GiftedDialog, AlertMessage, QuickNav, EntityIcon },
|
components: { GiftedDialog, AlertMessage, QuickNav },
|
||||||
})
|
})
|
||||||
export default class ProjectViewView extends Vue {
|
export default class ProjectViewView extends Vue {
|
||||||
activeDid = "";
|
activeDid = "";
|
||||||
@@ -328,38 +285,16 @@ export default class ProjectViewView extends Vue {
|
|||||||
this.truncatedDesc = this.description.slice(0, this.truncateLength);
|
this.truncatedDesc = this.description.slice(0, this.truncateLength);
|
||||||
} else if (resp.status === 404) {
|
} else if (resp.status === 404) {
|
||||||
// actually, axios throws an error so we never get here
|
// actually, axios throws an error so we never get here
|
||||||
this.$notify(
|
this.alertMessage = "That project does not exist.";
|
||||||
{
|
|
||||||
group: "alert",
|
|
||||||
type: "danger",
|
|
||||||
title: "Error",
|
|
||||||
text: "That project does not exist.",
|
|
||||||
},
|
|
||||||
-1,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
const serverError = error as AxiosError;
|
const serverError = error as AxiosError;
|
||||||
if (serverError.response?.status === 404) {
|
if (serverError.response?.status === 404) {
|
||||||
this.$notify(
|
this.alertMessage = "That project does not exist.";
|
||||||
{
|
|
||||||
group: "alert",
|
|
||||||
type: "danger",
|
|
||||||
title: "Error",
|
|
||||||
text: "That project does not exist.",
|
|
||||||
},
|
|
||||||
-1,
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
this.$notify(
|
this.alertMessage =
|
||||||
{
|
"Something went wrong retrieving that project." +
|
||||||
group: "alert",
|
" See logs for more info.";
|
||||||
type: "danger",
|
|
||||||
title: "Error",
|
|
||||||
text: "Something went wrong retrieving that project. See logs for more info.",
|
|
||||||
},
|
|
||||||
-1,
|
|
||||||
);
|
|
||||||
console.error("Error retrieving project:", serverError.message);
|
console.error("Error retrieving project:", serverError.message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -373,27 +308,12 @@ export default class ProjectViewView extends Vue {
|
|||||||
if (resp.status === 200 && resp.data.data) {
|
if (resp.status === 200 && resp.data.data) {
|
||||||
this.givesToThis = resp.data.data;
|
this.givesToThis = resp.data.data;
|
||||||
} else {
|
} else {
|
||||||
this.$notify(
|
this.alertMessage = "Failed to retrieve gives to this project.";
|
||||||
{
|
|
||||||
group: "alert",
|
|
||||||
type: "danger",
|
|
||||||
title: "Error",
|
|
||||||
text: "Failed to retrieve gives to this project.",
|
|
||||||
},
|
|
||||||
-1,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
const serverError = error as AxiosError;
|
const serverError = error as AxiosError;
|
||||||
this.$notify(
|
this.alertMessage =
|
||||||
{
|
"Something went wrong retrieving gives to this project.";
|
||||||
group: "alert",
|
|
||||||
type: "danger",
|
|
||||||
title: "Error",
|
|
||||||
text: "Something went wrong retrieving gives to this project.",
|
|
||||||
},
|
|
||||||
-1,
|
|
||||||
);
|
|
||||||
console.error(
|
console.error(
|
||||||
"Error retrieving gives to this project:",
|
"Error retrieving gives to this project:",
|
||||||
serverError.message,
|
serverError.message,
|
||||||
@@ -409,27 +329,11 @@ export default class ProjectViewView extends Vue {
|
|||||||
if (resp.status === 200 && resp.data.data) {
|
if (resp.status === 200 && resp.data.data) {
|
||||||
this.givesByThis = resp.data.data;
|
this.givesByThis = resp.data.data;
|
||||||
} else {
|
} else {
|
||||||
this.$notify(
|
this.alertMessage = "Failed to retrieve gives by this project.";
|
||||||
{
|
|
||||||
group: "alert",
|
|
||||||
type: "danger",
|
|
||||||
title: "Error",
|
|
||||||
text: "Failed to retrieve gives by this project.",
|
|
||||||
},
|
|
||||||
-1,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
const serverError = error as AxiosError;
|
const serverError = error as AxiosError;
|
||||||
this.$notify(
|
this.alertMessage = "Something went wrong retrieving gives by project.";
|
||||||
{
|
|
||||||
group: "alert",
|
|
||||||
type: "danger",
|
|
||||||
title: "Error",
|
|
||||||
text: "Something went wrong retrieving gives by project.",
|
|
||||||
},
|
|
||||||
-1,
|
|
||||||
);
|
|
||||||
console.error(
|
console.error(
|
||||||
"Error retrieving gives by this project:",
|
"Error retrieving gives by this project:",
|
||||||
serverError.message,
|
serverError.message,
|
||||||
@@ -460,28 +364,16 @@ export default class ProjectViewView extends Vue {
|
|||||||
*/
|
*/
|
||||||
async recordGive(giverDid, description, hours) {
|
async recordGive(giverDid, description, hours) {
|
||||||
if (!this.activeDid) {
|
if (!this.activeDid) {
|
||||||
this.$notify(
|
this.alertTitle = "Error";
|
||||||
{
|
this.alertMessage =
|
||||||
group: "alert",
|
"You must select an identity before you can record a give.";
|
||||||
type: "danger",
|
|
||||||
title: "Error",
|
|
||||||
text: "You must select an identity before you can record a give.",
|
|
||||||
},
|
|
||||||
-1,
|
|
||||||
);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!description && !hours) {
|
if (!description && !hours) {
|
||||||
this.$notify(
|
this.alertTitle = "Error";
|
||||||
{
|
this.alertMessage =
|
||||||
group: "alert",
|
"You must enter a description or some number of hours.";
|
||||||
type: "danger",
|
|
||||||
title: "Error",
|
|
||||||
text: "You must enter a description or some number of hours.",
|
|
||||||
},
|
|
||||||
-1,
|
|
||||||
);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -500,42 +392,21 @@ export default class ProjectViewView extends Vue {
|
|||||||
|
|
||||||
if (result.status !== 201 || result.data?.error) {
|
if (result.status !== 201 || result.data?.error) {
|
||||||
console.log("Error with give result:", result);
|
console.log("Error with give result:", result);
|
||||||
this.$notify(
|
this.alertTitle = "Error";
|
||||||
{
|
this.alertMessage =
|
||||||
group: "alert",
|
result.data?.error?.message ||
|
||||||
type: "danger",
|
"There was an error recording the give.";
|
||||||
title: "Error",
|
|
||||||
text:
|
|
||||||
result.data?.error?.message ||
|
|
||||||
"There was an error recording the give.",
|
|
||||||
},
|
|
||||||
-1,
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
this.$notify(
|
this.alertTitle = "Success";
|
||||||
{
|
this.alertMessage = "That gift was recorded.";
|
||||||
group: "alert",
|
|
||||||
type: "success",
|
|
||||||
title: "Success",
|
|
||||||
text: "That gift was recorded.",
|
|
||||||
},
|
|
||||||
-1,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log("Error with give caught:", e);
|
console.log("Error with give caught:", e);
|
||||||
this.$notify(
|
this.alertTitle = "Error";
|
||||||
{
|
this.alertMessage =
|
||||||
group: "alert",
|
e.userMessage ||
|
||||||
type: "danger",
|
e.response?.data?.error?.message ||
|
||||||
title: "Error",
|
"There was an error recording the give.";
|
||||||
text:
|
|
||||||
e.userMessage ||
|
|
||||||
e.response?.data?.error?.message ||
|
|
||||||
"There was an error recording the give.",
|
|
||||||
},
|
|
||||||
-1,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,18 +8,16 @@
|
|||||||
|
|
||||||
<!-- Quick Search -->
|
<!-- Quick Search -->
|
||||||
|
|
||||||
<div id="QuickSearch" class="mb-4 flex">
|
<input
|
||||||
<input
|
type="text"
|
||||||
type="text"
|
placeholder="Search…"
|
||||||
placeholder="Search…"
|
class="block w-full rounded-l border border-r-0 border-slate-400 px-3 py-2"
|
||||||
class="block w-full rounded-l border border-r-0 border-slate-400 px-3 py-2"
|
/>
|
||||||
/>
|
<button
|
||||||
<button
|
class="px-4 rounded-r bg-slate-200 border border-l-0 border-slate-400"
|
||||||
class="px-4 rounded-r bg-slate-200 border border-l-0 border-slate-400"
|
>
|
||||||
>
|
<fa icon="magnifying-glass" class="fa-fw"></fa>
|
||||||
<fa icon="magnifying-glass" class="fa-fw"></fa>
|
</button>
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- New Project -->
|
<!-- New Project -->
|
||||||
<button
|
<button
|
||||||
@@ -39,7 +37,7 @@
|
|||||||
|
|
||||||
<!-- Results List -->
|
<!-- Results List -->
|
||||||
<InfiniteScroll @reached-bottom="loadMoreData">
|
<InfiniteScroll @reached-bottom="loadMoreData">
|
||||||
<ul class="border-t border-slate-300">
|
<ul>
|
||||||
<li
|
<li
|
||||||
class="border-b border-slate-300"
|
class="border-b border-slate-300"
|
||||||
v-for="project in projects"
|
v-for="project in projects"
|
||||||
@@ -50,11 +48,10 @@
|
|||||||
class="block py-4 flex gap-4"
|
class="block py-4 flex gap-4"
|
||||||
>
|
>
|
||||||
<div class="flex-none w-12">
|
<div class="flex-none w-12">
|
||||||
<EntityIcon
|
<img
|
||||||
:entityId="project.handleId"
|
src="https://picsum.photos/200/200?random=1"
|
||||||
:iconSize="48"
|
class="w-full rounded"
|
||||||
class="inline-block align-middle border border-slate-300 rounded-md"
|
/>
|
||||||
></EntityIcon>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="grow overflow-hidden">
|
<div class="grow overflow-hidden">
|
||||||
@@ -83,10 +80,9 @@ import { IIdentifier } from "@veramo/core";
|
|||||||
import InfiniteScroll from "@/components/InfiniteScroll";
|
import InfiniteScroll from "@/components/InfiniteScroll";
|
||||||
import AlertMessage from "@/components/AlertMessage";
|
import AlertMessage from "@/components/AlertMessage";
|
||||||
import QuickNav from "@/components/QuickNav";
|
import QuickNav from "@/components/QuickNav";
|
||||||
import EntityIcon from "@/components/EntityIcon";
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
components: { InfiniteScroll, AlertMessage, QuickNav, EntityIcon },
|
components: { InfiniteScroll, AlertMessage, QuickNav },
|
||||||
})
|
})
|
||||||
export default class ProjectsView extends Vue {
|
export default class ProjectsView extends Vue {
|
||||||
apiServer = "";
|
apiServer = "";
|
||||||
@@ -128,15 +124,8 @@ export default class ProjectsView extends Vue {
|
|||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Got error loading projects:", error.message);
|
console.error("Got error loading projects:", error.message);
|
||||||
this.$notify(
|
this.alertTitle = "Error";
|
||||||
{
|
this.alertMessage = "Got an error loading projects:" + error.message;
|
||||||
group: "alert",
|
|
||||||
type: "danger",
|
|
||||||
title: "Error",
|
|
||||||
text: "Got an error loading projects: " + error.message,
|
|
||||||
},
|
|
||||||
-1,
|
|
||||||
);
|
|
||||||
} finally {
|
} finally {
|
||||||
this.isLoading = false;
|
this.isLoading = false;
|
||||||
}
|
}
|
||||||
@@ -205,15 +194,8 @@ export default class ProjectsView extends Vue {
|
|||||||
|
|
||||||
if (this.numAccounts === 0) {
|
if (this.numAccounts === 0) {
|
||||||
console.error("No accounts found.");
|
console.error("No accounts found.");
|
||||||
this.$notify(
|
this.alertTitle = "Error";
|
||||||
{
|
this.alertMessage = "You need an identity to load your projects.";
|
||||||
group: "alert",
|
|
||||||
type: "danger",
|
|
||||||
title: "Error",
|
|
||||||
text: "You need an identity to load your projects.",
|
|
||||||
},
|
|
||||||
-1,
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
const identity = await this.getIdentity(activeDid);
|
const identity = await this.getIdentity(activeDid);
|
||||||
this.current = identity;
|
this.current = identity;
|
||||||
@@ -221,15 +203,8 @@ export default class ProjectsView extends Vue {
|
|||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log("Error initializing:", err);
|
console.log("Error initializing:", err);
|
||||||
this.$notify(
|
this.alertTitle = "Error";
|
||||||
{
|
this.alertMessage = "Something went wrong loading your projects.";
|
||||||
group: "alert",
|
|
||||||
type: "danger",
|
|
||||||
title: "Error",
|
|
||||||
text: "Something went wrong loading your projects.",
|
|
||||||
},
|
|
||||||
-1,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,34 +20,22 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="activeAccount">
|
<div v-if="activeAccount">
|
||||||
<p class="text-center mb-4">
|
<p>
|
||||||
<b class="text-red-600">BEWARE!</b> Anyone who has this seed phrase will
|
BEWARE: Anyone who gets hold of this mnemonic seed phrase will be able
|
||||||
be able impersonate you and take over any digital holdings based on it.
|
impersonate you and take over any digital holdings based on it. So only
|
||||||
Reveal it when you are somewhere only you can see your screen, and
|
reveal it when you are in a private place out of sight of other eyes,
|
||||||
record it somewhere only you have access.
|
and only record it in something private -- don't take a screenshot or
|
||||||
<i>Don't take a screenshot or send it to any online service.</i>
|
send it to any online service.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p v-if="numAccounts > 1">
|
<button
|
||||||
<b class="text-orange-600">Note:</b> You have more than one identity
|
class="block w-full text-center text-md uppercase bg-slate-500 text-white px-1.5 py-2 rounded-md"
|
||||||
stored in this browser. If they are all based on the same seed as the
|
@click="showSeedPhrase"
|
||||||
current identity, this one backup is sufficient; however, if you have
|
>
|
||||||
different seeds for other identities, you will have to back them up
|
Click here when you're ready to see it.
|
||||||
separately.
|
</button>
|
||||||
</p>
|
|
||||||
|
|
||||||
<div class="bg-slate-100 rounded-md overflow-hidden p-4 mb-4">
|
<p v-if="showSeed">{{ activeAccount.mnemonic }}</p>
|
||||||
<button
|
|
||||||
class="block w-full text-center text-md uppercase bg-slate-500 text-white px-1.5 py-2 rounded-md"
|
|
||||||
@click="showSeedPhrase"
|
|
||||||
>
|
|
||||||
Reveal my Seed Phrase
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<p v-if="showSeed" class="text-center text-slate-700 mt-2">
|
|
||||||
{{ activeAccount.mnemonic }}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div v-else>You do not have an active identity.</div>
|
<div v-else>You do not have an active identity.</div>
|
||||||
<AlertMessage
|
<AlertMessage
|
||||||
@@ -68,7 +56,6 @@ 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 = "";
|
||||||
@@ -82,19 +69,11 @@ 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);
|
||||||
this.$notify(
|
this.alertTitle = "Error Loading Account";
|
||||||
{
|
this.alertMessage = "Got an error loading your seed data.";
|
||||||
group: "alert",
|
|
||||||
type: "danger",
|
|
||||||
title: "Error Loading Account",
|
|
||||||
text: "Got an error loading your seed data.",
|
|
||||||
},
|
|
||||||
-1,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,46 +10,30 @@
|
|||||||
|
|
||||||
<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 have an identity to import?
|
Do you already have an identity to import?
|
||||||
</p>
|
</p>
|
||||||
<a
|
<a
|
||||||
@click="onClickYes()"
|
@click="onClickYes()"
|
||||||
class="block w-full text-center text-lg uppercase bg-blue-600 text-white px-2 py-3 rounded-md"
|
class="block w-full text-center text-lg font-bold uppercase bg-blue-600 text-white px-2 py-3 rounded-md mb-2"
|
||||||
>
|
>
|
||||||
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 mt-2"
|
class="block w-full text-center text-md uppercase bg-slate-500 text-white px-1.5 py-2 rounded-md"
|
||||||
|
>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 from Existing Account
|
|
||||||
</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" });
|
||||||
}
|
}
|
||||||
@@ -57,9 +41,5 @@ 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>
|
||||||
|
|||||||
@@ -62,15 +62,8 @@ export default class StatisticsView extends Vue {
|
|||||||
this.world = newWorld;
|
this.world = newWorld;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
this.$notify(
|
this.alertTitle = "Mounting error";
|
||||||
{
|
this.alertMessage = err.message;
|
||||||
group: "alert",
|
|
||||||
type: "danger",
|
|
||||||
title: "Mounting Error",
|
|
||||||
text: err.message,
|
|
||||||
},
|
|
||||||
-1,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user