Compare commits

..

23 Commits

Author SHA1 Message Date
Jose Olarte III
ab523639a5 Normalized button visual styles 2023-12-13 18:48:45 +08:00
Jose Olarte III
0484dfb253 Spacing and typography fixes 2023-12-13 18:37:03 +08:00
Jose Olarte III
c2839e8a99 Mobile-style flushed-right toggle switches 2023-12-13 18:22:15 +08:00
Jose Olarte III
e533cd3d34 Visual improvements to "set name" button 2023-12-13 18:16:15 +08:00
Jose Olarte III
18e00b95c7 Fixed size and alignment of QR code button 2023-12-13 17:41:27 +08:00
Jose Olarte III
e97cd1b1fa Minor visual improvements in "giving recognition" section 2023-12-13 17:29:53 +08:00
ccca93b9f1 change some messages, rework tasks 2023-12-11 19:19:29 -07:00
1be6c04699 prompt them to fill in their name when sharing their info 2023-12-11 16:36:50 -07:00
2c33febb0e fix location of web-push unsubscribe action 2023-12-10 20:22:41 -07:00
e6f73dc81c add an unsubscribe to the web push 2023-12-10 20:17:14 -07:00
0d55a722c5 there's no need to capitalize EVERYTHING 2023-12-10 18:55:13 -07:00
97ef78f5dd add better debug logging for web-push info 2023-12-10 18:53:58 -07:00
672abac9a9 show web-push subscription info on demand, and refine docs 2023-12-10 18:43:24 -07:00
0607fad3e5 remove the 'never' option for notifications & close on 'maybe later' 2023-12-10 17:41:03 -07:00
6aa89a1d1d update icon and favicon 2023-12-10 16:53:35 -07:00
2556d5feb9 Merge pull request 'add hash to help page for tracking exact versions' (#95) from git-hash into master
Reviewed-on: trent_larson/crowd-funder-for-time-pwa#95
2023-12-10 11:21:23 -05:00
3c1654764c add commit hash to help page 2023-12-10 09:20:03 -07:00
4c1e229d62 compute commit hash with git-describe 2023-12-10 09:18:07 -07:00
17444d75de remove references to test file 2023-12-10 08:59:25 -07:00
f2fb432d2e update documentation for going to production 2023-12-09 22:15:24 -07:00
e45689daed bump version to next beta 2023-12-09 21:21:35 -07:00
041308ebc9 fix app name so that it'll build 2023-12-09 20:39:17 -07:00
9c36bb509a bump to v 0.1.5 and other misc tweaks 2023-12-09 20:36:51 -07:00
22 changed files with 2437 additions and 2478 deletions

View File

@@ -8,8 +8,24 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased] ## [Unreleased]
## [0.1.6]
## [0.1.5] - 2023.12.09 - 9c36bb509a9bae9bb3306d3bd9eeb144b67aa8ad
### Added ### Added
- Web push notifications - Web push notifications (though not finalized)
- Credentials details page
- See more data without an ID
- Change units of a give
## [0.1.4] - 2023.11.20 - 7311d36726f3667ec4c68f241f91d404273ad4db
### Added
- Offer on a project
### Changed
- Automatically set as visible when importing a contact
## [0.1.3] - 2023.11.08 - 910f57ec7d2e50803ae3d04f4b927e0f5219fbde ## [0.1.3] - 2023.11.08 - 910f57ec7d2e50803ae3d04f4b927e0f5219fbde
### Added ### Added

View File

@@ -22,16 +22,23 @@ npm run lint
If you are deploying in a subdirectory, add it to `publicPath` in vue.config.js, eg: `publicPath: "/app/time-tracker/",` If you are deploying in a subdirectory, add it to `publicPath` in vue.config.js, eg: `publicPath: "/app/time-tracker/",`
``` * `npx prettier --write ./sw_scripts/`
npm run build
```
``` ...to make sure the service worker scripts are in proper form
npx prettier --write ./sw_scripts/
```
to make sure the service worker scripts are in proper form
... then copy the contents of the `sw_scripts` folder to the `dist` folder - except additional_scripts.js. * Update the CHANGELOG.md & the version in package.json, run `npm install`, and commit. Tag wth the new version: `git tag 0.1.0`
* If production, change src/constants/app.ts DEFAULT_*_SERVER to be PROD.
* `npm run build`
* Revert src/constants/app.ts & change version to "-beta"
* `cp sw_scripts/[ns]* dist/`
... to copy the contents of the `sw_scripts` folder to the `dist` folder - except additional_scripts.js.
* `rsync -azvu -e "ssh -i ~/.ssh/..." dist ubuntu@endorser.ch:time-safari`
@@ -103,9 +110,9 @@ To add an icon, add to main.ts and reference with `fa` element and `icon` attrib
### Clear/Reset data & restart ### Clear/Reset data & restart
* Clear cache for site. (In Chrome, go to `chrome://settings/cookies` and "all site data and permissions"; in Firefox, go to `about:preferences` and search for cache.) * Clear cache for site. (In Chrome, go to `chrome://settings/cookies` and "all site data and permissions"; in Firefox, go to `about:preferences` and search for "cache" then "Manage Data".)
* Unregister service worker (in Chrome, go to `chrome://serviceworker-internals/`; in Firefox, go to `about:serviceworkers` or `about:debugging`). * Unregister service worker (in Chrome, go to `chrome://serviceworker-internals/`; in Firefox, go to `about:serviceworkers`).
* Clear notification permission (in Chrome, go to `chrome://settings/content/notifications`; in Firefox, go to `about:preferences` and search). * Clear notification permission (in Chrome, go to `chrome://settings/content/notifications`; in Firefox, go to `about:preferences` and search for "notifications").
* Clear Cache Storage (in Chrome, in dev tools under Application; in Firefox, in dev tools under Storage). * Clear Cache Storage (in Chrome, in dev tools under Application; in Firefox, in dev tools under Storage).

