much miscellany for small features and documentation & testing #82

Merged
anomalist merged 5 commits from many-misc into master 1 year ago
  1. 159
      README.md
  2. 43
      project.task.yaml
  3. 5
      src/views/AccountViewView.vue
  4. 15
      src/views/ContactQRScanShowView.vue
  5. 60
      src/views/ContactsView.vue
  6. 19
      src/views/DiscoverView.vue
  7. 106
      src/views/HelpView.vue
  8. 2
      src/views/HomeView.vue
  9. 16
      src/views/NewIdentifierView.vue
  10. 5
      src/views/SearchAreaView.vue
  11. 13
      src/views/StartView.vue
  12. 18
      src/views/StatisticsView.vue
  13. 16
      src/views/TestView.vue

159
README.md

@ -26,31 +26,13 @@ npm run build
npm run lint npm run lint
``` ```
## Tests
### Web-push
For your own web-push tests, change the 'vapid' URL in App.vue, and install apps on the same domain.
### Test key contents ## Tests
See [this page](openssl_signing_console.rst)
### Register new user on test server ### Register new user on test server
New users require registration. This can be done with a claim payload like this
by an existing user:
```
const vcClaim = {
"@context": "https://schema.org",
"@type": "RegisterAction",
agent: { identifier: identity0.did },
object: SERVICE_ID,
participant: { identifier: newIdentity.did },
};
```
On the test server, User #0 has rights to register others, so you can start On the test server, User #0 has rights to register others, so you can start
playing one of two ways: playing one of two ways:
@ -66,14 +48,35 @@ playing one of two ways:
### Create multiple identifiers ### Create multiple identifiers
Go to /start and create or import a new one. Then switch identifiers on the bottom of the Your Identity page. Under the "Your Identity" screen, click "Advanced", click "Switch Identity / No Identity", then "Add Another Identity...".
### Create keys with alternate tools ### Create keys with alternate tools
See [this page](openssl_signing_console.rst) [This page](openssl_signing_console.rst) is a tool to create a JWT from a locally-generated keypair.
### Web-push
For your own web-push tests, change the 'vapid' URL in App.vue, and install apps on the same domain.
### Manual walk-through
- Clear the browser cache for localhost for a new user.
- See that it's using the test API.
- On each page, verify the messaging.
- On the home page, see the feed without names, and see a message prompting to generate an ID.
- On the discovery page, check that they can see projects, and set a search area to see projects nearby.
- As User #0 in another browser on the test API, add a give & a project. (See User #0 details above.)
- With the new user on the home page, see the feed that shows User #0 in network but without the name.
- As the new user on the contacts page, add User #0 as a contact.
- On the home page, see the feed that shows User #0 with a name.
- Generate an ID.
- On the home page, check that it now prompts them to get registered.
- On the account page, check that they see messages on limits.
- Register the ID from User #0.
- As the new user on the home page, check that they can now record a gift.
- On the contacts page, check that they cannot register someone else yet.
- Walk through the functions on each page.
### Customize Vue configuration
See [Configuration Reference](https://cli.vuejs.org/config/).
## Scenarios ## Scenarios
@ -90,8 +93,8 @@ See [Configuration Reference](https://cli.vuejs.org/config/).
### Clear data & restart ### Clear data & restart
Clear cache for localhost, then go to http://localhost:8080/start Clear the browser cache for localhost.
(because it'll generate a new one automatically if you start on the `/account` page).
@ -102,110 +105,10 @@ Clear cache for localhost, then go to http://localhost:8080/start
* Notifications can be type of `toast` (self-dismiss), `info`, `success`, `warning`, and `danger`. * Notifications can be type of `toast` (self-dismiss), `info`, `success`, `warning`, and `danger`.
They are done via [notiwind](https://www.npmjs.com/package/notiwind) and set up in App.vue. They are done via [notiwind](https://www.npmjs.com/package/notiwind) and set up in App.vue.
``` * [Customize Vue configuration](https://cli.vuejs.org/config/).
// reference material from https://github.com/trentlarson/endorser-mobile/blob/8dc8e0353e0cc80ffa7ed89ded15c8b0da92726b/src/utility/idUtility.ts#L83
// Import an existing ID
export const importAndStoreIdentifier = async (mnemonic: string, mnemonicPassword: string, toLowercase: boolean, previousIdentifiers: Array<IIdentifier>) => {
// just to get rid of variability that might cause an error
mnemonic = mnemonic.trim().toLowerCase()
/**
// an approach I pieced together
// requires: yarn add elliptic
// ... plus:
// const EC = require('elliptic').ec
// const secp256k1 = new EC('secp256k1')
//
const keyHex: string = bip39.mnemonicToEntropy(mnemonic)
// returns a KeyPair from the elliptic.ec library
const keyPair = secp256k1.keyFromPrivate(keyHex, 'hex')
// this code is from did-provider-eth createIdentifier
const privateHex = keyPair.getPrivate('hex')
const publicHex = keyPair.getPublic('hex')
const address = didJwt.toEthereumAddress(publicHex)
**/
/**
// from https://github.com/uport-project/veramo/discussions/346#discussioncomment-302234
// ... which almost works but the didJwt.toEthereumAddress is wrong
// requires: yarn add bip32
// ... plus: import * as bip32 from 'bip32'
//
const seed: Buffer = await bip39.mnemonicToSeed(mnemonic)
const root = bip32.fromSeed(seed)
const node = root.derivePath(UPORT_ROOT_DERIVATION_PATH)
const privateHex = node.privateKey.toString("hex")
const publicHex = node.publicKey.toString("hex")
const address = didJwt.toEthereumAddress('0x' + publicHex)
**/
/**
// from https://github.com/uport-project/veramo/discussions/346#discussioncomment-302234
// requires: yarn add @ethersproject/hdnode
// ... plus: import { HDNode } from '@ethersproject/hdnode'
**/
const hdnode: HDNode = HDNode.fromMnemonic(mnemonic)
const rootNode: HDNode = hdnode.derivePath(UPORT_ROOT_DERIVATION_PATH)
const privateHex = rootNode.privateKey.substring(2) // original starts with '0x'
const publicHex = rootNode.publicKey.substring(2) // original starts with '0x'
let address = rootNode.address
const prevIds = previousIdentifiers || [];
if (toLowercase) {
const foundEqual = R.find(
(id) => utility.rawAddressOfDid(id.did) === address,
prevIds
)
if (foundEqual) {
// They're trying to create a lowercase version of one that exists in normal case.
// (We really should notify the user.)
appStore.dispatch(appSlice.actions.addLog({log: true, msg: "Will create a normal-case version of the DID since a regular version exists."}))
} else {
address = address.toLowerCase()
}
} else {
// They're not trying to convert to lowercase.
const foundLower = R.find((id) =>
utility.rawAddressOfDid(id.did) === address.toLowerCase(),
prevIds
)
if (foundLower) {
// They're trying to create a normal case version of one that exists in lowercase.
// (We really should notify the user.)
appStore.dispatch(appSlice.actions.addLog({log: true, msg: "Will create a lowercase version of the DID since a lowercase version exists."}))
address = address.toLowerCase()
}
}
appStore.dispatch(appSlice.actions.addLog({log: false, msg: "... derived keys and address..."}))
const newId = newIdentifier(address, publicHex, privateHex, UPORT_ROOT_DERIVATION_PATH)
appStore.dispatch(appSlice.actions.addLog({log: false, msg: "... created new ID..."}))
// awaiting because otherwise the UI may not see that a mnemonic was created
const savedId = await storeIdentifier(newId, mnemonic, mnemonicPassword)
appStore.dispatch(appSlice.actions.addLog({log: false, msg: "... stored new ID..."}))
return savedId
}
// Create a totally new ID
export const createAndStoreIdentifier = async (mnemonicPassword) => {
// This doesn't give us the entropy/seed.
//const id = await agent.didManagerCreate()
const entropy = crypto.randomBytes(32)
const mnemonic = bip39.entropyToMnemonic(entropy)
appStore.dispatch(appSlice.actions.addLog({log: false, msg: "... generated mnemonic..."}))
return importAndStoreIdentifier(mnemonic, mnemonicPassword, false, [])
}
```
## Kudos ### Kudos
Gifts make the world go 'round! Gifts make the world go 'round!

43
project.task.yaml

@ -5,41 +5,32 @@ tasks:
- 40 notifications : - 40 notifications :
- push, where we trigger a ServiceWorker(?) in the app to reach out and check for new data assignee:matthew - push, where we trigger a ServiceWorker(?) in the app to reach out and check for new data assignee:matthew
- 01 Ensure each action sent to the server has a confirmation - eg registration (ie a toast something that dismisses after 5-10s) - .5 add project ID to the URL of the project-view, to make a project publicly-accessible
- .5 add link to further project / people when a project pays ahead
- Home Feed & Quick Give screen : - .5 show checkbox on "gave" modal to say that user is recipient (so it could be uncheked for someone unspecified)
- 01 save the feed-viewed status in settings storage ("afterQuery")
- 01 quick action - send action, maybe choose via canvas tool
- SEE: https://github.com/konvajs/vue-konva
- 24 Move to Vite assignee:matthew
- .5 allow to manage their notifications even without an identity
- .5 bug - on the discover page, enter a search term and search and see a duplicate project show at the end of the list
- 01 Ensure each action sent to the server has a confirmation - eg registration (ie a toast something that dismisses after 5-10s)
- .3 fix the Project-location-selection map display to not show on top of bottom icons (and any other UI tweaks on the map flow) assignee-group:ui - .3 fix the Project-location-selection map display to not show on top of bottom icons (and any other UI tweaks on the map flow) assignee-group:ui
- .5 switch so DiscoverView shows anywhere by default, and no number unless search is done (and maybe a better filter UI, including "mine" to consolidate with ProjectsView)
- .5 Add infinite scroll to gifts on the home page - .5 Add infinite scroll to gifts on the home page
- .5 bug - search for "Safari" does not find the project, but if already on the "Anywhere" tab it shows all - .5 bug - search for "Safari" does not find the project, but if already on the "Anywhere" tab it shows all
- .2 figure out why endorser-mobile search doesn't find recently created PlanAction - .2 figure out why endorser-mobile search doesn't find recently created PlanAction
- .1 when creating a plan, select location and then make sure you can deselect on Android - .1 when creating a plan, select location and then make sure you can deselect on Android
- .5 add link to further project / people when a project pays ahead
- .5 add project ID to the URL of the project-view, to make a project publicly-accessible
- .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 on ProjectViewView, show different messages for "to" and "from" sections if none exist - .1 remove the logic to exclude beforeId in list of plans after server has commit 26b25af605e715600d4f12b6416ed9fd7142d164 assignee:trent
- .2 fix rate limit verbiage (with the new one-per-day allowance) assignee:trent
- .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" - .2 in SeedBackupView, don't load the mnemonic and keep it in memory; only load it when they click "show"
- .1 Make give description text box into something that expands as they type
- .1 Make contact info specific to Time Safari - rather pointing at CommunityCred.org
- Discuss whether the remaining tasks are worthwhile before MVP release. - Discuss whether the remaining tasks are worthwhile before MVP release.
- .1 Make give description text box into something that expands as they type?
- 04 allow user to download claims, mine + ones I can see about me from others - 04 allow user to download claims, mine + ones I can see about me from others
- 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 assignee-group:ui - .5 customize favicon assignee-group:ui
- .2 Show a warning if both giver and recipient are the same (but still allow?) - .2 Show a warning if both giver and recipient are the same (but still allow?)
- 01 Would it look better to shrink the buttons on many pages so they don't expand to the width of the screen? assignee-group:ui - 01 Would it look better to shrink the buttons on many pages so they don't expand to the width of the screen? assignee-group:ui
- .5 Display a more appealing confirmation on the map when erasing the marker - .5 Display a more appealing confirmation on the map when erasing the marker
- .5 make a VC details page - .5 make a VC details page, or link to endorser.ch
- .1 Add units or different icon to the coins (to distinguish $, BTC, hours, etc) - .1 Add units or different icon to the coins (to distinguish $, BTC, hours, etc)
- .5 include the hash of the latest commit on help page next to version - .5 include the hash of the latest commit on help page next to version
- .5 remove references to localStorage for projectId (now that it's pulling from the path) - .5 remove references to localStorage for projectId (now that it's pulling from the path)
@ -51,7 +42,7 @@ tasks:
- stats v1 : - stats v1 :
- 01 show numeric stats - 01 show numeric stats
- 04 show different graphic for projects vs people on world - 04 show different graphic for projects vs people (gnome?) on world
- 01 link to world for specific stats - 01 link to world for specific stats
- .5 don't load another instance of a bush if it already exists - .5 don't load another instance of a bush if it already exists
- 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")
@ -69,7 +60,9 @@ tasks:
blocks: ref:https://raw.githubusercontent.com/trentlarson/lives-of-gifts/master/project.yaml#kickstarter%20for%20time blocks: ref:https://raw.githubusercontent.com/trentlarson/lives-of-gifts/master/project.yaml#kickstarter%20for%20time
- .5 show seed phrase in a QR code for transfer to another device - .5 show seed phrase in a QR code for transfer to another device
- .5 on DiscoverView, switch to a filter UI (eg. just from friend
- 24 Move to Vite
- 32 accept images for projects - 32 accept images for projects
- 32 accept images for contacts - 32 accept images for contacts
@ -99,11 +92,10 @@ tasks:
- Multiple identities - Multiple identities
- Peer DID - Support KERI AIDs
- Support Peer DIDs
- DIDComm - Support messaging through DIDComm
- Write to or read from a different ledger (eg. private ACDC, EAS & attest.sh)
- Write to or read from a different ledger (eg. private ACDC, attest.sh)
- Do we want split first name & last name? - Do we want split first name & last name?
@ -111,6 +103,7 @@ tasks:
- pull, w/ scheduled runs - pull, w/ scheduled runs
- 01 On nearby search, if user starts changing their box but cancels and goes back to the map it is zoomed far out. Fix to fit the box better. - 01 On nearby search, if user starts changing their box but cancels and goes back to the map it is zoomed far out. Fix to fit the box better.
- 16 From the home screen, make the quick action even easier.
log: log:
- videos for multiple identities https://youtu.be/p8L87AeD76w and for adding time to contacts https://youtu.be/7Yylczevp10 done:2023-03-29 - videos for multiple identities https://youtu.be/p8L87AeD76w and for adding time to contacts https://youtu.be/7Yylczevp10 done:2023-03-29

5
src/views/AccountViewView.vue

@ -186,8 +186,9 @@
</p> </p>
<p> <p>
You have done {{ limits.doneRegistrationsThisMonth }} registrations You have done {{ limits.doneRegistrationsThisMonth }} registrations
out of {{ limits.maxRegistrationsPerMonth }} for this month. Your out of {{ limits.maxRegistrationsPerMonth }} for this month. (You can
registrations counter resets at register nobody on your first day, and after that only one a day in
your first month.) Your registration counter resets at
{{ readableTime(limits.nextMonthBeginDateTime) }} {{ readableTime(limits.nextMonthBeginDateTime) }}
</p> </p>
</div> </div>

15
src/views/ContactQRScanShowView.vue

@ -2,10 +2,23 @@
<QuickNav selected="Profile"></QuickNav> <QuickNav selected="Profile"></QuickNav>
<!-- CONTENT --> <!-- CONTENT -->
<section id="Content" class="p-6 pb-24"> <section id="Content" class="p-6 pb-24">
<!-- Breadcrumb -->
<div class="mb-8">
<!-- Back -->
<div class="text-lg text-center font-light relative px-7">
<h1
class="text-lg text-center px-2 py-1 absolute -left-2 -top-1"
@click="$router.back()"
>
<fa icon="chevron-left" class="fa-fw"></fa>
</h1>
</div>
<!-- Heading --> <!-- Heading -->
<h1 id="ViewHeading" class="text-4xl text-center font-light pt-4"> <h1 id="ViewHeading" class="text-4xl text-center font-light pt-4">
Your Contact Info Your Contact Info
</h1> </h1>
</div>
<!-- <!--
Play with display options: https://qr-code-styling.com/ Play with display options: https://qr-code-styling.com/
@ -137,7 +150,7 @@ export default class ContactQRScanShow extends Vue {
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
onScanDetect(content: any) { onScanDetect(content: any) {
if (content[0]?.rawValue) { if (content[0]?.rawValue) {
console.log("onDetect", content[0].rawValue); //console.log("onDetect", content[0].rawValue);
localStorage.setItem("contactEndorserUrl", content[0].rawValue); localStorage.setItem("contactEndorserUrl", content[0].rawValue);
this.$router.push({ name: "contacts" }); this.$router.push({ name: "contacts" });
} else { } else {

60
src/views/ContactsView.vue

@ -113,7 +113,7 @@
<button <button
v-if="contact.seesMe" v-if="contact.seesMe"
class="text-sm uppercase bg-slate-500 text-white px-2 py-1.5 rounded-md" class="text-sm uppercase bg-slate-500 text-white px-2 py-1.5 rounded-md"
@click="setVisibility(contact, false)" @click="setVisibility(contact, false, true)"
title="They can see you" title="They can see you"
> >
<fa icon="eye" class="fa-fw" /> <fa icon="eye" class="fa-fw" />
@ -121,7 +121,7 @@
<button <button
v-else v-else
class="text-sm uppercase bg-slate-500 text-white px-2 py-1.5 rounded-md" class="text-sm uppercase bg-slate-500 text-white px-2 py-1.5 rounded-md"
@click="setVisibility(contact, true)" @click="setVisibility(contact, true, true)"
title="They cannot see you" title="They cannot see you"
> >
<fa icon="eye-slash" class="fa-fw" /> <fa icon="eye-slash" class="fa-fw" />
@ -137,7 +137,7 @@
<button <button
@click="register(contact)" @click="register(contact)"
class="text-sm uppercase bg-slate-500 text-white px-2 py-1.5 rounded-md" class="text-sm uppercase bg-slate-500 text-white ml-6 px-2 py-1.5 rounded-md"
> >
<fa <fa
v-if="contact.registered" v-if="contact.registered"
@ -155,7 +155,7 @@
<button <button
@click="deleteContact(contact)" @click="deleteContact(contact)"
class="text-sm uppercase bg-red-600 text-white px-2 py-1.5 rounded-md" class="text-sm uppercase bg-red-600 text-white ml-24 px-2 py-1.5 rounded-md"
title="Delete" title="Delete"
> >
<fa icon="trash-can" class="fa-fw" /> <fa icon="trash-can" class="fa-fw" />
@ -531,6 +531,7 @@ export default class ContactsView extends Vue {
); );
return; return;
} }
newContact.seesMe = true; // since we will immediately set that on the server
return db.contacts return db.contacts
.add(newContact) .add(newContact)
.then(() => { .then(() => {
@ -539,12 +540,28 @@ export default class ContactsView extends Vue {
(a: Contact, b) => (a.name || "").localeCompare(b.name || ""), (a: Contact, b) => (a.name || "").localeCompare(b.name || ""),
allContacts, allContacts,
); );
this.setVisibility(newContact, true, false);
this.$notify( this.$notify(
{ {
group: "alert", group: "alert",
type: "success", type: "success",
title: "Contact added", title: "Contact Added",
text: newContact.name + " was added.", text:
newContact.name +
" was added, and your activity is visible to them.",
},
-1,
);
// putting this last so that it shows on the top
this.$notify(
{
group: "alert",
type: "info",
title: "New User?",
text:
"If " +
newContact.name +
" is a new user, be sure to register them.",
}, },
-1, -1,
); );
@ -556,7 +573,7 @@ export default class ContactsView extends Vue {
group: "alert", group: "alert",
type: "danger", type: "danger",
title: "Contact Not Added", title: "Contact Not Added",
text: "An error prevented importing.", text: "An error prevented this import.",
}, },
-1, -1,
); );
@ -566,11 +583,13 @@ export default class ContactsView extends Vue {
async deleteContact(contact: Contact) { async deleteContact(contact: Contact) {
if ( if (
confirm( confirm(
"Are you sure you want to delete " + "You should first make sure that your activity is no longer visible to them." +
" Note that this only deletes them from your contacts on this device." +
" \n\nAre you sure you want to remove " +
this.nameForDid(this.contacts, contact.did) + this.nameForDid(this.contacts, contact.did) +
" with DID " + " with DID " +
contact.did + contact.did +
" ?", " from your contact list?",
) )
) { ) {
await db.open(); await db.open();
@ -692,7 +711,11 @@ export default class ContactsView extends Vue {
} }
} }
async setVisibility(contact: Contact, visibility: boolean) { async setVisibility(
contact: Contact,
visibility: boolean,
showSuccessAlert: boolean,
) {
const url = const url =
this.apiServer + this.apiServer +
"/api/report/" + "/api/report/" +
@ -704,6 +727,21 @@ 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.status === 200) { if (resp.status === 200) {
if (showSuccessAlert) {
this.$notify(
{
group: "alert",
type: "success",
title: "Visibility Set",
text:
this.nameForDid(this.contacts, contact.did) +
" can " +
(visibility ? "" : "not ") +
"see your activity.",
},
-1,
);
}
contact.seesMe = visibility; contact.seesMe = visibility;
db.contacts.update(contact.did, { seesMe: visibility }); db.contacts.update(contact.did, { seesMe: visibility });
} else { } else {
@ -756,7 +794,7 @@ export default class ContactsView extends Vue {
{ {
group: "alert", group: "alert",
type: "info", type: "info",
title: "Refreshed", title: "Visibility Refreshed",
text: text:
this.nameForContact(contact, true) + this.nameForContact(contact, true) +
" can " + " can " +

19
src/views/DiscoverView.vue

@ -41,7 +41,7 @@
Nearby Nearby
<span <span
class="font-semibold text-sm bg-slate-200 px-1.5 py-0.5 rounded-md" class="font-semibold text-sm bg-slate-200 px-1.5 py-0.5 rounded-md"
>{{ localCount }}</span >{{ localCount > -1 ? localCount : "?" }}</span
> >
</a> </a>
</li> </li>
@ -59,7 +59,7 @@
Anywhere Anywhere
<span <span
class="font-semibold text-sm bg-slate-200 px-1.5 py-0.5 rounded-md" class="font-semibold text-sm bg-slate-200 px-1.5 py-0.5 rounded-md"
>{{ remoteCount }}</span >{{ remoteCount > -1 ? remoteCount : "?" }}</span
> >
</a> </a>
</li> </li>
@ -86,7 +86,7 @@
</div> </div>
<!-- Results List --> <!-- Results List -->
<InfiniteScroll @reached-bottom="loadMoreData" v-if="!isChoosingSearchBox"> <InfiniteScroll @reached-bottom="loadMoreData">
<ul> <ul>
<li <li
class="border-b border-slate-300" class="border-b border-slate-300"
@ -156,11 +156,10 @@ export default class DiscoverView extends Vue {
apiServer = ""; apiServer = "";
searchTerms = ""; searchTerms = "";
projects: ProjectData[] = []; projects: ProjectData[] = [];
isChoosingSearchBox = false;
isLocalActive = true; isLocalActive = true;
isRemoteActive = false; isRemoteActive = false;
localCount = 0; localCount = -1;
remoteCount = 0; remoteCount = -1;
searchBox: { name: string; bbox: BoundingBox } | null = null; searchBox: { name: string; bbox: BoundingBox } | null = null;
isLoading = false; isLoading = false;
@ -180,7 +179,13 @@ export default class DiscoverView extends Vue {
const allAccounts = await accountsDB.accounts.toArray(); const allAccounts = await accountsDB.accounts.toArray();
this.allMyDids = allAccounts.map((acc) => acc.did); this.allMyDids = allAccounts.map((acc) => acc.did);
this.searchLocal(); if (this.searchBox) {
await this.searchLocal();
} else {
this.isLocalActive = false;
this.isRemoteActive = true;
await this.searchAll();
}
} }
public async buildHeaders(): Promise<HeadersInit> { public async buildHeaders(): Promise<HeadersInit> {

106
src/views/HelpView.vue

@ -1,11 +1,25 @@
<template> <template>
<QuickNav selected="Profile"></QuickNav> <QuickNav />
<!-- CONTENT --> <!-- CONTENT -->
<section id="Content" class="p-6 pb-24"> <section id="Content" class="p-6 pb-24">
<!-- Breadcrumb -->
<div class="mb-8">
<!-- Back -->
<div class="text-lg text-center font-light relative px-7">
<h1
class="text-lg text-center px-2 py-1 absolute -left-2 -top-1"
@click="$router.back()"
>
<fa icon="chevron-left" class="fa-fw"></fa>
</h1>
</div>
<!-- Heading --> <!-- Heading -->
<h1 id="ViewHeading" class="text-4xl text-center font-light pt-4 mb-8"> <h1 id="ViewHeading" class="text-4xl text-center font-light pt-4 mb-8">
Help Help
</h1> </h1>
</div>
<div> <div>
<p> <p>
@ -15,7 +29,7 @@
<h2 class="text-xl font-semibold">What is the philosophy here?</h2> <h2 class="text-xl font-semibold">What is the philosophy here?</h2>
<p> <p>
We are building networks of people who want to grow a gifting society. We are building networks of people who want to grow a giving society.
First of all, you can record ways you've seen people give, and that First of all, you can record ways you've seen people give, and that
leaves a permanent record -- one that came from you, and the recipient leaves a permanent record -- one that came from you, and the recipient
can prove it was for them. This is personally gratifying, but it extends can prove it was for them. This is personally gratifying, but it extends
@ -36,22 +50,39 @@
the control; this app gives you the control. the control; this app gives you the control.
</p> </p>
<h2 class="text-xl font-semibold">How do I take my first action?</h2> <h2 class="text-xl font-semibold">How do I get started?</h2>
<p> <p>
You need someone to register you -- usually the person who told you You need someone to register you -- usually the person who told you
about this app, on the Contacts about this app, on the Contacts
<fa icon="circle-user" class="fa-fw" /> page. After they register you, <fa icon="users" class="fa-fw" /> page. After they register you, you can
you can select any contact on the home page (or "anonymous") and record select any contact on the home page (or "anonymous") and record your
your appreciation for... whatever. The main goal is to record what appreciation for... whatever. The main goal is to record what people
people have given you, to grow gifting economies. Each claim is recorded have given you, to grow giving economies. Each claim is recorded on a
on a custom ledger. The day after being registered, you'll be able to custom ledger. The day after being registered, you'll be able to able to
able to register others; later, you can create projects, too. register others; later, you can create projects, too.
</p> </p>
<p> <p>
Note that there are limits to how many others each person can register, Note that there are limits to how many others each person can register,
so you may have to wait. so you may have to wait.
</p> </p>
<h2 class="text-xl font-semibold">How do I add someone else?</h2>
<p>
<button class="text-blue-500" @click="showOnboardInfo">
Click here to show an alert with the steps.
</button>
To start scanning, go
<router-link class="text-blue-500" to="/contact-qr">here.</router-link>
</p>
<p>
If they are not nearby to scan QR codes, tell them to copy their ID from
their Identity <fa icon="circle-user" class="fa-fw" /> page, which
typically starts with "did:ethr:...", and send it to you. Go to the
Contacts <fa icon="users" class="fa-fw" /> page and enter that into the
top form. To add a name, put a comma and then their name; to add their
public key, put another comma followed by the key.
</p>
<h2 class="text-xl font-semibold">How do I backup all my data?</h2> <h2 class="text-xl font-semibold">How do I backup all my data?</h2>
<p> <p>
There are two sets of data to backup: the identifier secrets and the There are two sets of data to backup: the identifier secrets and the
@ -113,27 +144,20 @@
How do I restore my other (non-identifier-secret) data? How do I restore my other (non-identifier-secret) data?
</h2> </h2>
<ul class="list-disc list-inside"> <ul class="list-disc list-inside">
<li>Make sure you have your backup file (above), then contact us.</li> <li>
Make sure you have your backup file (above), then contact us with
your interest. This is functionality that has to be written, and
your interest will help us prioritize it, but there are also manual
ways to restore your data.
</li>
</ul> </ul>
</div> </div>
<h2 class="text-xl font-semibold">
How do I add someone to my contacts?
</h2>
<p>
Tell them to copy their ID, which typically starts with "did:ethr:...",
and send it to you. Go to the Contacts
<fa icon="circle-user" class="fa-fw" /> page and enter that into the top
form. You may add a name by adding a comma followed by their name; you
may also add their public key by adding another comma followed by the
key.
</p>
<h2 class="text-xl font-semibold">How do I create another identity?</h2> <h2 class="text-xl font-semibold">How do I create another identity?</h2>
<p> <p>
Before doing this, note that it is an advanced feature that affects Before doing this, note that it is an advanced feature that affects
functionality (eg. the words "Alt ID" next to results, backup features) functionality (eg. the words "Alt ID" next to results, backup features)
so beware if you think that may cause confusion. You can so beware. You can
<router-link to="start" class="text-blue-500"> <router-link to="start" class="text-blue-500">
create another identity here. create another identity here.
</router-link> </router-link>
@ -151,10 +175,10 @@
<fa icon="eye-slash" class="fa-fw" />. <fa icon="eye-slash" class="fa-fw" />.
</p> </p>
<p> <p>
Sometimes the reason you don't see something is because the search time Sometimes the reason you don't see something is because the search
is limited. Go to the bottom and make sure to load all the data on a results are limited. Go to the bottom and make sure to load all the data
list. If you still don't see it, try a search or view on a different on a list. If you still don't see it, try a search or view on a
page. different page.
</p> </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>
@ -171,11 +195,11 @@
</p> </p>
<h2 class="text-xl font-semibold"> <h2 class="text-xl font-semibold">
For any other questions, including remove your data: For any other questions, including removing your data:
</h2> </h2>
<p> <p>
Contact us through Contact us at
<a href="https://communitycred.org">CommunityCred.org</a>. <a mailto="info@TimeSafari.app">info@TimeSafari.app</a>
</p> </p>
</div> </div>
</section> </section>
@ -186,8 +210,30 @@ import * as Package from "../../package.json";
import { Component, Vue } from "vue-facing-decorator"; import { Component, Vue } from "vue-facing-decorator";
import QuickNav from "@/components/QuickNav.vue"; import QuickNav from "@/components/QuickNav.vue";
interface Notification {
group: string;
type: string;
title: string;
text: string;
}
@Component({ components: { QuickNav } }) @Component({ components: { QuickNav } })
export default class Help extends Vue { export default class Help extends Vue {
$notify!: (notification: Notification, timeout?: number) => void;
package = Package; package = Package;
showOnboardInfo() {
this.$notify(
{
group: "alert",
type: "info",
title: "Onboard Someone",
// If you edit this, check that the numbers still line up on the side in the alert (on mobile, preferably).
text: "1) Check that they've entered their name. 2) Go to the scanning page via the Identity page and then the through the QR icon at the top, and then scan and register them. 3) Have them go to that page and scan you.",
},
-1,
);
}
} }
</script> </script>

2
src/views/HomeView.vue

@ -29,7 +29,7 @@
<div v-else> <div v-else>
<!-- activeDid && isRegistered --> <!-- activeDid && isRegistered -->
<h2 class="text-xl font-bold">Record a Gift</h2> <h2 class="text-xl font-bold">Record Something Given</h2>
<ul class="grid grid-cols-4 gap-x-3 gap-y-5 text-center mb-5"> <ul class="grid grid-cols-4 gap-x-3 gap-y-5 text-center mb-5">
<li @click="openDialog()"> <li @click="openDialog()">

16
src/views/NewIdentifierView.vue

@ -1,11 +1,25 @@
<template> <template>
<QuickNav selected="Profile"></QuickNav> <QuickNav />
<!-- CONTENT --> <!-- CONTENT -->
<section id="Content" class="p-6 pb-24"> <section id="Content" class="p-6 pb-24">
<!-- Breadcrumb -->
<div class="mb-8">
<!-- Back -->
<div class="text-lg text-center font-light relative px-7">
<h1
class="text-lg text-center px-2 py-1 absolute -left-2 -top-1"
@click="$router.back()"
>
<fa icon="chevron-left" class="fa-fw"></fa>
</h1>
</div>
<!-- Heading --> <!-- Heading -->
<h1 id="ViewHeading" class="text-4xl text-center font-light pt-4 mb-8"> <h1 id="ViewHeading" class="text-4xl text-center font-light pt-4 mb-8">
Your Identity Your Identity
</h1> </h1>
</div>
<div class="flex justify-center py-12"> <div class="flex justify-center py-12">
<span /> <span />

5
src/views/SearchAreaView.vue

@ -1,4 +1,6 @@
<template> <template>
<QuickNav />
<!-- CONTENT --> <!-- CONTENT -->
<section id="Content" class="p-6 pb-24"> <section id="Content" class="p-6 pb-24">
<!-- Breadcrumb --> <!-- Breadcrumb -->
@ -105,6 +107,7 @@ import {
import { db } from "@/db/index"; import { db } from "@/db/index";
import { BoundingBox, MASTER_SETTINGS_KEY } from "@/db/tables/settings"; import { BoundingBox, MASTER_SETTINGS_KEY } from "@/db/tables/settings";
import QuickNav from "@/components/QuickNav.vue";
const DEFAULT_LAT_LONG_DIFF = 0.01; const DEFAULT_LAT_LONG_DIFF = 0.01;
const WORLD_ZOOM = 2; const WORLD_ZOOM = 2;
@ -119,6 +122,7 @@ interface Notification {
@Component({ @Component({
components: { components: {
QuickNav,
LRectangle, LRectangle,
LMap, LMap,
LMarker, LMarker,
@ -214,6 +218,7 @@ export default class DiscoverView extends Vue {
}, },
-1, -1,
); );
this.$router.back();
} catch (err) { } catch (err) {
this.$notify( this.$notify(
{ {

13
src/views/StartView.vue

@ -3,10 +3,23 @@
id="Content" id="Content"
class="p-6 pb-24 min-h-screen flex flex-col justify-center" class="p-6 pb-24 min-h-screen flex flex-col justify-center"
> >
<!-- Breadcrumb -->
<div class="mb-8">
<!-- Back -->
<div class="text-lg text-center font-light relative px-7">
<h1
class="text-lg text-center px-2 py-1 absolute -left-2 -top-1"
@click="$router.back()"
>
<fa icon="chevron-left" class="fa-fw"></fa>
</h1>
</div>
<!-- Heading --> <!-- Heading -->
<h1 id="ViewHeading" class="text-4xl text-center font-light pt-4 mb-8"> <h1 id="ViewHeading" class="text-4xl text-center font-light pt-4 mb-8">
Start Here Start Here
</h1> </h1>
</div>
<!-- id used by puppeteer test script --> <!-- id used by puppeteer test script -->
<div id="start-question" class="mt-8"> <div id="start-question" class="mt-8">

18
src/views/StatisticsView.vue

@ -1,11 +1,25 @@
<template> <template>
<QuickNav selected="Profile"></QuickNav> <QuickNav />
<!-- CONTENT --> <!-- CONTENT -->
<section id="Content" class="p-6 pb-24"> <section id="Content" class="p-6 pb-24">
<!-- Breadcrumb -->
<div class="mb-8">
<!-- Back -->
<div class="text-lg text-center font-light relative px-7">
<h1
class="text-lg text-center px-2 py-1 absolute -left-2 -top-1"
@click="$router.back()"
>
<fa icon="chevron-left" class="fa-fw"></fa>
</h1>
</div>
<!-- Heading --> <!-- Heading -->
<h1 id="ViewHeading" class="text-4xl text-center font-light pt-4 mb-8"> <h1 id="ViewHeading" class="text-4xl text-center font-light pt-4 mb-8">
Achievements & Statistics Achievements & Statistics
</h1> </h1>
</div>
<div> <div>
Here is a view of the activity you can see. Here is a view of the activity you can see.
@ -32,7 +46,7 @@
{{ worldProperties.animationDurationSeconds }} seconds {{ worldProperties.animationDurationSeconds }} seconds
</div> </div>
</div> </div>
<button class="float-right" @click="captureGraphics()">Screenshot</button> <button class="float-right text-blue-600" @click="captureGraphics()">Screenshot</button>
<div id="scene-container" class="h-screen"></div> <div id="scene-container" class="h-screen"></div>
</section> </section>
</template> </template>

16
src/views/TestView.vue

@ -1,11 +1,25 @@
<template> <template>
<QuickNav selected="Profile"></QuickNav> <QuickNav />
<!-- CONTENT --> <!-- CONTENT -->
<section id="Content" class="p-6 pb-24"> <section id="Content" class="p-6 pb-24">
<!-- Breadcrumb -->
<div class="mb-8">
<!-- Back -->
<div class="text-lg text-center font-light relative px-7">
<h1
class="text-lg text-center px-2 py-1 absolute -left-2 -top-1"
@click="$router.back()"
>
<fa icon="chevron-left" class="fa-fw"></fa>
</h1>
</div>
<!-- Heading --> <!-- Heading -->
<h1 id="ViewHeading" class="text-4xl text-center font-light pt-4 mb-8"> <h1 id="ViewHeading" class="text-4xl text-center font-light pt-4 mb-8">
Test Test
</h1> </h1>
</div>
<div class="mb-8"> <div class="mb-8">
<h2 class="text-xl font-bold mb-4">Notiwind Alert Test Suite</h2> <h2 class="text-xl font-bold mb-4">Notiwind Alert Test Suite</h2>

Loading…
Cancel
Save