Browse Source

add marker in feed to show where they've seen claims, plus other small clean-up

pull/23/head
Trent Larson 1 year ago
parent
commit
5747404fd6
  1. 29
      project.task.yaml
  2. 2
      src/db/tables/settings.ts
  3. 1
      src/router/index.ts
  4. 27
      src/views/AccountViewView.vue
  5. 10
      src/views/ContactAmountsView.vue
  6. 5
      src/views/ContactQRScanShowView.vue
  7. 22
      src/views/ContactsView.vue
  8. 39
      src/views/HomeView.vue
  9. 10
      src/views/NewEditProjectView.vue
  10. 5
      src/views/ProjectViewView.vue
  11. 5
      src/views/ProjectsView.vue
  12. 2
      src/views/StatisticsView.vue

29
project.task.yaml

@ -4,13 +4,14 @@
- add infinite scroll assignee:matthew
blocks: ref:https://raw.githubusercontent.com/trentlarson/lives-of-gifts/master/project.yaml#kickstarter%20for%20time
- allow type annotations in World.js & landmarks.js (since we get this error: "Types are not supported by current JavaScript version")
- allow type annotations in World.js & landmarks.js (since we get this error - "Types are not supported by current JavaScript version")
- replace user-affecting console.log & console.error with error messages (eg. catches)
- if there's no identity, handle it on pages which expect an identity (eg. project -- look for JSON.parse identity calls)
- stats v1 :
- 01 show numeric stats
- 01 link to world for specific stats
- .5 don't load another instance of a bush if it already exists
- show project activity :
- Save IDs of special projects of interest
- allow to give where a project is the provider
- allow to see activity where a project is provider
- contacts v1 :
- 01 Import contact info a la QR code.
@ -29,19 +30,26 @@
- show pop-up confirming that settings & contacts have been downloaded
- Ensure each action sent to the server has a confirmation.
- Ensure each action sent to the server has a confirmation - registration
- Home Feed & Quick Give screen
- Home Feed & Quick Give screen :
- 01 save the feed-viewed status in settings storage ("afterQuery")
- 01 quick action - send action, maybe choose via canvas tool https://github.com/konvajs/vue-konva
- .5 customize favicon
- .5 make advanced features harder to access; advanced build?
- 40 notifications
- pull, w/ scheduled runs
- 40 notifications :
- push
- stats v1 :
- 01 show numeric stats
- 01 link to world for specific stats
- .5 don't load another instance of a bush if it already exists
- Do we want split first name & last name?
- remove 'about' page
- Release Minimum Viable Product :
- Turn off stats-world or ensure it's usable (eg. cannot zoom out too far and lose world, cannot screenshot).
- Add disclaimers.
@ -51,6 +59,9 @@
- Ensure public server has limits that work for group adoption.
- Test PWA features on Android and iOS.
- 40 notifications v+ :
- pull, w/ scheduled runs
- Stats :
- 01 point out user's location on the world
- 01 present a credential selected from the stats

2
src/db/tables/settings.ts

@ -1,10 +1,12 @@
// a singleton
export type Settings = {
id: number; // there's only one entry: MASTER_SETTINGS_KEY
activeDid?: string;
apiServer?: string;
firstName?: string;
lastName?: string;
lastViewedClaimId?: string;
showContactGivesInline?: boolean;
};

1
src/router/index.ts

