Browse Source

filter by selections (now all working), add cache for plans

kb/add-usage-guide
Trent Larson 6 months ago
parent
commit
640d273646
  1. 1
      babel.config.js
  2. 149
      package-lock.json
  3. 1
      package.json
  4. 5
      project.task.yaml
  5. 50
      src/components/FeedFilters.vue
  6. 8
      src/db/tables/settings.ts
  7. 94
      src/libs/endorserServer.ts
  8. 14
      src/libs/util.ts
  9. 10
      src/views/ContactAmountsView.vue
  10. 4
      src/views/ContactsView.vue
  11. 113
      src/views/HomeView.vue
  12. 30
      src/views/ProjectViewView.vue
  13. 4
      src/views/ProjectsView.vue
  14. 6
      src/views/QuickActionBvcEndView.vue
  15. 2
      src/views/SearchAreaView.vue

1
babel.config.js

@ -1,3 +1,4 @@
module.exports = { module.exports = {
plugins: ["@babel/plugin-transform-private-methods"],
presets: ["@vue/cli-plugin-babel/preset"], presets: ["@vue/cli-plugin-babel/preset"],
}; };

149
package-lock.json

@ -42,6 +42,7 @@
"js-generate-password": "^0.1.9", "js-generate-password": "^0.1.9",
"js-yaml": "^4.1.0", "js-yaml": "^4.1.0",
"localstorage-slim": "^2.5.0", "localstorage-slim": "^2.5.0",
"lru-cache": "^10.2.0",
"luxon": "^3.4.4", "luxon": "^3.4.4",
"merkletreejs": "^0.3.11", "merkletreejs": "^0.3.11",
"moment": "^2.29.4", "moment": "^2.29.4",
@ -3052,6 +3053,18 @@
"integrity": "sha512-0CNTVCLZggSh7bc5VkX5WWPWO+cyZbNd07IHIsSXLia/eAq+r836hgk+8BKoEh7949Mda87VUOitx5OddVj64A==", "integrity": "sha512-0CNTVCLZggSh7bc5VkX5WWPWO+cyZbNd07IHIsSXLia/eAq+r836hgk+8BKoEh7949Mda87VUOitx5OddVj64A==",
"optional": true "optional": true
}, },
"node_modules/@digitalcredentials/jsonld/node_modules/lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"optional": true,
"dependencies": {
"yallist": "^4.0.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/@digitalcredentials/keypair": { "node_modules/@digitalcredentials/keypair": {
"version": "1.0.5", "version": "1.0.5",
"resolved": "https://registry.npmjs.org/@digitalcredentials/keypair/-/keypair-1.0.5.tgz", "resolved": "https://registry.npmjs.org/@digitalcredentials/keypair/-/keypair-1.0.5.tgz",
@ -3149,6 +3162,18 @@
"integrity": "sha512-0CNTVCLZggSh7bc5VkX5WWPWO+cyZbNd07IHIsSXLia/eAq+r836hgk+8BKoEh7949Mda87VUOitx5OddVj64A==", "integrity": "sha512-0CNTVCLZggSh7bc5VkX5WWPWO+cyZbNd07IHIsSXLia/eAq+r836hgk+8BKoEh7949Mda87VUOitx5OddVj64A==",
"optional": true "optional": true
}, },
"node_modules/@digitalcredentials/vc-status-list/node_modules/lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"optional": true,
"dependencies": {
"yallist": "^4.0.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/@discoveryjs/json-ext": { "node_modules/@discoveryjs/json-ext": {
"version": "0.5.7", "version": "0.5.7",
"resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz",
@ -4317,6 +4342,19 @@
"node": ">=4" "node": ">=4"
} }
}, },
"node_modules/@expo/cli/node_modules/lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"optional": true,
"peer": true,
"dependencies": {
"yallist": "^4.0.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/@expo/cli/node_modules/mimic-fn": { "node_modules/@expo/cli/node_modules/mimic-fn": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz",
@ -4714,6 +4752,19 @@
"url": "https://github.com/sponsors/isaacs" "url": "https://github.com/sponsors/isaacs"
} }
}, },
"node_modules/@expo/config/node_modules/lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"optional": true,
"peer": true,
"dependencies": {
"yallist": "^4.0.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/@expo/config/node_modules/resolve-from": { "node_modules/@expo/config/node_modules/resolve-from": {
"version": "5.0.0", "version": "5.0.0",
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
@ -8912,6 +8963,18 @@
"node": ">=12" "node": ">=12"
} }
}, },
"node_modules/@transmute/jsonld/node_modules/lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"optional": true,
"dependencies": {
"yallist": "^4.0.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/@transmute/ld-key-pair": { "node_modules/@transmute/ld-key-pair": {
"version": "0.7.0-unstable.81", "version": "0.7.0-unstable.81",
"resolved": "https://registry.npmjs.org/@transmute/ld-key-pair/-/ld-key-pair-0.7.0-unstable.81.tgz", "resolved": "https://registry.npmjs.org/@transmute/ld-key-pair/-/ld-key-pair-0.7.0-unstable.81.tgz",
@ -9674,6 +9737,18 @@
"integrity": "sha512-0CNTVCLZggSh7bc5VkX5WWPWO+cyZbNd07IHIsSXLia/eAq+r836hgk+8BKoEh7949Mda87VUOitx5OddVj64A==", "integrity": "sha512-0CNTVCLZggSh7bc5VkX5WWPWO+cyZbNd07IHIsSXLia/eAq+r836hgk+8BKoEh7949Mda87VUOitx5OddVj64A==",
"optional": true "optional": true
}, },
"node_modules/@veramo-community/lds-ecdsa-secp256k1-recovery2020/node_modules/lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"optional": true,
"dependencies": {
"yallist": "^4.0.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/@veramo/core": { "node_modules/@veramo/core": {
"version": "5.5.3", "version": "5.5.3",
"resolved": "https://registry.npmjs.org/@veramo/core/-/core-5.5.3.tgz", "resolved": "https://registry.npmjs.org/@veramo/core/-/core-5.5.3.tgz",
@ -10378,6 +10453,18 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/@vue/cli-shared-utils/node_modules/lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"dev": true,
"dependencies": {
"yallist": "^4.0.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/@vue/cli-shared-utils/node_modules/supports-color": { "node_modules/@vue/cli-shared-utils/node_modules/supports-color": {
"version": "7.2.0", "version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
@ -12425,6 +12512,19 @@
"node": ">= 10" "node": ">= 10"
} }
}, },
"node_modules/cacache/node_modules/lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"optional": true,
"peer": true,
"dependencies": {
"yallist": "^4.0.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/cacache/node_modules/mkdirp": { "node_modules/cacache/node_modules/mkdirp": {
"version": "1.0.4", "version": "1.0.4",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
@ -17014,6 +17114,19 @@
"node": ">=10" "node": ">=10"
} }
}, },
"node_modules/hosted-git-info/node_modules/lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"optional": true,
"peer": true,
"dependencies": {
"yallist": "^4.0.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/hpack.js": { "node_modules/hpack.js": {
"version": "2.1.6", "version": "2.1.6",
"resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz",
@ -19269,6 +19382,18 @@
"integrity": "sha512-0CNTVCLZggSh7bc5VkX5WWPWO+cyZbNd07IHIsSXLia/eAq+r836hgk+8BKoEh7949Mda87VUOitx5OddVj64A==", "integrity": "sha512-0CNTVCLZggSh7bc5VkX5WWPWO+cyZbNd07IHIsSXLia/eAq+r836hgk+8BKoEh7949Mda87VUOitx5OddVj64A==",
"optional": true "optional": true
}, },
"node_modules/jsonld/node_modules/lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"optional": true,
"dependencies": {
"yallist": "^4.0.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/jsonpointer": { "node_modules/jsonpointer": {
"version": "5.0.1", "version": "5.0.1",
"resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz", "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz",
@ -20246,15 +20371,11 @@
} }
}, },
"node_modules/lru-cache": { "node_modules/lru-cache": {
"version": "6.0.0", "version": "10.2.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==",
"devOptional": true,
"dependencies": {
"yallist": "^4.0.0"
},
"engines": { "engines": {
"node": ">=10" "node": "14 || >=16.14"
} }
}, },
"node_modules/luxon": { "node_modules/luxon": {
@ -25124,6 +25245,18 @@
"node": ">=10" "node": ">=10"
} }
}, },
"node_modules/semver/node_modules/lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"devOptional": true,
"dependencies": {
"yallist": "^4.0.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/send": { "node_modules/send": {
"version": "0.18.0", "version": "0.18.0",
"resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",

1
package.json

@ -42,6 +42,7 @@
"js-generate-password": "^0.1.9", "js-generate-password": "^0.1.9",
"js-yaml": "^4.1.0", "js-yaml": "^4.1.0",
"localstorage-slim": "^2.5.0", "localstorage-slim": "^2.5.0",
"lru-cache": "^10.2.0",
"luxon": "^3.4.4", "luxon": "^3.4.4",
"merkletreejs": "^0.3.11", "merkletreejs": "^0.3.11",
"moment": "^2.29.4", "moment": "^2.29.4",

5
project.task.yaml

@ -1,10 +1,13 @@
tasks : tasks :
- fix the notification link to the app
- 24 contextual tutorials https://docs.google.com/document/d/11C_K3RM0rgo0onih20KFhcIzukZyq_CRWqaWX5om_kM/edit#heading=h.iwiwcydou5hw - 24 contextual tutorials https://docs.google.com/document/d/11C_K3RM0rgo0onih20KFhcIzukZyq_CRWqaWX5om_kM/edit#heading=h.iwiwcydou5hw
- 24 Move to Vite - 24 Move to Vite
- feeds - add "remote" filter, if they choose 'visible' then warn that they won't see any others, cache list & don't reload front page on change
- .1 add KindSpring link to ideas - .1 add KindSpring link to ideas
- .1 on feed, don't show "to someone anonymous" if it's to a project - .1 on feed, don't show "to someone anonymous" if it's to a project
- .1 on ideas, put an "x" to close it assignee-group:ui - .1 on ideas, put an "x" to close it assignee-group:ui
@ -122,7 +125,7 @@ tasks :
- 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 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 - .5 on DiscoverView, switch to a filter UI (eg. just from friend)
- .5 don't show "Offer" on project screen if they aren't registered - .5 don't show "Offer" on project screen if they aren't registered
- 01 especially for iOS, check for new version & update, eg. https://stackoverflow.com/questions/52221805/any-way-yet-to-auto-update-or-just-clear-the-cache-on-a-pwa-on-ios - 01 especially for iOS, check for new version & update, eg. https://stackoverflow.com/questions/52221805/any-way-yet-to-auto-update-or-just-clear-the-cache-on-a-pwa-on-ios

50
src/components/FeedFilters.vue

@ -3,21 +3,21 @@
<div class="dialog"> <div class="dialog">
<h1 class="text-xl font-bold text-center mb-4">Feed Filters</h1> <h1 class="text-xl font-bold text-center mb-4">Feed Filters</h1>
<p class="mb-4 font-bold">Show only activities that are</p> <p class="mb-4 font-bold">Show only activities that</p>
<div class="grid grid-cols-1 gap-2"> <div class="grid grid-cols-1 gap-2">
<div <div
class="flex items-center justify-between cursor-pointer" class="flex items-center justify-between cursor-pointer"
@click="toggleContacts()" @click="toggleHasVisibleDid()"
> >
<!-- label --> <!-- label -->
<div>From my contacts</div> <div>Include Someone Visible to Me</div>
<!-- toggle --> <!-- toggle -->
<div class="relative ml-2"> <div class="relative ml-2">
<!-- input --> <!-- input -->
<input <input
type="checkbox" type="checkbox"
v-model="isInMyContacts" v-model="hasVisibleDid"
name="toggleFilterFromMyContacts" name="toggleFilterFromMyContacts"
class="sr-only" class="sr-only"
/> />
@ -30,6 +30,8 @@
</div> </div>
</div> </div>
<em>or</em>
<div <div
class="flex items-center justify-between cursor-pointer" class="flex items-center justify-between cursor-pointer"
@click=" @click="
@ -39,7 +41,7 @@
" "
> >
<!-- label --> <!-- label -->
<div>Nearby</div> <div>Are Nearby</div>
<!-- toggle --> <!-- toggle -->
<div v-if="hasSearchBox" class="relative ml-2"> <div v-if="hasSearchBox" class="relative ml-2">
<!-- input --> <!-- input -->
@ -109,20 +111,20 @@ import { db } from "@/db/index";
}, },
}) })
export default class FeedFilters extends Vue { export default class FeedFilters extends Vue {
callOnCloseIfChanged = () => {}; onCloseIfChanged = () => {};
hasSearchBox = false; hasSearchBox = false;
isInMyContacts = false; hasVisibleDid = false;
isNearby = false; isNearby = false;
settingChanged = false; settingChanged = false;
visible = false; visible = false;
async open(callOnCloseIfChanged: () => void) { async open(onCloseIfChanged: () => void) {
this.callOnCloseIfChanged = callOnCloseIfChanged; this.onCloseIfChanged = onCloseIfChanged;
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.isInMyContacts = !!settings?.filterFeedContacts; this.hasVisibleDid = !!settings?.filterFeedByVisible;
this.isNearby = !!settings?.filterFeedNearby; this.isNearby = !!settings?.filterFeedByNearby;
if (settings?.searchBoxes && settings.searchBoxes.length > 0) { if (settings?.searchBoxes && settings.searchBoxes.length > 0) {
this.hasSearchBox = true; this.hasSearchBox = true;
} }
@ -131,11 +133,11 @@ export default class FeedFilters extends Vue {
this.visible = true; this.visible = true;
} }
toggleContacts() { toggleHasVisibleDid() {
this.settingChanged = true; this.settingChanged = true;
this.isInMyContacts = !this.isInMyContacts; this.hasVisibleDid = !this.hasVisibleDid;
db.settings.update(MASTER_SETTINGS_KEY, { db.settings.update(MASTER_SETTINGS_KEY, {
filterFeedContacts: this.isInMyContacts, filterFeedByVisible: this.hasVisibleDid,
}); });
} }
@ -143,41 +145,41 @@ export default class FeedFilters extends Vue {
this.settingChanged = true; this.settingChanged = true;
this.isNearby = !this.isNearby; this.isNearby = !this.isNearby;
db.settings.update(MASTER_SETTINGS_KEY, { db.settings.update(MASTER_SETTINGS_KEY, {
filterFeedNearby: this.isNearby, filterFeedByNearby: this.isNearby,
}); });
} }
async clearAll() { async clearAll() {
if (this.isInMyContacts || this.isNearby) { if (this.hasVisibleDid || this.isNearby) {
this.settingChanged = true; this.settingChanged = true;
} }
db.settings.update(MASTER_SETTINGS_KEY, { db.settings.update(MASTER_SETTINGS_KEY, {
filterFeedNearby: false, filterFeedByNearby: false,
filterFeedContacts: false, filterFeedByVisible: false,
}); });
this.isInMyContacts = false; this.hasVisibleDid = false;
this.isNearby = false; this.isNearby = false;
} }
async setAll() { async setAll() {
if (!this.isInMyContacts || !this.isNearby) { if (!this.hasVisibleDid || !this.isNearby) {
this.settingChanged = true; this.settingChanged = true;
} }
db.settings.update(MASTER_SETTINGS_KEY, { db.settings.update(MASTER_SETTINGS_KEY, {
filterFeedNearby: true, filterFeedByNearby: true,
filterFeedContacts: true, filterFeedByVisible: true,
}); });
this.isInMyContacts = true; this.hasVisibleDid = true;
this.isNearby = true; this.isNearby = true;
} }
close() { close() {
if (this.settingChanged) { if (this.settingChanged) {
this.callOnCloseIfChanged(); this.onCloseIfChanged();
} }
this.visible = false; this.visible = false;
} }

8
src/db/tables/settings.ts

@ -17,8 +17,8 @@ export type Settings = {
activeDid?: string; // Active Decentralized ID activeDid?: string; // Active Decentralized ID
apiServer?: string; // API server URL apiServer?: string; // API server URL
filterFeedNearby?: string; // filter by nearby filterFeedByNearby?: boolean; // filter by nearby
filterFeedContacts?: string; // filter by user contacts filterFeedByVisible?: boolean; // filter by visible users ie. anyone not hidden
firstName?: string; // User's first name firstName?: string; // User's first name
isRegistered?: boolean; isRegistered?: boolean;
@ -42,6 +42,10 @@ export type Settings = {
webPushServer?: string; // Web Push server URL webPushServer?: string; // Web Push server URL
}; };
export function isAnyFeedFilterOn(settings: Settings): boolean {
return !!(settings.filterFeedByNearby || settings.filterFeedByVisible);
}
/** /**
* Schema for the Settings table in the database. * Schema for the Settings table in the database.
*/ */

94
src/libs/endorserServer.ts

@ -1,9 +1,11 @@
import { Axios, AxiosResponse, RawAxiosRequestHeaders } from "axios";
import * as didJwt from "did-jwt";
import { LRUCache } from "lru-cache";
import * as R from "ramda"; import * as R from "ramda";
import { IIdentifier } from "@veramo/core"; import { IIdentifier } from "@veramo/core";
import { accessToken, SimpleSigner } from "@/libs/crypto";
import * as didJwt from "did-jwt";
import { Axios, AxiosResponse } from "axios";
import { Contact } from "@/db/tables/contacts"; import { Contact } from "@/db/tables/contacts";
import { accessToken, SimpleSigner } from "@/libs/crypto";
export const SCHEMA_ORG_CONTEXT = "https://schema.org"; export const SCHEMA_ORG_CONTEXT = "https://schema.org";
// the object in RegisterAction claims // the object in RegisterAction claims
@ -49,7 +51,7 @@ export interface GenericVerifiableCredential {
[key: string]: any; // eslint-disable-line @typescript-eslint/no-explicit-any [key: string]: any; // eslint-disable-line @typescript-eslint/no-explicit-any
} }
export interface GenericServerRecord extends GenericVerifiableCredential { export interface GenericCredWrapper extends GenericVerifiableCredential {
handleId?: string; handleId?: string;
id: string; id: string;
issuedAt: string; issuedAt: string;
@ -58,7 +60,7 @@ export interface GenericServerRecord extends GenericVerifiableCredential {
claim: Record<string, any>; claim: Record<string, any>;
claimType?: string; claimType?: string;
} }
export const BLANK_GENERIC_SERVER_RECORD: GenericServerRecord = { export const BLANK_GENERIC_SERVER_RECORD: GenericCredWrapper = {
"@context": SCHEMA_ORG_CONTEXT, "@context": SCHEMA_ORG_CONTEXT,
"@type": "", "@type": "",
claim: {}, claim: {},
@ -68,7 +70,7 @@ export const BLANK_GENERIC_SERVER_RECORD: GenericServerRecord = {
}; };
// a summary record; the VC is found the fullClaim field // a summary record; the VC is found the fullClaim field
export interface GiveServerRecord { export interface GiveSummaryRecord {
agentDid: string; agentDid: string;
amount: number; amount: number;
amountConfirmed: number; amountConfirmed: number;
@ -83,7 +85,7 @@ export interface GiveServerRecord {
} }
// a summary record; the VC is found the fullClaim field // a summary record; the VC is found the fullClaim field
export interface OfferServerRecord { export interface OfferSummaryRecord {
amount: number; amount: number;
amountGiven: number; amountGiven: number;
amountGivenConfirmed: number; amountGivenConfirmed: number;
@ -101,7 +103,7 @@ export interface OfferServerRecord {
} }
// a summary record; the VC is not currently part of this record // a summary record; the VC is not currently part of this record
export interface PlanServerRecord { export interface PlanSummaryRecord {
agentDid?: string; // optional, if the issuer wants someone else to manage as well agentDid?: string; // optional, if the issuer wants someone else to manage as well
description: string; description: string;
endTime?: string; endTime?: string;
@ -256,6 +258,10 @@ export type CreateAndSubmitClaimResult = SuccessResult | ErrorResult;
// See https://github.com/trentlarson/endorser-ch/blob/0cb626f803028e7d9c67f095858a9fc8542e3dbd/server/api/services/util.js#L6 // See https://github.com/trentlarson/endorser-ch/blob/0cb626f803028e7d9c67f095858a9fc8542e3dbd/server/api/services/util.js#L6
const HIDDEN_DID = "did:none:HIDDEN"; const HIDDEN_DID = "did:none:HIDDEN";
const planCache: LRUCache<string, PlanSummaryRecord> = new LRUCache({
max: 500,
});
export function isDid(did: string) { export function isDid(did: string) {
return did.startsWith("did:"); return did.startsWith("did:");
} }
@ -269,7 +275,7 @@ export function isEmptyOrHiddenDid(did?: string) {
} }
/** /**
* @return true for any nested string where func(input) === true * @return true for any string within this primitive/object/array where func(input) === true
* *
* Similar logic is found in endorser-mobile. * Similar logic is found in endorser-mobile.
*/ */
@ -304,6 +310,12 @@ export function containsHiddenDid(obj: any) {
return testRecursivelyOnStrings(isHiddenDid, obj); return testRecursivelyOnStrings(isHiddenDid, obj);
} }
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const containsNonHiddenDid = (obj: any) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return testRecursivelyOnStrings((s: any) => isDid(s) && !isHiddenDid(s), obj);
};
export function stripEndorserPrefix(claimId: string) { export function stripEndorserPrefix(claimId: string) {
if (claimId && claimId.startsWith(ENDORSER_CH_HANDLE_PREFIX)) { if (claimId && claimId.startsWith(ENDORSER_CH_HANDLE_PREFIX)) {
return claimId.substring(ENDORSER_CH_HANDLE_PREFIX.length); return claimId.substring(ENDORSER_CH_HANDLE_PREFIX.length);
@ -423,6 +435,62 @@ export function didInfo(
return didInfoForContact(did, activeDid, contact, allMyDids).displayName; return didInfoForContact(did, activeDid, contact, allMyDids).displayName;
} }
async function getHeaders(identity: IIdentifier) {
const headers: RawAxiosRequestHeaders = {
"Content-Type": "application/json",
};
if (identity) {
const token = await accessToken(identity);
headers["Authorization"] = "Bearer " + token;
}
return headers;
}
export async function getPlanFromCache(
handleId: string,
identity: IIdentifier,
axios: Axios,
apiServer: string,
) {
let cred = planCache.get(handleId);
if (!cred) {
const url =
apiServer +
"/api/v2/report/plans?handleId=" +
encodeURIComponent(handleId);
const headers = await getHeaders(identity);
try {
const resp = await axios.get(url, { headers });
if (resp.status === 200 && resp.data?.data?.length > 0) {
cred = resp.data.data[0];
planCache.set(handleId, cred);
} else {
console.log(
"Failed to load plan with handle",
handleId,
" Got data:",
resp.data,
);
}
} catch (error) {
console.log(
"Failed to load plan with handle",
handleId,
" Got error:",
error,
);
}
}
return cred;
}
export async function setPlanInCache(
handleId: string,
planSummary: PlanSummaryRecord,
) {
planCache.set(handleId, planSummary);
}
/** /**
* For result, see https://api.endorser.ch/api-docs/#/claims/post_api_v2_claim * For result, see https://api.endorser.ch/api-docs/#/claims/post_api_v2_claim
* *
@ -475,7 +543,7 @@ export async function createAndSubmitGive(
vcClaim.image = imageUrl; vcClaim.image = imageUrl;
} }
return createAndSubmitClaim( return createAndSubmitClaim(
vcClaim as GenericServerRecord, vcClaim as GenericCredWrapper,
identity, identity,
apiServer, apiServer,
axios, axios,
@ -524,7 +592,7 @@ export async function createAndSubmitOffer(
}; };
} }
return createAndSubmitClaim( return createAndSubmitClaim(
vcClaim as GenericServerRecord, vcClaim as GenericCredWrapper,
identity, identity,
apiServer, apiServer,
axios, axios,
@ -695,7 +763,7 @@ const claimSummary = (claim: Record<string, any>) => {
similar code is also contained in endorser-mobile similar code is also contained in endorser-mobile
**/ **/
export const claimSpecialDescription = ( export const claimSpecialDescription = (
record: GenericServerRecord, record: GenericCredWrapper,
activeDid: string, activeDid: string,
identifiers: Array<string>, identifiers: Array<string>,
contacts: Array<Contact>, contacts: Array<Contact>,
@ -789,7 +857,7 @@ export const claimSpecialDescription = (
"...]" "...]"
); );
} else { } else {
return issuer + " declared " + claimSummary(claim as GenericServerRecord); return issuer + " declared " + claimSummary(claim as GenericCredWrapper);
} }
}; };

14
src/libs/util.ts

@ -9,7 +9,7 @@ import { accountsDB, db } from "@/db/index";
import { Account } from "@/db/tables/accounts"; import { Account } from "@/db/tables/accounts";
import { MASTER_SETTINGS_KEY } from "@/db/tables/settings"; import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
import { deriveAddress, generateSeed, newIdentifier } from "@/libs/crypto"; import { deriveAddress, generateSeed, newIdentifier } from "@/libs/crypto";
import { GenericServerRecord, containsHiddenDid } from "@/libs/endorserServer"; import { GenericCredWrapper, containsHiddenDid } from "@/libs/endorserServer";
import * as serverUtil from "@/libs/endorserServer"; import * as serverUtil from "@/libs/endorserServer";
// eslint-disable-next-line @typescript-eslint/no-var-requires // eslint-disable-next-line @typescript-eslint/no-var-requires
@ -69,7 +69,7 @@ export const isGlobalUri = (uri: string) => {
return uri && uri.match(new RegExp(/^[A-Za-z][A-Za-z0-9+.-]+:/)); return uri && uri.match(new RegExp(/^[A-Za-z][A-Za-z0-9+.-]+:/));
}; };
export const giveIsConfirmable = (veriClaim: GenericServerRecord) => { export const giveIsConfirmable = (veriClaim: GenericCredWrapper) => {
return veriClaim.claimType === "GiveAction"; return veriClaim.claimType === "GiveAction";
}; };
@ -85,7 +85,7 @@ export const doCopyTwoSecRedo = (text: string, fn: () => void) => {
* @param veriClaim is expected to have fields: claim, claimType, and issuer * @param veriClaim is expected to have fields: claim, claimType, and issuer
*/ */
export const isGiveRecordTheUserCanConfirm = ( export const isGiveRecordTheUserCanConfirm = (
veriClaim: GenericServerRecord, veriClaim: GenericCredWrapper,
activeDid: string, activeDid: string,
confirmerIdList: string[] = [], confirmerIdList: string[] = [],
) => { ) => {
@ -101,9 +101,9 @@ export const isGiveRecordTheUserCanConfirm = (
* @returns the DID of the person who offered, or undefined if hidden * @returns the DID of the person who offered, or undefined if hidden
* @param veriClaim is expected to have fields: claim and issuer * @param veriClaim is expected to have fields: claim and issuer
*/ */
export const offerGiverDid: ( export const offerGiverDid: (arg0: GenericCredWrapper) => string | undefined = (
arg0: GenericServerRecord, veriClaim,
) => string | undefined = (veriClaim) => { ) => {
let giver; let giver;
if ( if (
veriClaim.claim.offeredBy?.identifier && veriClaim.claim.offeredBy?.identifier &&
@ -120,7 +120,7 @@ export const offerGiverDid: (
* @returns true if the user can fulfill the offer * @returns true if the user can fulfill the offer
* @param veriClaim is expected to have fields: claim, claimType, and issuer * @param veriClaim is expected to have fields: claim, claimType, and issuer
*/ */
export const canFulfillOffer = (veriClaim: GenericServerRecord) => { export const canFulfillOffer = (veriClaim: GenericCredWrapper) => {
return !!(veriClaim.claimType === "Offer" && offerGiverDid(veriClaim)); return !!(veriClaim.claimType === "Offer" && offerGiverDid(veriClaim));
}; };

10
src/views/ContactAmountsView.vue

@ -119,7 +119,7 @@ import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
import { accessToken, SimpleSigner } from "@/libs/crypto"; import { accessToken, SimpleSigner } from "@/libs/crypto";
import { import {
AgreeVerifiableCredential, AgreeVerifiableCredential,
GiveServerRecord, GiveSummaryRecord,
GiveVerifiableCredential, GiveVerifiableCredential,
SCHEMA_ORG_CONTEXT, SCHEMA_ORG_CONTEXT,
} from "@/libs/endorserServer"; } from "@/libs/endorserServer";
@ -131,7 +131,7 @@ export default class ContactAmountssView extends Vue {
activeDid = ""; activeDid = "";
apiServer = ""; apiServer = "";
contact: Contact | null = null; contact: Contact | null = null;
giveRecords: Array<GiveServerRecord> = []; giveRecords: Array<GiveSummaryRecord> = [];
numAccounts = 0; numAccounts = 0;
async beforeCreate() { async beforeCreate() {
@ -197,7 +197,7 @@ export default class ContactAmountssView extends Vue {
async loadGives(activeDid: string, contact: Contact) { async loadGives(activeDid: string, contact: Contact) {
try { try {
const identity = await this.getIdentity(this.activeDid); const identity = await this.getIdentity(this.activeDid);
let result: Array<GiveServerRecord> = []; let result: Array<GiveSummaryRecord> = [];
const url = const url =
this.apiServer + this.apiServer +
"/api/v2/report/gives?agentDid=" + "/api/v2/report/gives?agentDid=" +
@ -252,7 +252,7 @@ export default class ContactAmountssView extends Vue {
); );
} }
const sortedResult: Array<GiveServerRecord> = R.sort( const sortedResult: Array<GiveSummaryRecord> = R.sort(
(a, b) => (a, b) =>
new Date(b.issuedAt).getTime() - new Date(a.issuedAt).getTime(), new Date(b.issuedAt).getTime() - new Date(a.issuedAt).getTime(),
result, result,
@ -271,7 +271,7 @@ export default class ContactAmountssView extends Vue {
} }
} }
async confirm(record: GiveServerRecord) { async confirm(record: GiveSummaryRecord) {
// Make claim // Make claim
// I use clone here because otherwise it gets a Proxy object. // I use clone here because otherwise it gets a Proxy object.
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any

4
src/views/ContactsView.vue

@ -303,7 +303,7 @@ import {
import { import {
CONTACT_CSV_HEADER, CONTACT_CSV_HEADER,
CONTACT_URL_PREFIX, CONTACT_URL_PREFIX,
GiveServerRecord, GiveSummaryRecord,
GiveVerifiableCredential, GiveVerifiableCredential,
isDid, isDid,
RegisterVerifiableCredential, RegisterVerifiableCredential,
@ -410,7 +410,7 @@ export default class ContactsView extends Vue {
} }
const handleResponse = ( const handleResponse = (
resp: { status: number; data: { data: GiveServerRecord[] } }, resp: { status: number; data: { data: GiveSummaryRecord[] } },
descriptions: Record<string, string>, descriptions: Record<string, string>,
confirmed: Record<string, number>, confirmed: Record<string, number>,
unconfirmed: Record<string, number>, unconfirmed: Record<string, number>,

113
src/views/HomeView.vue

@ -247,11 +247,17 @@
<fa icon="spinner" class="fa-spin-pulse"></fa> Loading&hellip; <fa icon="spinner" class="fa-spin-pulse"></fa> Loading&hellip;
</p> </p>
</div> </div>
<div v-if="!isFeedLoading && feedData.length === 0">
<p class="text-slate-500 text-center italic mt-4 mb-4">
No claims match your filters.
</p>
</div>
</div> </div>
</section> </section>
</template> </template>
<script lang="ts"> <script lang="ts">
import * as R from "ramda";
import { UAParser } from "ua-parser-js"; import { UAParser } from "ua-parser-js";
import { IIdentifier } from "@veramo/core"; import { IIdentifier } from "@veramo/core";
import { Component, Vue } from "vue-facing-decorator"; import { Component, Vue } from "vue-facing-decorator";
@ -267,17 +273,24 @@ import { NotificationIface } from "@/constants/app";
import { db, accountsDB } from "@/db/index"; import { db, accountsDB } from "@/db/index";
import { Account } from "@/db/tables/accounts"; import { Account } from "@/db/tables/accounts";
import { Contact } from "@/db/tables/contacts"; import { Contact } from "@/db/tables/contacts";
import { MASTER_SETTINGS_KEY, Settings } from "@/db/tables/settings"; import {
BoundingBox,
isAnyFeedFilterOn,
MASTER_SETTINGS_KEY,
Settings,
} from "@/db/tables/settings";
import { accessToken } from "@/libs/crypto"; import { accessToken } from "@/libs/crypto";
import { import {
contactForDid, contactForDid,
containsNonHiddenDid,
didInfoForContact, didInfoForContact,
getPlanFromCache,
GiverInputInfo, GiverInputInfo,
GiveServerRecord, GiveSummaryRecord,
} from "@/libs/endorserServer"; } from "@/libs/endorserServer";
import { generateSaveAndActivateIdentity } from "@/libs/util"; import { generateSaveAndActivateIdentity } from "@/libs/util";
interface GiveRecordWithContactInfo extends GiveServerRecord { interface GiveRecordWithContactInfo extends GiveSummaryRecord {
giver: { giver: {
displayName: string; displayName: string;
known: boolean; known: boolean;
@ -310,11 +323,16 @@ export default class HomeView extends Vue {
feedData: GiveRecordWithContactInfo[] = []; feedData: GiveRecordWithContactInfo[] = [];
feedPreviousOldestId?: string; feedPreviousOldestId?: string;
feedLastViewedClaimId?: string; feedLastViewedClaimId?: string;
isAnyFeedFilterOn: boolean;
isCreatingIdentifier = false; isCreatingIdentifier = false;
isFeedFilteredByContacts = false; isFeedFilteredByVisible = false;
isFeedFilteredByNearby = false; isFeedFilteredByNearby = false;
isFeedLoading = true; isFeedLoading = true;
isRegistered = false; isRegistered = false;
searchBoxes: Array<{
name: string;
bbox: BoundingBox;
}> = [];
showShortcutBvc = false; showShortcutBvc = false;
userAgentInfo = new UAParser(); // see https://docs.uaparser.js.org/v2/api/ua-parser-js/get-os.html userAgentInfo = new UAParser(); // see https://docs.uaparser.js.org/v2/api/ua-parser-js/get-os.html
@ -349,11 +367,14 @@ export default class HomeView extends Vue {
this.activeDid = settings?.activeDid || ""; this.activeDid = settings?.activeDid || "";
this.allContacts = await db.contacts.toArray(); this.allContacts = await db.contacts.toArray();
this.feedLastViewedClaimId = settings?.lastViewedClaimId; this.feedLastViewedClaimId = settings?.lastViewedClaimId;
this.isFeedFilteredByContacts = !!settings?.filterFeedContacts; this.isFeedFilteredByVisible = !!settings?.filterFeedByVisible;
this.isFeedFilteredByNearby = !!settings?.filterFeedNearby; this.isFeedFilteredByNearby = !!settings?.filterFeedByNearby;
this.isRegistered = !!settings?.isRegistered; this.isRegistered = !!settings?.isRegistered;
this.searchBoxes = settings?.searchBoxes || [];
this.showShortcutBvc = !!settings?.showShortcutBvc; this.showShortcutBvc = !!settings?.showShortcutBvc;
this.isAnyFeedFilterOn = isAnyFeedFilterOn(settings);
if (this.allMyDids.length === 0) { if (this.allMyDids.length === 0) {
this.isCreatingIdentifier = true; this.isCreatingIdentifier = true;
this.activeDid = await generateSaveAndActivateIdentity(); this.activeDid = await generateSaveAndActivateIdentity();
@ -383,7 +404,7 @@ export default class HomeView extends Vue {
} }
resultsAreFiltered() { resultsAreFiltered() {
return this.isFeedFilteredByContacts || this.isFeedFilteredByNearby; return this.isFeedFilteredByVisible || this.isFeedFilteredByNearby;
} }
notificationsSupported() { notificationsSupported() {
@ -395,21 +416,15 @@ export default class HomeView extends Vue {
"Content-Type": "application/json", "Content-Type": "application/json",
}; };
const identity = await this.getIdentity(this.activeDid);
if (this.activeDid) { if (this.activeDid) {
await accountsDB.open(); if (identity) {
const allAccounts = await accountsDB.accounts.toArray(); headers["Authorization"] = "Bearer " + (await accessToken(identity));
const account = allAccounts.find( } else {
(acc) => acc.did === this.activeDid,
) as Account;
const identity = JSON.parse(account?.identity || "null");
if (!identity) {
throw new Error( throw new Error(
"An ID is chosen but there are no keys for it so it cannot be used to talk with the service. Switch your ID.", "An ID is chosen but there are no keys for it so it cannot be used to talk with the service. Switch your ID.",
); );
} }
headers["Authorization"] = "Bearer " + (await accessToken(identity));
} else { } else {
// it's OK without auth... we just won't get any identifiers // it's OK without auth... we just won't get any identifiers
} }
@ -420,8 +435,9 @@ export default class HomeView extends Vue {
async reloadFeedOnChange() { async reloadFeedOnChange() {
await db.open(); await db.open();
const settings = (await db.settings.get(MASTER_SETTINGS_KEY)) as Settings; const settings = (await db.settings.get(MASTER_SETTINGS_KEY)) as Settings;
this.isFeedFilteredByContacts = !!settings?.filterFeedContacts; this.isFeedFilteredByVisible = !!settings?.filterFeedByVisible;
this.isFeedFilteredByNearby = !!settings?.filterFeedNearby; this.isFeedFilteredByNearby = !!settings?.filterFeedByNearby;
this.isAnyFeedFilterOn = isAnyFeedFilterOn(settings);
this.feedData = []; this.feedData = [];
this.feedPreviousOldestId = undefined; this.feedPreviousOldestId = undefined;
@ -438,14 +454,30 @@ export default class HomeView extends Vue {
} }
} }
latLongInAnySearchBox(lat: number, long: number) {
for (const boxInfo of this.searchBoxes) {
if (
boxInfo.bbox.westLong <= long &&
long <= boxInfo.bbox.eastLong &&
boxInfo.bbox.minLat <= lat &&
lat <= boxInfo.bbox.maxLat
) {
return true;
}
}
}
public async updateAllFeed() { public async updateAllFeed() {
this.isFeedLoading = true; this.isFeedLoading = true;
let endOfResults = true;
await this.retrieveGives(this.apiServer, this.feedPreviousOldestId) await this.retrieveGives(this.apiServer, this.feedPreviousOldestId)
.then(async (results) => { .then(async (results) => {
if (results.data.length > 0) { if (results.data.length > 0) {
endOfResults = false;
// include the descriptions of the giver and receiver // include the descriptions of the giver and receiver
const newFeedData: GiveRecordWithContactInfo = results.data.map( const identity = await this.getIdentity(this.activeDid);
(record: GiveServerRecord) => { const newFeedData: Array<Promise<GiveRecordWithContactInfo>> =
results.data.map(async (record: GiveSummaryRecord) => {
// similar code is in endorser-mobile utility.ts // similar code is in endorser-mobile utility.ts
// claim.claim happen for some claims wrapped in a Verifiable Credential // claim.claim happen for some claims wrapped in a Verifiable Credential
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
@ -456,6 +488,33 @@ export default class HomeView extends Vue {
// recipient.did is for legacy data, before March 2023 // recipient.did is for legacy data, before March 2023
const recipientDid = const recipientDid =
claim.recipient?.identifier || (claim.recipient as any)?.did; // eslint-disable-line @typescript-eslint/no-explicit-any claim.recipient?.identifier || (claim.recipient as any)?.did; // eslint-disable-line @typescript-eslint/no-explicit-any
let anyMatch = false;
if (
this.isFeedFilteredByVisible &&
containsNonHiddenDid(record)
) {
// has a visible DID so it's a keeper
anyMatch = true;
}
if (!anyMatch && this.isFeedFilteredByNearby) {
// check if the associated project has a location inside user's search box
if (record.fulfillsPlanHandleId) {
const plan = await getPlanFromCache(
record.fulfillsPlanHandleId,
identity,
this.axios,
this.apiServer,
);
if (plan?.locLat && plan?.locLon) {
if (this.latLongInAnySearchBox(plan.locLat, plan.locLon)) {
anyMatch = true;
}
}
}
}
if (this.isAnyFeedFilterOn && !anyMatch) {
return null;
}
return { return {
...record, ...record,
giver: didInfoForContact( giver: didInfoForContact(
@ -472,9 +531,11 @@ export default class HomeView extends Vue {
this.allMyDids, this.allMyDids,
), ),
}; };
}, });
); const allNewFeedData: GiveRecordWithContactInfo[] =
this.feedData = this.feedData.concat(newFeedData); await Promise.all(newFeedData);
const filteredFeedData = allNewFeedData.filter(R.isNotNil);
this.feedData = this.feedData.concat(filteredFeedData);
this.feedPreviousOldestId = this.feedPreviousOldestId =
results.data[results.data.length - 1].jwtId; results.data[results.data.length - 1].jwtId;
// The following update is only done on the first load. // The following update is only done on the first load.
@ -501,6 +562,10 @@ export default class HomeView extends Vue {
-1, -1,
); );
}); });
if (this.feedData.length === 0 && !endOfResults) {
// repeat until there's at least some data
this.updateAllFeed();
}
this.isFeedLoading = false; this.isFeedLoading = false;
} }

30
src/views/ProjectViewView.vue

@ -360,11 +360,11 @@ import { accessToken } from "@/libs/crypto";
import * as libsUtil from "@/libs/util"; import * as libsUtil from "@/libs/util";
import { import {
BLANK_GENERIC_SERVER_RECORD, BLANK_GENERIC_SERVER_RECORD,
GenericServerRecord, GenericCredWrapper,
GiverInputInfo, GiverInputInfo,
GiveServerRecord, GiveSummaryRecord,
OfferServerRecord, OfferSummaryRecord,
PlanServerRecord, PlanSummaryRecord,
} from "@/libs/endorserServer"; } from "@/libs/endorserServer";
import * as serverUtil from "@/libs/endorserServer"; import * as serverUtil from "@/libs/endorserServer";
@ -388,14 +388,14 @@ export default class ProjectViewView extends Vue {
apiServer = ""; apiServer = "";
description = ""; description = "";
expanded = false; expanded = false;
fulfilledByThis: PlanServerRecord | null = null; fulfilledByThis: PlanSummaryRecord | null = null;
fulfillersToThis: Array<PlanServerRecord> = []; fulfillersToThis: Array<PlanSummaryRecord> = [];
givesToThis: Array<GiveServerRecord> = []; givesToThis: Array<GiveSummaryRecord> = [];
issuer = ""; issuer = "";
latitude = 0; latitude = 0;
longitude = 0; longitude = 0;
name = ""; name = "";
offersToThis: Array<OfferServerRecord> = []; offersToThis: Array<OfferSummaryRecord> = [];
projectId = localStorage.getItem("projectId") || ""; // handle ID projectId = localStorage.getItem("projectId") || ""; // handle ID
showDidCopy = false; showDidCopy = false;
timeSince = ""; timeSince = "";
@ -718,8 +718,8 @@ export default class ProjectViewView extends Vue {
this.$router.push(route); this.$router.push(route);
} }
checkIsFulfillable(offer: OfferServerRecord) { checkIsFulfillable(offer: OfferSummaryRecord) {
const offerRecord: GenericServerRecord = { const offerRecord: GenericCredWrapper = {
...BLANK_GENERIC_SERVER_RECORD, ...BLANK_GENERIC_SERVER_RECORD,
claim: offer.fullClaim, claim: offer.fullClaim,
claimType: "Offer", claimType: "Offer",
@ -728,8 +728,8 @@ export default class ProjectViewView extends Vue {
return libsUtil.canFulfillOffer(offerRecord); return libsUtil.canFulfillOffer(offerRecord);
} }
onClickFulfillGiveToOffer(offer: OfferServerRecord) { onClickFulfillGiveToOffer(offer: OfferSummaryRecord) {
const offerRecord: GenericServerRecord = { const offerRecord: GenericCredWrapper = {
...BLANK_GENERIC_SERVER_RECORD, ...BLANK_GENERIC_SERVER_RECORD,
claim: offer.fullClaim, claim: offer.fullClaim,
issuer: offer.offeredByDid, issuer: offer.offeredByDid,
@ -768,8 +768,8 @@ export default class ProjectViewView extends Vue {
} }
} }
checkIsConfirmable(give: GiveServerRecord) { checkIsConfirmable(give: GiveSummaryRecord) {
const giveDetails: GenericServerRecord = { const giveDetails: GenericCredWrapper = {
...BLANK_GENERIC_SERVER_RECORD, ...BLANK_GENERIC_SERVER_RECORD,
claim: give.fullClaim, claim: give.fullClaim,
claimType: "GiveAction", claimType: "GiveAction",
@ -779,7 +779,7 @@ export default class ProjectViewView extends Vue {
} }
// similar code is found in ClaimView // similar code is found in ClaimView
async confirmClaim(give: GiveServerRecord) { async confirmClaim(give: GiveSummaryRecord) {
if (confirm("Do you personally confirm that this is true?")) { if (confirm("Do you personally confirm that this is true?")) {
// similar logic is found in endorser-mobile // similar logic is found in endorser-mobile
const goodClaim = serverUtil.removeSchemaContext( const goodClaim = serverUtil.removeSchemaContext(

4
src/views/ProjectsView.vue

@ -223,7 +223,7 @@ import InfiniteScroll from "@/components/InfiniteScroll.vue";
import QuickNav from "@/components/QuickNav.vue"; import QuickNav from "@/components/QuickNav.vue";
import ProjectIcon from "@/components/ProjectIcon.vue"; import ProjectIcon from "@/components/ProjectIcon.vue";
import TopMessage from "@/components/TopMessage.vue"; import TopMessage from "@/components/TopMessage.vue";
import { OfferServerRecord, PlanData } from "@/libs/endorserServer"; import { OfferSummaryRecord, PlanData } from "@/libs/endorserServer";
import EntityIcon from "@/components/EntityIcon.vue"; import EntityIcon from "@/components/EntityIcon.vue";
@Component({ @Component({
@ -237,7 +237,7 @@ export default class ProjectsView extends Vue {
currentIid: IIdentifier; currentIid: IIdentifier;
isLoading = false; isLoading = false;
numAccounts = 0; numAccounts = 0;
offers: OfferServerRecord[] = []; offers: OfferSummaryRecord[] = [];
showOffers = true; showOffers = true;
showProjects = false; showProjects = false;

6
src/views/QuickActionBvcEndView.vue

@ -146,7 +146,7 @@ import {
createAndSubmitConfirmation, createAndSubmitConfirmation,
createAndSubmitGive, createAndSubmitGive,
ErrorResult, ErrorResult,
GenericServerRecord, GenericCredWrapper,
GenericVerifiableCredential, GenericVerifiableCredential,
} from "@/libs/endorserServer"; } from "@/libs/endorserServer";
import * as libsUtil from "@/libs/util"; import * as libsUtil from "@/libs/util";
@ -166,7 +166,7 @@ export default class QuickActionBvcBeginView extends Vue {
allMyDids: Array<string> = []; allMyDids: Array<string> = [];
apiServer = ""; apiServer = "";
claimCountWithHidden = 0; claimCountWithHidden = 0;
claimsToConfirm: GenericServerRecord[] = []; claimsToConfirm: GenericCredWrapper[] = [];
claimsToConfirmSelected: string[] = []; claimsToConfirmSelected: string[] = [];
description = "breakfast"; description = "breakfast";
loadingConfirms = true; loadingConfirms = true;
@ -228,7 +228,7 @@ export default class QuickActionBvcBeginView extends Vue {
} }
await response.json().then((data) => { await response.json().then((data) => {
const dataByOthers = R.reject( const dataByOthers = R.reject(
(claim: GenericServerRecord) => claim.issuer === this.activeDid, (claim: GenericCredWrapper) => claim.issuer === this.activeDid,
data, data,
); );
const dataByOthersWithoutHidden = R.reject( const dataByOthersWithoutHidden = R.reject(

2
src/views/SearchAreaView.vue

@ -246,7 +246,7 @@ export default class DiscoverView extends Vue {
await db.open(); await db.open();
db.settings.update(MASTER_SETTINGS_KEY, { db.settings.update(MASTER_SETTINGS_KEY, {
searchBoxes: [], searchBoxes: [],
filterFeedNearby: false, filterFeedByNearby: false,
}); });
this.searchBox = null; this.searchBox = null;
this.localCenterLat = 0; this.localCenterLat = 0;

Loading…
Cancel
Save