51
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{ {
"name": "crowd-funder-for-time-pwa", "name": "TimeSafari",
"version": "0.1.4", "version": "0.1.6-beta",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "crowd-funder-for-time-pwa", "name": "TimeSafari",
"version": "0.1.4", "version": "0.1.6-beta",
"dependencies": { "dependencies": {
"@ethersproject/hdnode": "^5.7.0", "@ethersproject/hdnode": "^5.7.0",
"@fortawesome/fontawesome-svg-core": "^6.4.2", "@fortawesome/fontawesome-svg-core": "^6.4.2",
@@ -33,9 +33,9 @@
"ethereum-cryptography": "^2.1.2", "ethereum-cryptography": "^2.1.2",
"ethereumjs-util": "^7.1.5", "ethereumjs-util": "^7.1.5",
"ethr-did-resolver": "^8.1.2", "ethr-did-resolver": "^8.1.2",
"git-describe": "^4.1.1",
"jdenticon": "^3.2.0", "jdenticon": "^3.2.0",
"js-generate-password": "^0.1.9", "js-generate-password": "^0.1.9",
"js-yaml": "^4.1.0",
"localstorage-slim": "^2.5.0", "localstorage-slim": "^2.5.0",
"luxon": "^3.4.3", "luxon": "^3.4.3",
"merkletreejs": "^0.3.10", "merkletreejs": "^0.3.10",
@@ -59,7 +59,6 @@
"web-did-resolver": "^2.0.27" "web-did-resolver": "^2.0.27"
}, },
"devDependencies": { "devDependencies": {
"@types/js-yaml": "^4.0.9",
"@types/leaflet": "^1.9.4", "@types/leaflet": "^1.9.4",
"@types/ramda": "^0.29.3", "@types/ramda": "^0.29.3",
"@types/three": "^0.155.1", "@types/three": "^0.155.1",
@@ -8794,12 +8793,6 @@
"@types/istanbul-lib-report": "*" "@types/istanbul-lib-report": "*"
} }
}, },
"node_modules/@types/js-yaml": {
"version": "4.0.9",
"resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.9.tgz",
"integrity": "sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==",
"dev": true
},
"node_modules/@types/json-schema": { "node_modules/@types/json-schema": {
"version": "7.0.13", "version": "7.0.13",
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.13.tgz", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.13.tgz",
@@ -8902,8 +8895,7 @@
"node_modules/@types/semver": { "node_modules/@types/semver": {
"version": "7.5.3", "version": "7.5.3",
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.3.tgz", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.3.tgz",
"integrity": "sha512-OxepLK9EuNEIPxWNME+C6WwbRAOOI2o2BaQEGzz5Lu2e4Z5eDnEo+/aVEDMIXywoJitJ7xWd641wrGLZdtwRyw==", "integrity": "sha512-OxepLK9EuNEIPxWNME+C6WwbRAOOI2o2BaQEGzz5Lu2e4Z5eDnEo+/aVEDMIXywoJitJ7xWd641wrGLZdtwRyw=="
"dev": true
}, },
"node_modules/@types/send": { "node_modules/@types/send": {
"version": "0.17.2", "version": "0.17.2",
@@ -11069,7 +11061,8 @@
"node_modules/argparse": { "node_modules/argparse": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
"devOptional": true
}, },
"node_modules/array-buffer-byte-length": { "node_modules/array-buffer-byte-length": {
"version": "1.0.0", "version": "1.0.0",
@@ -16279,6 +16272,30 @@
"node": ">=6" "node": ">=6"
} }
}, },
"node_modules/git-describe": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/git-describe/-/git-describe-4.1.1.tgz",
"integrity": "sha512-JC8ganO5kO80G8+XE98TDDjnMXQN3Estk3qdJuG2EGRF/l6zuMTMcN+8OSfQZ5FWpqIRLB015anWX4aSRgnxAQ==",
"dependencies": {
"@types/semver": "^7.3.8",
"lodash": "^4.17.21"
},
"engines": {
"node": ">=4.0.0"
},
"optionalDependencies": {
"semver": "^5.6.0"
}
},
"node_modules/git-describe/node_modules/semver": {
"version": "5.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
"integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
"optional": true,
"bin": {
"semver": "bin/semver"
}
},
"node_modules/glob": { "node_modules/glob": {
"version": "7.2.3", "version": "7.2.3",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
@@ -18593,6 +18610,7 @@
"version": "4.1.0", "version": "4.1.0",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
"devOptional": true,
"dependencies": { "dependencies": {
"argparse": "^2.0.1" "argparse": "^2.0.1"
}, },
@@ -19344,8 +19362,7 @@
"node_modules/lodash": { "node_modules/lodash": {
"version": "4.17.21", "version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
"devOptional": true
}, },
"node_modules/lodash.clonedeep": { "node_modules/lodash.clonedeep": {
"version": "4.5.0", "version": "4.5.0",

View File

@@ -1,6 +1,6 @@
{ {
"name": "crowd-funder-for-time-pwa", "name": "TimeSafari",
"version": "0.1.4", "version": "0.1.6-beta",
"private": true, "private": true,
"scripts": { "scripts": {
"serve": "vue-cli-service serve", "serve": "vue-cli-service serve",
@@ -33,9 +33,9 @@
"ethereum-cryptography": "^2.1.2", "ethereum-cryptography": "^2.1.2",
"ethereumjs-util": "^7.1.5", "ethereumjs-util": "^7.1.5",
"ethr-did-resolver": "^8.1.2", "ethr-did-resolver": "^8.1.2",
"git-describe": "^4.1.1",
"jdenticon": "^3.2.0", "jdenticon": "^3.2.0",
"js-generate-password": "^0.1.9", "js-generate-password": "^0.1.9",
"js-yaml": "^4.1.0",
"localstorage-slim": "^2.5.0", "localstorage-slim": "^2.5.0",
"luxon": "^3.4.3", "luxon": "^3.4.3",
"merkletreejs": "^0.3.10", "merkletreejs": "^0.3.10",
@@ -59,7 +59,6 @@
"web-did-resolver": "^2.0.27" "web-did-resolver": "^2.0.27"
}, },
"devDependencies": { "devDependencies": {
"@types/js-yaml": "^4.0.9",
"@types/leaflet": "^1.9.4", "@types/leaflet": "^1.9.4",
"@types/ramda": "^0.29.3", "@types/ramda": "^0.29.3",
"@types/three": "^0.155.1", "@types/three": "^0.155.1",

View File

@@ -1,15 +1,20 @@
tasks: tasks:
- 40 notifications : - 08 notifications :
- push, where we trigger a ServiceWorker(?) in the app to reach out and check for new data assignee:matthew - get it to work on Android
- extract private_key_hex in py-push-server webpush.py - get it to work on iOS
- lock down regenerate_vapid endpoint (so only we admins can do it on demand) - lock down regenerate_vapid endpoint (so only we admins can do it on demand)
- remove sleep in py-push-server app.py - make the app behave correctly when App Notifications are turned off
- revisit "maybe" and "never" buttons on accont screen - remove "mute notifications"
- remove sleep in py-push-server app.py?
- see if we can detect OS-level notifications if turned off - see if we can detect OS-level notifications if turned off
- write troubleshooting docs for notifications - write troubleshooting docs for notifications
- make the "App Notifications" toggle on when they turn notifications on
- make the "App Notifications" toggle off when they turn notifications off
- in py-push-server, when sending a push to a subscriber and we get on a 410 "error #106", delete the subscription record - in py-push-server, when sending a push to a subscriber and we get on a 410 "error #106", delete the subscription record
- https://gitea.anomalistdesign.com/trent_larson/py-push-server/pulls/3/files
- remove "notification push server" advanced setting since it only makes sense on the current domain
- .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
@@ -17,6 +22,7 @@ tasks:
- .5 If notifications are not enabled, add message to front page with link/button to enable - .5 If notifications are not enabled, add message to front page with link/button to enable
- fix notification error when first loading the app
- add note after contact addition that they can see your info - add note after contact addition that they can see your info
- enhance help page instructions for debugging - enhance help page instructions for debugging
- add way to test quickly a push notification - add way to test quickly a push notification
@@ -30,7 +36,6 @@ tasks:
- add VC confirmation? - add VC confirmation?
- Release Minimum Viable Product : - Release Minimum Viable Product :
- generate new webpush.db entry, webpush.py private_key_hex & subscription_info & vapid_claims email
- .5 deploy endorser.ch server above Dec 1 (to get plan searches by names as well as descriptions) - .5 deploy endorser.ch server above Dec 1 (to get plan searches by names as well as descriptions)
- 08 thorough testing for errors & edge cases - 08 thorough testing for errors & edge cases
- 01 ensure ability to recover server remotely, and add redundant access - 01 ensure ability to recover server remotely, and add redundant access
@@ -58,6 +63,9 @@ tasks:
- switch some checks for activeDid to check for isRegistered - switch some checks for activeDid to check for isRegistered
- .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"
- .5 fix cert generation on server (since it didn't happen automatically for Nov 30) - .5 fix cert generation on server (since it didn't happen automatically for Nov 30)
- 04 fix lack of initial notification in Firefox (on MacOS, maybe others)
- contacts v+ : - contacts v+ :
- 01 Import all the non-sensitive data (ie. contacts & settings). - 01 Import all the non-sensitive data (ie. contacts & settings).
- .2 show error to user when adding a duplicate contact - .2 show error to user when adding a duplicate contact
@@ -99,6 +107,8 @@ tasks:
- automated tests, eg. cypress - automated tests, eg. cypress
- Notifications (wake on the phone, push notifications) - Notifications (wake on the phone, push notifications)
- pull instead of push, maybe via scheduled runs
- have a notification pop-up on Mac screen
- Connect with phone contacts - Connect with phone contacts
@@ -111,9 +121,6 @@ tasks:
- Do we want split first name & last name? - Do we want split first name & last name?
- 40 notifications v+ :
- 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. - 16 From the home screen, make the quick action even easier.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

@@ -169,20 +169,12 @@
> >
Turn on Notifications Turn on Notifications
</button> </button>
<div class="grid grid-cols-2 gap-2"> <button
<button @click="close(notification.id)"
@click="maybeLater(notification.id)" class="block w-full text-center text-md font-bold uppercase bg-slate-600 text-white px-2 py-2 rounded-md"
class="block w-full text-center text-md font-bold uppercase bg-slate-600 text-white px-2 py-2 rounded-md" >
> Maybe Later
Maybe Later </button>
</button>
<button
@click="never(notification.id)"
class="block w-full text-center text-md font-bold uppercase bg-rose-600 text-white px-2 py-2 rounded-md"
>
Never
</button>
</div>
</div> </div>
</div> </div>
</div> </div>
@@ -238,6 +230,10 @@
</p> </p>
<button <button
@click="
close(notification.id);
turnOffNotifications();
"
class="block w-full text-center text-md font-bold uppercase bg-rose-600 text-white px-2 py-2 rounded-md mb-2" class="block w-full text-center text-md font-bold uppercase bg-rose-600 text-white px-2 py-2 rounded-md mb-2"
> >
Turn Off Notifications Turn Off Notifications
@@ -410,7 +406,10 @@ export default class App extends Vue {
private requestNotificationPermission(): Promise<NotificationPermission> { private requestNotificationPermission(): Promise<NotificationPermission> {
return Notification.requestPermission().then((permission) => { return Notification.requestPermission().then((permission) => {
if (permission !== "granted") { if (permission !== "granted") {
alert("We need notification permission to provide certain features."); alert(
"Allow this app permission to make notifications for personal reminders." +
" You can adjust them at any time in your settings.",
);
throw new Error("We weren't granted permission."); throw new Error("We weren't granted permission.");
} }
return permission; return permission;
@@ -452,8 +451,13 @@ export default class App extends Vue {
}); });
}) })
.catch((error) => { .catch((error) => {
console.error("An error occurred:", error); console.error(
alert("Some error occurred." + error); "An error occurred setting notification permissions:",
error,
);
alert(
"Some error occurred setting notification permissions. See logs.",
);
}); });
} }
@@ -520,7 +524,7 @@ export default class App extends Vue {
private sendSubscriptionToServer( private sendSubscriptionToServer(
subscription: PushSubscription, subscription: PushSubscription,
): Promise<void> { ): Promise<void> {
console.log(subscription); console.log("About to send subscription", subscription);
return fetch("/web-push/subscribe", { return fetch("/web-push/subscribe", {
method: "POST", method: "POST",
headers: { headers: {
@@ -535,12 +539,49 @@ export default class App extends Vue {
}); });
} }
never(ID: string) { async turnOffNotifications() {
alert(ID); let subscription;
} const pushProviderSuccess = await navigator.serviceWorker.ready
.then((registration) => {
return registration.pushManager.getSubscription();
})
.then((subscript) => {
subscription = subscript;
if (subscription) {
return subscription.unsubscribe();
} else {
console.log("Subscription object is not available.");
return false;
}
})
.catch((error) => {
console.log("Push provider server communication failed:", error);
return false;
});
maybeLater(ID: string) { const pushServerSuccess = await fetch("/web-push/unsubscribe", {
alert(ID); method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(subscription),
})
.then((response) => {
return response.ok;
})
.catch((error) => {
console.log("Push server communication failed:", error);
return false;
});
alert(
"Notifications are off. Push provider unsubscribe " +
(pushProviderSuccess ? "succeeded" : "failed") +
(pushProviderSuccess === pushServerSuccess ? " and" : " but") +
" push server unsubscribe " +
(pushServerSuccess ? "succeeded" : "failed") +
".",
);
} }
} }
</script> </script>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

After

Width:  |  Height:  |  Size: 85 KiB

View File

@@ -16,7 +16,7 @@ export type Settings = {
activeDid?: string; // Active Decentralized ID activeDid?: string; // Active Decentralized ID
apiServer?: string; // API server URL apiServer?: string; // API server URL
firstName?: string; // User's first name firstName?: string; // User's first name
lastName?: string; // User's last name lastName?: string; // deprecated - put all names in firstName
lastViewedClaimId?: string; // Last viewed claim ID lastViewedClaimId?: string; // Last viewed claim ID
lastNotifiedClaimId?: string; // Last notified claim ID lastNotifiedClaimId?: string; // Last notified claim ID
isRegistered?: boolean; isRegistered?: boolean;

View File

@@ -39,7 +39,6 @@ const routes: Array<RouteRecordRaw> = [
name: "account", name: "account",
component: () => component: () =>
import(/* webpackChunkName: "account" */ "../views/AccountViewView.vue"), import(/* webpackChunkName: "account" */ "../views/AccountViewView.vue"),
beforeEnter: enterOrStart,
}, },
{ {
path: "/claim/:id?", path: "/claim/:id?",

4436
src/util.d.ts vendored

File diff suppressed because it is too large Load Diff

View File

@@ -58,9 +58,9 @@
<span v-else> <span v-else>
<router-link <router-link
:to="{ name: 'new-edit-account' }" :to="{ name: 'new-edit-account' }"
class="text-xs bg-blue-500 text-white px-1.5 py-1 rounded-md" class="block w-full text-center text-md text-slate-500 uppercase border border-dashed border-slate-400 px-1.5 py-2 rounded-md mb-2"
> >
(set name) (Set Your Name)
</router-link> </router-link>
</span> </span>
@@ -89,15 +89,23 @@
<div class="bg-slate-100 rounded-md overflow-hidden px-4 py-4 mt-8 mb-8"> <div class="bg-slate-100 rounded-md overflow-hidden px-4 py-4 mt-8 mb-8">
<label <label
for="toggleNotifications" for="toggleNotifications"
class="flex items-center cursor-pointer" class="flex items-center justify-between cursor-pointer"
@click=" @click="
this.$notify( !toggleNotifications
{ ? this.$notify(
group: 'modal', {
type: 'notification-permission', group: 'modal',
}, type: 'notification-permission',
-1, },
) -1,
)
: this.$notify(
{
group: 'modal',
type: 'notification-off',
},
-1,
)
" "
> >
<!-- label --> <!-- label -->
@@ -121,7 +129,7 @@
</label> </label>
<label <label
for="toggleMuteNotifications" for="toggleMuteNotifications"
class="flex items-center cursor-pointer mt-4" class="flex items-center justify-between cursor-pointer mt-4"
@click=" @click="
this.$notify( this.$notify(
{ {
@@ -157,7 +165,6 @@
<router-link <router-link
:to="{ name: 'seed-backup' }" :to="{ name: 'seed-backup' }"
href=""
class="block w-full text-center text-md uppercase bg-slate-500 text-white px-1.5 py-2 rounded-md mb-2" class="block w-full text-center text-md uppercase bg-slate-500 text-white px-1.5 py-2 rounded-md mb-2"
> >
Backup Identifier Seed Backup Identifier Seed
@@ -172,30 +179,42 @@
</a> </a>
<a ref="downloadLink" /> <a ref="downloadLink" />
<div v-if="activeDid" class="flex py-2"> <div v-if="activeDid" class="my-8">
<button class="text-center text-md text-blue-500" @click="checkLimits()"> <h3 class="text-sm uppercase font-semibold mb-3">Rate Limits</h3>
<button
class="block w-full text-center text-md uppercase bg-slate-500 text-white px-1.5 py-2 rounded-md mb-2"
@click="checkLimits()"
>
Check Limits Check Limits
</button> </button>
<!-- show spinner if loading limits --> <!-- show spinner if loading limits -->
<div v-if="loadingLimits" class="ml-2"> <div v-if="loadingLimits" class="text-center mb-4">
Checking... <fa icon="spinner" class="fa-spin"></fa> Checking&hellip; <fa icon="spinner" class="fa-spin"></fa>
</div> </div>
<div class="ml-2"> <div class="mb-4">
{{ limitsMessage }} {{ limitsMessage }}
</div> </div>
<div v-if="!!limits?.nextWeekBeginDateTime" class="px-9"> <div v-if="!!limits?.nextWeekBeginDateTime">
<span class="font-bold">Rate Limits</span> <p class="mb-3 text-sm">
<p> You have done <b>{{ limits.doneClaimsThisWeek }}</b> claims out of
You have done {{ limits.doneClaimsThisWeek }} claims out of <b>{{ limits.maxClaimsPerWeek }}</b> for this week. Your claims
{{ limits.maxClaimsPerWeek }} for this week. Your claims counter counter resets at
resets at {{ readableTime(limits.nextWeekBeginDateTime) }} <b class="whitespace-nowrap">{{
readableTime(limits.nextWeekBeginDateTime)
}}</b>
</p> </p>
<p> <p class="text-sm">
You have done {{ limits.doneRegistrationsThisMonth }} registrations You have done
out of {{ limits.maxRegistrationsPerMonth }} for this month. (You can <b>{{ limits.doneRegistrationsThisMonth }}</b> registrations out of
register nobody on your first day, and after that only one a day in <b>{{ limits.maxRegistrationsPerMonth }}</b> for this month.
your first month.) Your registration counter resets at <i
{{ readableTime(limits.nextMonthBeginDateTime) }} >(You can register nobody on your first day, and after that only one
a day in your first month.)</i
>
Your registration counter resets at
<b class="whitespace-nowrap">
{{ readableTime(limits.nextMonthBeginDateTime) }}
</b>
</p> </p>
</div> </div>
</div> </div>
@@ -209,13 +228,13 @@
Advanced Advanced
</h3> </h3>
<div v-if="showAdvanced"> <div v-if="showAdvanced">
<p> <p class="text-rose-600 mb-8">
Beware: the features here can be confusing and even change data in ways Beware: the features here can be confusing and even change data in ways
you do not expect. But we support your freedoms! you do not expect. But we support your freedoms!
</p> </p>
<!-- Deep Identity Details --> <!-- Deep Identity Details -->
<h2 class="text-slate-500 text-sm font-bold mb-2 py-2"> <h2 class="text-sm uppercase font-semibold mb-3">
Deep Identity Details Deep Identity Details
</h2> </h2>
<div class="bg-slate-100 rounded-md overflow-hidden px-4 py-3 mb-4"> <div class="bg-slate-100 rounded-md overflow-hidden px-4 py-3 mb-4">
@@ -273,13 +292,11 @@
<label <label
for="toggleShowAmounts" for="toggleShowAmounts"
class="flex items-center cursor-pointer py-2" class="flex items-center justify-between cursor-pointer my-4"
@click="handleChange" @click="handleChange"
> >
<!-- label --> <!-- label -->
<h2 class="text-slate-500 text-sm font-bold mb-2"> <h2>Show amounts given with contacts</h2>
Show amounts given with contacts
</h2>
<!-- toggle --> <!-- toggle -->
<div class="relative ml-2"> <div class="relative ml-2">
<!-- input --> <!-- input -->
@@ -298,26 +315,28 @@
</div> </div>
</label> </label>
<div class="flex py-2"> <router-link
<button class="text-blue-500"> :to="{ name: 'statistics' }"
<router-link :to="{ name: 'statistics' }" class="block text-center"> class="block w-full text-center text-md uppercase bg-slate-500 text-white px-1.5 py-2 rounded-md mb-2"
See Global Animated History of Giving >
</router-link> See Global Animated History of Giving
</button> </router-link>
</div>
<div class="flex py-2"> <!-- id used by puppeteer test script -->
<button class="text-blue-500"> <router-link
<!-- id used by puppeteer test script --> id="switch-identity-link"
<router-link :to="{ name: 'identity-switcher' }"
id="switch-identity-link" class="block w-full text-center text-md uppercase bg-slate-500 text-white px-1.5 py-2 rounded-md mb-2"
:to="{ name: 'identity-switcher' }" >
class="block text-center" Switch Identity / No Identity
> </router-link>
Switch Identity / No Identity
</router-link> <button
</button> @click="alertWebPushSubscription()"
</div> class="block w-full text-center text-md uppercase bg-slate-500 text-white px-1.5 py-2 rounded-md mb-2"
>
Show Subscription from Web Push Server
</button>
<div class="flex py-4"> <div class="flex py-4">
<h2 class="text-slate-500 text-sm font-bold mb-2">Claim Server</h2> <h2 class="text-slate-500 text-sm font-bold mb-2">Claim Server</h2>
@@ -457,12 +476,12 @@ export default class AccountViewView extends Vue {
showAdvanced = false; showAdvanced = false;
private isSubscribed = false; subscription: PushSubscription | null = null;
private isSubscribed = false;
get toggleNotifications() { get toggleNotifications() {
return this.isSubscribed; return this.isSubscribed;
} }
set toggleNotifications(value) { set toggleNotifications(value) {
this.isSubscribed = value; this.isSubscribed = value;
} }
@@ -549,7 +568,6 @@ export default class AccountViewView extends Vue {
* @throws Will display specific messages to the user based on different errors. * @throws Will display specific messages to the user based on different errors.
*/ */
async created() { async created() {
console.error("created");
try { try {
await db.open(); await db.open();
@@ -569,13 +587,12 @@ export default class AccountViewView extends Vue {
} }
async mounted() { async mounted() {
console.error("mounted()");
try { try {
const registration = await navigator.serviceWorker.ready; const registration = await navigator.serviceWorker.ready;
const subscription = await registration.pushManager.getSubscription(); this.subscription = await registration.pushManager.getSubscription();
this.toggleNotifications = !!subscription; this.toggleNotifications = !!this.subscription;
} catch (error) { } catch (error) {
console.error(error); console.error("Mount error:", error);
this.toggleNotifications = false; this.toggleNotifications = false;
} }
} }
@@ -927,6 +944,23 @@ export default class AccountViewView extends Vue {
webPushServer: this.webPushServerInput, webPushServer: this.webPushServerInput,
}); });
this.webPushServer = this.webPushServerInput; this.webPushServer = this.webPushServerInput;
this.$notify(
{
group: "alert",
type: "warning",
title: "Reload",
text: "Now reload the app to get a new VAPID to use with this push server.",
},
-1,
);
}
alertWebPushSubscription() {
console.log(
"Web push subscription:",
JSON.parse(JSON.stringify(this.subscription)), // gives more info than plain console logging
);
alert(JSON.stringify(this.subscription));
} }
} }
</script> </script>

View File

@@ -137,7 +137,7 @@
<div> <div>
<h2 class="font-bold text-2xl mt-8">Claim</h2> <h2 class="font-bold text-2xl mt-8">Claim</h2>
<pre>{{ yamlVeriClaim }}</pre> <pre>{{ util.inspect(veriClaim, false, null) }}</pre>
</div> </div>
<h2 class="font-bold text-2xl mt-8">Full Claim</h2> <h2 class="font-bold text-2xl mt-8">Full Claim</h2>
@@ -158,7 +158,7 @@
</button> </button>
</div> </div>
<div v-else> <div v-else>
<pre>{{ yamlFullClaim }}</pre> <pre>{{ util.inspect(fullClaim, false, null) }}</pre>
</div> </div>
<a :href="apiServer + '/api/claim/' + veriClaim.id" target="_blank"> <a :href="apiServer + '/api/claim/' + veriClaim.id" target="_blank">
@@ -186,7 +186,6 @@ import * as serverUtil from "@/libs/endorserServer";
import QuickNav from "@/components/QuickNav.vue"; import QuickNav from "@/components/QuickNav.vue";
import EntityIcon from "@/components/EntityIcon.vue"; import EntityIcon from "@/components/EntityIcon.vue";
import { Account } from "@/db/tables/accounts"; import { Account } from "@/db/tables/accounts";
import * as yaml from 'js-yaml';
interface Notification { interface Notification {
group: string; group: string;
@@ -301,8 +300,7 @@ export default class ClaimView extends Vue {
try { try {
const resp = await this.axios.get(url, { headers }); const resp = await this.axios.get(url, { headers });
if (resp.status === 200) { if (resp.status === 200) {
this.veriClaim = resp.json; this.veriClaim = resp.data;
this.yamlVeriClaim = yaml.dumps(resp.json);
} else { } else {
// actually, axios typically throws an error so we never get here // actually, axios typically throws an error so we never get here
console.log("Error getting claim:", resp); console.log("Error getting claim:", resp);
@@ -381,8 +379,7 @@ export default class ClaimView extends Vue {
try { try {
const resp = await this.axios.get(url, { headers }); const resp = await this.axios.get(url, { headers });
if (resp.status === 200) { if (resp.status === 200) {
this.fullClaim = resp.json; this.fullClaim = resp.data;
this.yamlFullClaim = yaml.dump(resp.json);
} else { } else {
// actually, axios typically throws an error so we never get here // actually, axios typically throws an error so we never get here
console.log("Error getting full claim:", resp); console.log("Error getting full claim:", resp);

View File

@@ -18,6 +18,16 @@
<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>
<p v-if="!givenName" class="text-center mt-2">
<span class="text-red">Beware!</span>
You aren't sharing your name, so hurry and
<router-link
:to="{ name: 'new-edit-account' }"
class="bg-blue-500 text-white px-1.5 py-1 rounded-md"
>
go here to set it for them.
</router-link>
</p>
</div> </div>
<div @click="onCopyToClipboard()" v-if="activeDid"> <div @click="onCopyToClipboard()" v-if="activeDid">
@@ -87,6 +97,7 @@ export default class ContactQRScanShow extends Vue {
activeDid = ""; activeDid = "";
apiServer = ""; apiServer = "";
givenName = "";
qrValue = ""; qrValue = "";
public async getIdentity(activeDid: string) { public async getIdentity(activeDid: string) {
@@ -111,6 +122,7 @@ export default class ContactQRScanShow extends Vue {
const settings = await db.settings.get(MASTER_SETTINGS_KEY); const settings = await db.settings.get(MASTER_SETTINGS_KEY);
this.activeDid = settings?.activeDid || ""; this.activeDid = settings?.activeDid || "";
this.apiServer = settings?.apiServer || ""; this.apiServer = settings?.apiServer || "";
this.givenName = settings?.firstName || "";
await accountsDB.open(); await accountsDB.open();
const accounts = await accountsDB.accounts.toArray(); const accounts = await accountsDB.accounts.toArray();

View File

@@ -19,12 +19,13 @@
</div> </div>
<!-- New Contact --> <!-- New Contact -->
<div class="mb-4 flex"> <div class="mb-4 flex items-stretch">
<span class="self-center bg-slate-500 text-white px-1.5 py-1 rounded-md"> <router-link
<router-link :to="{ name: 'contact-qr' }"> :to="{ name: 'contact-qr' }"
<fa icon="qrcode" class="fa-fw" /> class="flex items-center bg-slate-500 text-white px-1.5 py-1 mr-1 rounded-md"
</router-link> >
</span> <fa icon="qrcode" class="fa-fw text-2xl" />
</router-link>
<input <input
type="text" type="text"
placeholder="DID, Name, Public Key (base 16 or 64)" placeholder="DID, Name, Public Key (base 16 or 64)"

View File

@@ -214,9 +214,7 @@
</p> </p>
<h2 class="text-xl font-semibold">What app version is this?</h2> <h2 class="text-xl font-semibold">What app version is this?</h2>
<p> <p>{{ package.version }} ({{ commitHash }})</p>
{{ package.version }}
</p>
<h2 class="text-xl font-semibold"> <h2 class="text-xl font-semibold">
For any other questions, including removing your data: For any other questions, including removing your data:
@@ -246,6 +244,7 @@ export default class Help extends Vue {
$notify!: (notification: Notification, timeout?: number) => void; $notify!: (notification: Notification, timeout?: number) => void;
package = Package; package = Package;
commitHash = process.env.VUE_APP_GIT_HASH;
showOnboardInfo() { showOnboardInfo() {
this.$notify( this.$notify(

View File

@@ -8,28 +8,44 @@
<!-- show the actions for recognizing a give --> <!-- show the actions for recognizing a give -->
<div class="mb-8"> <div class="mb-8">
<div v-if="!activeDid"> <div
To record others' giving, v-if="!activeDid"
<router-link :to="{ name: 'start' }" class="text-blue-500"> class="bg-amber-200 rounded-md overflow-hidden text-center px-4 py-3 mb-4"
create your identifier.</router-link >
<p class="text-lg mb-3">
You need an <b>identifier</b> before you can record others' giving.
</p>
<router-link
:to="{ name: 'start' }"
class="block text-center text-md font-bold uppercase bg-slate-500 text-white px-2 py-3 rounded-md"
>
Create Your Identifier</router-link
> >
</div> </div>
<div v-else-if="!isRegistered"> <div
To record others' giving, someone must register your account, so show v-else-if="!isRegistered"
them class="bg-amber-200 rounded-md overflow-hidden text-center px-4 py-3 mb-4"
<router-link :to="{ name: 'contact-qr' }" class="text-blue-500"> >
your identity info</router-link Someone must register your account before you can record others' giving.
To do this:
<router-link
:to="{ name: 'contact-qr' }"
class="block text-center text-md font-bold uppercase bg-slate-500 text-white px-2 py-3 rounded-md"
> >
and then 1. Show Them Your Identity Info</router-link
<router-link :to="{ name: 'account' }" class="text-blue-500"> >
check your limits.</router-link <router-link
:to="{ name: 'account' }"
class="block text-center text-md font-bold uppercase bg-slate-500 text-white px-2 py-3 rounded-md"
>
2. Check Your Limits</router-link
> >
</div> </div>
<div v-else> <div v-else>
<!-- activeDid && isRegistered --> <!-- activeDid && isRegistered -->
<h2 class="text-xl font-bold">Record Something Given</h2> <h2 class="text-xl font-bold mb-4">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()">

View File

@@ -68,7 +68,7 @@ export default class NewEditAccountView extends Vue {
}); });
localStorage.setItem("firstName", this.givenName as string); localStorage.setItem("firstName", this.givenName as string);
localStorage.setItem("lastName", ""); // deprecated, pre v 0.1.3 localStorage.setItem("lastName", ""); // deprecated, pre v 0.1.3
this.$router.push({ name: "account" }); this.$router.back();
} }
onClickCancel() { onClickCancel() {

View File

@@ -3,7 +3,7 @@
<section id="Content" class="p-6 pb-24"> <section id="Content" class="p-6 pb-24">
<!-- 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 Plans Your Ideas
</h1> </h1>
<!-- Quick Search --> <!-- Quick Search -->

View File

@@ -5,7 +5,7 @@ importScripts(
); );
self.addEventListener("install", (event) => { self.addEventListener("install", (event) => {
console.error("Adding event listener for:", event); console.log("Adding event listener for:", event);
importScripts( importScripts(
"safari-notifications.js", "safari-notifications.js",
"nacl.js", "nacl.js",

View File

@@ -395,12 +395,12 @@ async function setMostRecentNotified(id) {
data["lastNotifiedClaimId"] = id; data["lastNotifiedClaimId"] = id;
await updateRecord(store, data); await updateRecord(store, data);
} else { } else {
console.error("Record not found"); console.error("IndexedDB settings record not found.");
} }
transaction.oncomplete = () => db.close(); transaction.oncomplete = () => db.close();
} catch (error) { } catch (error) {
console.error("Database error: " + error.message); console.error("IndexedDB error:", error);
} }
} }
@@ -520,7 +520,11 @@ async function getNotificationCount() {
const most_recent_notified = claims[0]["id"]; const most_recent_notified = claims[0]["id"];
await setMostRecentNotified(most_recent_notified); await setMostRecentNotified(most_recent_notified);
} else { } else {
console.error("The service worker got a bad response status when fetching claims:", response.status, response); console.error(
"The service worker got a bad response status when fetching claims:",
response.status,
response,
);
} }
break; break;
} }

View File

@@ -1,4 +1,8 @@
const { defineConfig } = require("@vue/cli-service"); const { defineConfig } = require("@vue/cli-service");
const { gitDescribeSync } = require("git-describe");
process.env.VUE_APP_GIT_HASH = gitDescribeSync().hash;
module.exports = defineConfig({ module.exports = defineConfig({
transpileDependencies: true, transpileDependencies: true,
configureWebpack: { configureWebpack: {