@ -132,6 +132,7 @@ const routes: Array<RouteRecordRaw> = [
name: "projects",
component: () =>
import(/* webpackChunkName: "projects" */ "../views/ProjectsView.vue"),
beforeEnter: enterOrStart,
},
{
path: "/seed-backup",

27
src/views/AccountViewView.vue

@ -289,10 +289,10 @@
</div>
<div>
<button class="text-blue-500 px-2">
<button class="text-blue-500">
<router-link
:to="{ name: 'statistics' }"
class="block text-center py-3 px-1"
class="block text-center py-3"
>
See Achievements & Statistics
</router-link>
@ -427,7 +427,10 @@ export default class AccountViewView extends Vue {
const accounts = await accountsDB.accounts.toArray();
const account = R.find((acc) => acc.did === this.activeDid, accounts);
const identity = JSON.parse(account?.identity || "undefined");
const identity = JSON.parse(account?.identity || "null");
if (!identity) {
throw new Error("No identity found.");
}
this.publicHex = identity.keys[0].publicKeyHex;
this.publicBase64 = Buffer.from(this.publicHex, "hex").toString("base64");
this.derivationPath = identity.keys[0].meta.derivationPath;
@ -437,8 +440,8 @@ export default class AccountViewView extends Vue {
});
} catch (err) {
this.alertMessage =
"Clear your cache and start over (after data backup). See console log for more info.";
console.error("Telling user to clear cache because:", err);
"Clear your cache and start over (after data backup).";
console.error("Telling user to clear cache at page create because:", err);
this.alertTitle = "Error Creating Account";
this.isAlertVisible = true;
}
@ -452,9 +455,12 @@ export default class AccountViewView extends Vue {
});
} catch (err) {
this.alertMessage =
"Clear your cache and start over (after data backup). See console log for more info.";
console.error("Telling user to clear cache because:", err);
this.alertTitle = "Error Creating Account";
"Clear your cache and start over (after data backup).";
console.error(
"Telling user to clear cache after contact setting update because:",
err
);
this.alertTitle = "Error Updating Contact Setting";
this.isAlertVisible = true;
}
}
@ -487,7 +493,10 @@ export default class AccountViewView extends Vue {
await accountsDB.open();
const accounts = await accountsDB.accounts.toArray();
const account = R.find((acc) => acc.did === this.activeDid, accounts);
const identity = JSON.parse(account?.identity || "undefined");
const identity = JSON.parse(account?.identity || "null");
if (!identity) {
throw new Error("No identity found.");
}
const token = await accessToken(identity);
const headers = {
"Content-Type": "application/json",

10
src/views/ContactAmountsView.vue

@ -168,7 +168,10 @@ export default class ContactsView extends Vue {
await accountsDB.open();
const accounts = await accountsDB.accounts.toArray();
const account = R.find((acc) => acc.did === activeDid, accounts);
const identity = JSON.parse(account?.identity || "undefined");
const identity = JSON.parse(account?.identity || "null");
if (!identity) {
throw new Error("No identity found.");
}
// load all the time I have given to them
try {
@ -267,7 +270,10 @@ export default class ContactsView extends Vue {
await accountsDB.open();
const accounts = await accountsDB.accounts.toArray();
const account = R.find((acc) => acc.did === this.activeDid, accounts);
const identity = JSON.parse(account?.identity || "undefined");
const identity = JSON.parse(account?.identity || "null");
if (!identity) {
throw new Error("No identity found.");
}
if (identity.keys[0].privateKeyHex !== null) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const privateKeyHex: string = identity.keys[0].privateKeyHex!;

5
src/views/ContactQRScanShowView.vue

@ -113,7 +113,10 @@ export default class ContactQRScanShow extends Vue {
if (!account) {
this.alertMessage = "You have no identity yet.";
} else {
const identity = JSON.parse(account.identity);
const identity = JSON.parse(account?.identity || "null");
if (!identity) {
throw new Error("No identity found.");
}
const publicKeyHex = identity.keys[0].publicKeyHex;
const publicEncKey = Buffer.from(publicKeyHex, "hex").toString("base64");

22
src/views/ContactsView.vue

@ -314,7 +314,7 @@ export default class ContactsView extends Vue {
await accountsDB.open();
const accounts = await accountsDB.accounts.toArray();
const account = R.find((acc) => acc.did === this.activeDid, accounts);
const identity = JSON.parse(account?.identity || "undefined");
const identity = JSON.parse(account?.identity || "null");
if (!identity) {
console.error(
@ -487,7 +487,10 @@ export default class ContactsView extends Vue {
await accountsDB.open();
const accounts = await accountsDB.accounts.toArray();
const account = R.find((acc) => acc.did === this.activeDid, accounts);
const identity = JSON.parse(account?.identity || "undefined");
const identity = JSON.parse(account?.identity || "null");
if (!identity) {
throw new Error("No identity found.");
}
// Make a claim
const vcClaim: RegisterVerifiableCredential = {
@ -567,7 +570,10 @@ export default class ContactsView extends Vue {
await accountsDB.open();
const accounts = await accountsDB.accounts.toArray();
const account = R.find((acc) => acc.did === this.activeDid, accounts);
const identity = JSON.parse(account?.identity || "undefined");
const identity = JSON.parse(account?.identity || "null");
if (!identity) {
throw new Error("No identity found.");
}
const token = await accessToken(identity);
const headers = {
@ -606,7 +612,10 @@ export default class ContactsView extends Vue {
await accountsDB.open();
const accounts = await accountsDB.accounts.toArray();
const account = R.find((acc) => acc.did === this.activeDid, accounts);
const identity = JSON.parse(account?.identity || "undefined");
const identity = JSON.parse(account?.identity || "null");
if (!identity) {
throw new Error("No identity found.");
}
const token = await accessToken(identity);
const headers = {
@ -663,7 +672,10 @@ export default class ContactsView extends Vue {
await accountsDB.open();
const accounts = await accountsDB.accounts.toArray();
const account = R.find((acc) => acc.did === this.activeDid, accounts);
const identity = JSON.parse(account?.identity || "undefined");
const identity = JSON.parse(account?.identity || "null");
if (!identity) {
throw new Error("No identity found.");
}
// if they have unconfirmed amounts, ask to confirm those first
if (toDid == identity?.did && this.givenToMeUnconfirmed[fromDid] > 0) {

39
src/views/HomeView.vue

@ -57,12 +57,12 @@
v-for="contact in allContacts"
:key="contact.did"
@click="openDialog(contact)"
style="color: blue"
class="text-blue-500"
>
&nbsp;{{ contact.name }},
</button>
or
<button @click="openDialog()" style="color: blue">
<button @click="openDialog()" class="text-blue-500">
nobody in particular
</button>
</div>
@ -85,8 +85,14 @@
<li
class="border-b border-slate-300"
v-for="record in feedData"
:key="record.id"
:key="record.jwtId"
>
<div
class="border-b text-orange-400 px-8 py-4"
v-if="record.jwtId == feedLastViewedId"
>
You've seen all claims below.
</div>
{{ this.giveDescription(record) }}
</li>
</ul>
@ -129,8 +135,8 @@ export default class HomeView extends Vue {
feedAllLoaded = false;
feedData = [];
feedPreviousOldestId = null;
feedLastViewedId = null;
isHiddenSpinner = true;
showInput = false;
// 'created' hook runs when the Vue instance is first created
async created() {
@ -140,6 +146,7 @@ export default class HomeView extends Vue {
const settings = await db.settings.get(MASTER_SETTINGS_KEY);
this.activeDid = settings?.activeDid || "";
this.allContacts = await db.contacts.toArray();
this.feedLastViewedId = settings?.lastViewedClaimId;
}
// 'mounted' hook runs after initial render
@ -168,7 +175,19 @@ export default class HomeView extends Vue {
this.feedData = this.feedData.concat(results.data);
//console.log("Feed data:", this.feedData);
this.feedAllLoaded = results.hitLimit;
this.feedPreviousOldestId = results.data[results.data.length - 1].id;
this.feedPreviousOldestId =
results.data[results.data.length - 1].jwtId;
if (
this.feedLastViewedId == null ||
this.feedLastViewedId < results.data[0].jwtId
) {
// save it to storage
await db.open();
db.settings.update(MASTER_SETTINGS_KEY, {
lastViewedClaimId: results.data[0].jwtId,
});
// but not for this page because we need to remember what it was before
}
}
})
.catch((e) => {
@ -190,7 +209,10 @@ export default class HomeView extends Vue {
this.allAccounts
);
//console.log("about to parse from", this.activeDid, account?.identity);
const identity = JSON.parse(account?.identity || "undefined");
const identity = JSON.parse(account?.identity || "null");
if (!identity) {
throw new Error("No identity found.");
}
const token = await accessToken(identity);
headers["Authorization"] = "Bearer " + token;
} else {
@ -278,7 +300,10 @@ export default class HomeView extends Vue {
this.allAccounts
);
//console.log("about to parse from", this.activeDid, account?.identity);
const identity = JSON.parse(account?.identity || "undefined");
const identity = JSON.parse(account?.identity || "null");
if (!identity) {
throw new Error("No identity found.");
}
createAndSubmitGive(
this.axios,
this.apiServer,

10
src/views/NewEditProjectView.vue

@ -127,7 +127,10 @@ export default class NewEditProjectView extends Vue {
} else {
const accounts = await accountsDB.accounts.toArray();
const account = R.find((acc) => acc.did === this.activeDid, accounts);
const identity = JSON.parse(account?.identity || "undefined");
const identity = JSON.parse(account?.identity || "null");
if (!identity) {
throw new Error("No identity found.");
}
this.LoadProject(identity);
}
}
@ -259,7 +262,10 @@ export default class NewEditProjectView extends Vue {
} else {
const accounts = await accountsDB.accounts.toArray();
const account = R.find((acc) => acc.did === this.activeDid, accounts);
const identity = JSON.parse(account?.identity || "undefined");
const identity = JSON.parse(account?.identity || "null");
if (!identity) {
throw new Error("No identity found.");
}
this.SaveProject(identity);
}
}

5
src/views/ProjectViewView.vue

@ -240,7 +240,10 @@ export default class ProjectViewView extends Vue {
} else {
const accounts = await accountsDB.accounts.toArray();
const account = R.find((acc) => acc.did === activeDid, accounts);
const identity = JSON.parse(account?.identity || "undefined");
const identity = JSON.parse(account?.identity || "null");
if (!identity) {
throw new Error("No identity found.");
}
this.LoadProject(identity);
}
}

5
src/views/ProjectsView.vue

@ -167,7 +167,10 @@ export default class ProjectsView extends Vue {
} else {
const accounts = await accountsDB.accounts.toArray();
const account = R.find((acc) => acc.did === activeDid, accounts);
const identity = JSON.parse(account?.identity || "undefined");
const identity = JSON.parse(account?.identity || "null");
if (!identity) {
throw new Error("No identity found.");
}
this.LoadProjects(identity);
}
}

2
src/views/StatisticsView.vue

@ -61,7 +61,7 @@
<!-- eslint-disable prettier/prettier --><!-- If we format prettier then there is extra space at the start of the line. -->
<li>Each will show at their time of appearance relative to all others.</li>
<li>Note that the ones on the left and right edges are randomized
because not all their positional data is visible to you.
because their data isn't all visible to you.
</li>
<!-- eslint-enable -->
</ul>

Loading…
Cancel
Save