forked from jsnbuchanan/crowd-funder-for-time-pwa
Compare commits
22 Commits
many-misc
...
service-wo
| Author | SHA1 | Date | |
|---|---|---|---|
| 1b9ae96006 | |||
|
|
4dd5664462 | ||
|
|
7d6a45061d | ||
|
|
3b32c2b156 | ||
|
|
1ee6203f4c | ||
|
|
d93299c352 | ||
|
|
9aea7a576d | ||
| 714bb169fa | |||
| 606d9ec734 | |||
| 7a3bd069b8 | |||
| b1ac9e71cb | |||
| c1176fa24d | |||
| 1cf6660e6c | |||
| 6957678474 | |||
| 889b6d5737 | |||
| 1be10b1511 | |||
| 85405317ee | |||
| 072497a553 | |||
| 8a33ccfdcf | |||
| 7311d36726 | |||
| 7e819ea4de | |||
| 5670f23bf3 |
@@ -1,4 +1,4 @@
|
|||||||
# kickstart-for-time-pwa
|
# TimeSafari.app - Crowd-Funder for Time - PWA
|
||||||
|
|
||||||
## Project setup
|
## Project setup
|
||||||
|
|
||||||
|
|||||||
8
package-lock.json
generated
8
package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "kickstart-for-time-pwa",
|
"name": "crowd-funder-for-time-pwa",
|
||||||
"version": "0.1.3",
|
"version": "0.1.4",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "kickstart-for-time-pwa",
|
"name": "crowd-funder-for-time-pwa",
|
||||||
"version": "0.1.3",
|
"version": "0.1.4",
|
||||||
"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",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "kickstart-for-time-pwa",
|
"name": "crowd-funder-for-time-pwa",
|
||||||
"version": "0.1.3",
|
"version": "0.1.4",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"serve": "vue-cli-service serve",
|
"serve": "vue-cli-service serve",
|
||||||
@@ -72,13 +72,13 @@
|
|||||||
"@vue/cli-service": "~5.0.8",
|
"@vue/cli-service": "~5.0.8",
|
||||||
"@vue/eslint-config-typescript": "^11.0.3",
|
"@vue/eslint-config-typescript": "^11.0.3",
|
||||||
"autoprefixer": "^10.4.15",
|
"autoprefixer": "^10.4.15",
|
||||||
"eslint": "^8.48.0",
|
"eslint": "^8.53.0",
|
||||||
"eslint-config-prettier": "^9.0.0",
|
"eslint-config-prettier": "^9.0.0",
|
||||||
"eslint-plugin-prettier": "^5.0.0",
|
"eslint-plugin-prettier": "^5.0.0",
|
||||||
"eslint-plugin-vue": "^9.17.0",
|
"eslint-plugin-vue": "^9.17.0",
|
||||||
"leaflet": "^1.9.4",
|
"leaflet": "^1.9.4",
|
||||||
"postcss": "^8.4.29",
|
"postcss": "^8.4.29",
|
||||||
"prettier": "^3.0.3",
|
"prettier": "^3.1.0",
|
||||||
"tailwindcss": "^3.3.3",
|
"tailwindcss": "^3.3.3",
|
||||||
"typescript": "~5.2.2"
|
"typescript": "~5.2.2"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,14 @@
|
|||||||
|
|
||||||
tasks:
|
tasks:
|
||||||
|
|
||||||
|
- don't show "Give" & "Offer" on project screen if they don't have an identifier
|
||||||
|
- allow some gives even if they aren't registered
|
||||||
|
|
||||||
- in endorser-push-server - mount folder for persistent sqlite DB outside of container
|
- in endorser-push-server - mount folder for persistent sqlite DB outside of container
|
||||||
- 40 notifications :
|
- 40 notifications :
|
||||||
- push, where we trigger a ServiceWorker(?) in the app to reach out and check for new data assignee:matthew
|
- push, where we trigger a ServiceWorker(?) in the app to reach out and check for new data assignee:matthew
|
||||||
|
|
||||||
- .5 add project ID to the URL of the project-view, to make a project publicly-accessible
|
|
||||||
- .5 add link to further project / people when a project pays ahead
|
|
||||||
- .5 show checkbox on "gave" modal to say that user is recipient (so it could be uncheked for someone unspecified)
|
|
||||||
|
|
||||||
- .5 allow to manage their notifications even without an identity
|
- .5 allow to manage their notifications even without an identity
|
||||||
- .5 bug - on the discover page, enter a search term and search and see a duplicate project show at the end of the list
|
|
||||||
- 01 Ensure each action sent to the server has a confirmation - eg registration (ie a toast something that dismisses after 5-10s)
|
- 01 Ensure each action sent to the server has a confirmation - eg registration (ie a toast something that dismisses after 5-10s)
|
||||||
- .3 fix the Project-location-selection map display to not show on top of bottom icons (and any other UI tweaks on the map flow) assignee-group:ui
|
- .3 fix the Project-location-selection map display to not show on top of bottom icons (and any other UI tweaks on the map flow) assignee-group:ui
|
||||||
|
|
||||||
@@ -21,6 +19,7 @@ tasks:
|
|||||||
- .5 fix where user 0 sees no txns from user 1 on contacts page but sees them on list page
|
- .5 fix where user 0 sees no txns from user 1 on contacts page but sees them on list page
|
||||||
- .1 remove the logic to exclude beforeId in list of plans after server has commit 26b25af605e715600d4f12b6416ed9fd7142d164 assignee:trent
|
- .1 remove the logic to exclude beforeId in list of plans after server has commit 26b25af605e715600d4f12b6416ed9fd7142d164 assignee:trent
|
||||||
- .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"
|
||||||
|
- fix cert generation (since it didn't happen automatically for Nov 30)
|
||||||
|
|
||||||
- Discuss whether the remaining tasks are worthwhile before MVP release.
|
- Discuss whether the remaining tasks are worthwhile before MVP release.
|
||||||
|
|
||||||
@@ -32,8 +31,11 @@ tasks:
|
|||||||
- .5 Display a more appealing confirmation on the map when erasing the marker
|
- .5 Display a more appealing confirmation on the map when erasing the marker
|
||||||
- .5 make a VC details page, or link to endorser.ch
|
- .5 make a VC details page, or link to endorser.ch
|
||||||
- .1 Add units or different icon to the coins (to distinguish $, BTC, hours, etc)
|
- .1 Add units or different icon to the coins (to distinguish $, BTC, hours, etc)
|
||||||
- .5 include the hash of the latest commit on help page next to version
|
- .5 include the hash of the latest commit on help page next to version (maybe Trent's git-hash branch)
|
||||||
- .5 remove references to localStorage for projectId (now that it's pulling from the path)
|
- .5 remove references to localStorage for projectId (now that it's pulling from the path)
|
||||||
|
- bug (that is hard to reproduce) - on the second 'give' recorded on prod it showed me as the agent
|
||||||
|
- make identicons for contacts into more-memorable faces (and maybe change project identicons, too)
|
||||||
|
- allow download of each VC (to show that they can actually own their data)
|
||||||
|
|
||||||
- contacts v+ :
|
- contacts v+ :
|
||||||
- 01 Import all the non-sensitive data (ie. contacts & settings).
|
- 01 Import all the non-sensitive data (ie. contacts & settings).
|
||||||
@@ -49,6 +51,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)
|
||||||
|
|
||||||
- Release Minimum Viable Product :
|
- Release Minimum Viable Product :
|
||||||
|
- .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
|
||||||
- Turn off stats-world or ensure it's usable (eg. cannot zoom out too far and lose world, cannot screenshot).
|
- Turn off stats-world or ensure it's usable (eg. cannot zoom out too far and lose world, cannot screenshot).
|
||||||
|
|||||||
177
sample.txt
177
sample.txt
@@ -1,177 +0,0 @@
|
|||||||
|
|
||||||
> kickstart-for-time-pwa@0.1.0 build
|
|
||||||
> vue-cli-service build
|
|
||||||
|
|
||||||
All browser targets in the browserslist configuration have supported ES module.
|
|
||||||
Therefore we don't build two separate bundles for differential loading.
|
|
||||||
|
|
||||||
|
|
||||||
WARNING Compiled with 5 warnings6:06:43 PM
|
|
||||||
|
|
||||||
[eslint]
|
|
||||||
/home/matthew/projects/kick-starter-for-time-pwa/src/components/World/components/objects/landmarks.js
|
|
||||||
98:11 warning Unexpected console statement no-console
|
|
||||||
133:7 warning Unexpected console statement no-console
|
|
||||||
144:5 warning Unexpected console statement no-console
|
|
||||||
|
|
||||||
/home/matthew/projects/kick-starter-for-time-pwa/src/router/index.ts
|
|
||||||
210:3 warning Unexpected console statement no-console
|
|
||||||
|
|
||||||
/home/matthew/projects/kick-starter-for-time-pwa/src/views/AccountViewView.vue
|
|
||||||
362:7 warning Unexpected console statement no-console
|
|
||||||
375:7 warning Unexpected console statement no-console
|
|
||||||
404:7 warning Unexpected console statement no-console
|
|
||||||
516:7 warning Unexpected console statement no-console
|
|
||||||
536:7 warning Unexpected console statement no-console
|
|
||||||
630:5 warning Unexpected console statement no-console
|
|
||||||
682:7 warning Unexpected console statement no-console
|
|
||||||
|
|
||||||
/home/matthew/projects/kick-starter-for-time-pwa/src/views/ContactAmountsView.vue
|
|
||||||
206:9 warning Unexpected console statement no-console
|
|
||||||
233:9 warning Unexpected console statement no-console
|
|
||||||
|
|
||||||
/home/matthew/projects/kick-starter-for-time-pwa/src/views/ContactGiftingView.vue
|
|
||||||
244:9 warning Unexpected console statement no-console
|
|
||||||
267:7 warning Unexpected console statement no-console
|
|
||||||
|
|
||||||
/home/matthew/projects/kick-starter-for-time-pwa/src/views/ContactsView.vue
|
|
||||||
340:9 warning Unexpected console statement no-console
|
|
||||||
577:9 warning Unexpected console statement no-console
|
|
||||||
|
|
||||||
/home/matthew/projects/kick-starter-for-time-pwa/src/views/DiscoverView.vue
|
|
||||||
315:9 warning Unexpected console statement no-console
|
|
||||||
343:7 warning Unexpected console statement no-console
|
|
||||||
390:9 warning Unexpected console statement no-console
|
|
||||||
423:7 warning Unexpected console statement no-console
|
|
||||||
532:9 warning Unexpected console statement no-console
|
|
||||||
575:7 warning Unexpected console statement no-console
|
|
||||||
|
|
||||||
/home/matthew/projects/kick-starter-for-time-pwa/src/views/HomeView.vue
|
|
||||||
349:9 warning Unexpected console statement no-console
|
|
||||||
498:9 warning Unexpected console statement no-console
|
|
||||||
521:7 warning Unexpected console statement no-console
|
|
||||||
|
|
||||||
/home/matthew/projects/kick-starter-for-time-pwa/src/views/IdentitySwitcherView.vue
|
|
||||||
142:7 warning Unexpected console statement no-console
|
|
||||||
|
|
||||||
/home/matthew/projects/kick-starter-for-time-pwa/src/views/ImportAccountView.vue
|
|
||||||
123:9 warning Unexpected console statement no-console
|
|
||||||
|
|
||||||
/home/matthew/projects/kick-starter-for-time-pwa/src/views/ImportDerivedAccountView.vue
|
|
||||||
159:7 warning Unexpected console statement no-console
|
|
||||||
|
|
||||||
/home/matthew/projects/kick-starter-for-time-pwa/src/views/NewEditProjectView.vue
|
|
||||||
183:9 warning Unexpected console statement no-console
|
|
||||||
215:7 warning Unexpected console statement no-console
|
|
||||||
297:13 warning Unexpected console statement no-console
|
|
||||||
320:11 warning Unexpected console statement no-console
|
|
||||||
345:7 warning Unexpected console statement no-console
|
|
||||||
|
|
||||||
/home/matthew/projects/kick-starter-for-time-pwa/src/views/ProjectViewView.vue
|
|
||||||
387:9 warning Unexpected console statement no-console
|
|
||||||
421:7 warning Unexpected console statement no-console
|
|
||||||
457:7 warning Unexpected console statement no-console
|
|
||||||
552:9 warning Unexpected console statement no-console
|
|
||||||
554:11 warning Unexpected console statement no-console
|
|
||||||
|
|
||||||
/home/matthew/projects/kick-starter-for-time-pwa/src/views/ProjectsView.vue
|
|
||||||
131:9 warning Unexpected console statement no-console
|
|
||||||
144:7 warning Unexpected console statement no-console
|
|
||||||
221:9 warning Unexpected console statement no-console
|
|
||||||
237:7 warning Unexpected console statement no-console
|
|
||||||
|
|
||||||
/home/matthew/projects/kick-starter-for-time-pwa/src/views/SeedBackupView.vue
|
|
||||||
94:7 warning Unexpected console statement no-console
|
|
||||||
|
|
||||||
✖ 44 problems (0 errors, 44 warnings)
|
|
||||||
|
|
||||||
|
|
||||||
You may use special comments to disable some warnings.
|
|
||||||
Use // eslint-disable-next-line to ignore the next line.
|
|
||||||
Use /* eslint-disable */ to ignore all warnings in a file.
|
|
||||||
warning
|
|
||||||
|
|
||||||
/models/lupine_plant/textures/lambert2SG_baseColor.png is 3.75 MB, and won't be precached. Configure maximumFileSizeToCacheInBytes to change this limit.
|
|
||||||
|
|
||||||
warning
|
|
||||||
|
|
||||||
/models/lupine_plant/textures/lambert2SG_normal.png is 4.91 MB, and won't be precached. Configure maximumFileSizeToCacheInBytes to change this limit.
|
|
||||||
|
|
||||||
warning
|
|
||||||
|
|
||||||
asset size limit: The following asset(s) exceed the recommended size limit (244 KiB).
|
|
||||||
This can impact web performance.
|
|
||||||
Assets:
|
|
||||||
js/project.44f30c9f.js (318 KiB)
|
|
||||||
js/statistics.8a97010a.js (586 KiB)
|
|
||||||
js/chunk-vendors.a4845bfb.js (411 KiB)
|
|
||||||
js/705.f6a6ce2a.js (252 KiB)
|
|
||||||
img/textures/leafy-autumn-forest-floor.jpg (705 KiB)
|
|
||||||
models/lupine_plant/textures/lambert2SG_baseColor.png (3.58 MiB)
|
|
||||||
models/lupine_plant/textures/lambert2SG_normal.png (4.69 MiB)
|
|
||||||
|
|
||||||
warning
|
|
||||||
|
|
||||||
entrypoint size limit: The following entrypoint(s) combined asset size exceeds the recommended limit (244 KiB). This can impact web performance.
|
|
||||||
Entrypoints:
|
|
||||||
app (447 KiB)
|
|
||||||
js/chunk-vendors.a4845bfb.js
|
|
||||||
css/app.8f21529c.css
|
|
||||||
js/app.8833cebc.js
|
|
||||||
|
|
||||||
|
|
||||||
File Size Gzipped
|
|
||||||
|
|
||||||
dist/js/statistics.8a97010a.js 585.72 KiB 148.80 KiB
|
|
||||||
dist/js/chunk-vendors.a4845bfb.js 411.44 KiB 137.82 KiB
|
|
||||||
dist/js/project.44f30c9f.js 317.61 KiB 78.67 KiB
|
|
||||||
dist/js/705.f6a6ce2a.js 251.66 KiB 87.12 KiB
|
|
||||||
dist/js/891.33615e4f.js 147.32 KiB 42.09 KiB
|
|
||||||
dist/js/153.e2c8e249.js 146.26 KiB 42.21 KiB
|
|
||||||
dist/js/820.13565d16.js 66.10 KiB 18.33 KiB
|
|
||||||
dist/js/contact-qr.e170ec33.js 54.85 KiB 15.63 KiB
|
|
||||||
dist/js/772.7b4c53a7.js 30.29 KiB 7.21 KiB
|
|
||||||
dist/js/361.898a4525.js 27.40 KiB 8.19 KiB
|
|
||||||
dist/js/account.77d86130.js 17.51 KiB 5.93 KiB
|
|
||||||
dist/js/app.8833cebc.js 17.31 KiB 5.84 KiB
|
|
||||||
dist/js/contacts.3fc90ff8.js 16.94 KiB 5.52 KiB
|
|
||||||
dist/js/discover.24106939.js 15.30 KiB 5.22 KiB
|
|
||||||
dist/js/536.3bb13201.js 15.23 KiB 4.84 KiB
|
|
||||||
dist/workbox-5b385ed2.js 14.11 KiB 4.93 KiB
|
|
||||||
dist/js/home.218b99dd.js 13.89 KiB 4.97 KiB
|
|
||||||
dist/js/help.50d3117b.js 12.49 KiB 4.38 KiB
|
|
||||||
dist/js/projects.417a6cb7.js 8.71 KiB 3.00 KiB
|
|
||||||
dist/js/contact-amounts.a32b0ccd.js 8.44 KiB 3.25 KiB
|
|
||||||
dist/js/229.120e09bf.js 7.99 KiB 2.72 KiB
|
|
||||||
dist/js/identity-switcher.c7937333.js 7.44 KiB 2.52 KiB
|
|
||||||
dist/js/new-edit-project.0552181b.js 7.36 KiB 3.11 KiB
|
|
||||||
dist/js/300.dcaeb2a3.js 6.56 KiB 3.24 KiB
|
|
||||||
dist/js/seed-backup.76a0f7b3.js 3.99 KiB 1.97 KiB
|
|
||||||
dist/js/import-derive.c688d4b8.js 3.81 KiB 1.82 KiB
|
|
||||||
dist/js/import-account.c3fa35fd.js 3.54 KiB 1.66 KiB
|
|
||||||
dist/js/new-edit-account.bb763be2.js 3.39 KiB 1.51 KiB
|
|
||||||
dist/js/431.5a6d64e0.js 3.38 KiB 2.56 KiB
|
|
||||||
dist/service-worker.js 3.37 KiB 1.38 KiB
|
|
||||||
dist/js/scan-contact.46be989a.js 2.79 KiB 1.18 KiB
|
|
||||||
dist/js/start.091a7740.js 2.70 KiB 1.30 KiB
|
|
||||||
dist/js/new-identifier.bb379420.js 2.12 KiB 1.18 KiB
|
|
||||||
dist/js/93.b873dbbf.js 2.08 KiB 1.61 KiB
|
|
||||||
dist/js/new-edit-commitment.9248d367.j 1.96 KiB 1.05 KiB
|
|
||||||
s
|
|
||||||
dist/js/confirm-contact.02004d1d.js 1.89 KiB 1.04 KiB
|
|
||||||
dist/js/858.ae4c08ec.js 0.97 KiB 0.78 KiB
|
|
||||||
dist/css/app.8f21529c.css 18.41 KiB 4.39 KiB
|
|
||||||
dist/css/discover.73ee9bd3.css 14.77 KiB 6.25 KiB
|
|
||||||
dist/css/new-edit-project.73ee9bd3.css 14.77 KiB 6.25 KiB
|
|
||||||
dist/css/contacts.abb5e493.css 0.40 KiB 0.23 KiB
|
|
||||||
dist/css/contact-amounts.5b26ccd4.css 0.31 KiB 0.20 KiB
|
|
||||||
dist/css/home.828bc66e.css 0.25 KiB 0.19 KiB
|
|
||||||
dist/css/project.828bc66e.css 0.25 KiB 0.19 KiB
|
|
||||||
dist/css/statistics.828bc66e.css 0.25 KiB 0.19 KiB
|
|
||||||
|
|
||||||
Images and other types of assets omitted.
|
|
||||||
Build at: 2023-09-07T10:06:43.972Z - Hash: 2b39fcd4d0e78263 - Time: 32016ms
|
|
||||||
|
|
||||||
DONE Build complete. The dist directory is ready to be deployed.
|
|
||||||
INFO Check out deployment instructions at https://cli.vuejs.org/guide/deployment.html
|
|
||||||
|
|
||||||
171
src/App.vue
171
src/App.vue
@@ -261,7 +261,29 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Vue, Component } from "vue-facing-decorator";
|
import { Vue, Component } from "vue-facing-decorator";
|
||||||
import axios from "axios";
|
import axios, { AxiosError } from "axios";
|
||||||
|
interface ServiceWorkerMessage {
|
||||||
|
type: string;
|
||||||
|
data: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ServiceWorkerResponse {
|
||||||
|
// Define the properties and their types
|
||||||
|
success: boolean;
|
||||||
|
message?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Example interface for error
|
||||||
|
interface ErrorResponse {
|
||||||
|
message: string;
|
||||||
|
// Other properties as needed
|
||||||
|
}
|
||||||
|
|
||||||
|
interface VapidResponse {
|
||||||
|
data: {
|
||||||
|
vapidKey: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
export default class App extends Vue {
|
export default class App extends Vue {
|
||||||
@@ -269,45 +291,87 @@ export default class App extends Vue {
|
|||||||
mounted() {
|
mounted() {
|
||||||
axios
|
axios
|
||||||
.get("https://timesafari-pwa.anomalistlabs.com/web-push/vapid")
|
.get("https://timesafari-pwa.anomalistlabs.com/web-push/vapid")
|
||||||
.then((response) => {
|
.then((response: VapidResponse) => {
|
||||||
this.b64 = response.data.vapidKey;
|
this.b64 = response.data.vapidKey;
|
||||||
console.log(this.b64);
|
console.log(this.b64);
|
||||||
|
navigator.serviceWorker.addEventListener("controllerchange", () => {
|
||||||
|
console.log("New service worker is now controlling the page");
|
||||||
|
});
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error: AxiosError) => {
|
||||||
console.error("API error", error);
|
console.error("API error", error);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private sendMessageToServiceWorker(
|
||||||
|
message: ServiceWorkerMessage,
|
||||||
|
): Promise<unknown> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
if (navigator.serviceWorker.controller) {
|
||||||
|
const messageChannel = new MessageChannel();
|
||||||
|
|
||||||
|
messageChannel.port1.onmessage = (event: MessageEvent) => {
|
||||||
|
if (event.data.error) {
|
||||||
|
reject(event.data.error as ErrorResponse);
|
||||||
|
} else {
|
||||||
|
resolve(event.data as ServiceWorkerResponse);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
navigator.serviceWorker.controller.postMessage(message, [
|
||||||
|
messageChannel.port2,
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
reject("Service worker controller not available");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private askPermission(): Promise<NotificationPermission> {
|
private askPermission(): Promise<NotificationPermission> {
|
||||||
// Check if Notifications are supported
|
if (!("serviceWorker" in navigator && navigator.serviceWorker.controller)) {
|
||||||
|
return Promise.reject("Service worker not available.");
|
||||||
|
}
|
||||||
|
|
||||||
|
const secret = localStorage.getItem("secret");
|
||||||
|
if (!secret) {
|
||||||
|
return Promise.reject("No secret found.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.sendSecretToServiceWorker(secret)
|
||||||
|
.then(() => this.checkNotificationSupport())
|
||||||
|
.then(() => this.requestNotificationPermission())
|
||||||
|
.catch((error) => Promise.reject(error));
|
||||||
|
}
|
||||||
|
|
||||||
|
private sendSecretToServiceWorker(secret: string): Promise<void> {
|
||||||
|
const message: ServiceWorkerMessage = {
|
||||||
|
type: "SEND_LOCAL_DATA",
|
||||||
|
data: secret,
|
||||||
|
};
|
||||||
|
|
||||||
|
return this.sendMessageToServiceWorker(message).then((response) => {
|
||||||
|
console.log("Response from service worker:", response);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private checkNotificationSupport(): Promise<void> {
|
||||||
if (!("Notification" in window)) {
|
if (!("Notification" in window)) {
|
||||||
alert("This browser does not support notifications.");
|
alert("This browser does not support notifications.");
|
||||||
return Promise.reject("This browser does not support notifications.");
|
return Promise.reject("This browser does not support notifications.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check existing permissions
|
|
||||||
if (Notification.permission === "granted") {
|
if (Notification.permission === "granted") {
|
||||||
return Promise.resolve("granted");
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
|
||||||
// Request permission
|
private requestNotificationPermission(): Promise<NotificationPermission> {
|
||||||
return new Promise((resolve, reject) => {
|
return Notification.requestPermission().then((permission) => {
|
||||||
const permissionResult = Notification.requestPermission((result) => {
|
if (permission !== "granted") {
|
||||||
resolve(result);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (permissionResult) {
|
|
||||||
permissionResult.then(resolve, reject);
|
|
||||||
}
|
|
||||||
}).then((permissionResult) => {
|
|
||||||
console.log("Permission result:", permissionResult);
|
|
||||||
|
|
||||||
if (permissionResult !== "granted") {
|
|
||||||
alert("We need notification permission to provide certain features.");
|
alert("We need notification permission to provide certain features.");
|
||||||
return Promise.reject("We weren't granted permission.");
|
throw new Error("We weren't granted permission.");
|
||||||
}
|
}
|
||||||
|
return permission;
|
||||||
return permissionResult;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -366,34 +430,49 @@ export default class App extends Vue {
|
|||||||
return outputArray;
|
return outputArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The subscribeToPush method
|
|
||||||
private subscribeToPush(): Promise<void> {
|
private subscribeToPush(): Promise<void> {
|
||||||
return new Promise<void>((resolve, reject) => {
|
return new Promise<void>((resolve, reject) => {
|
||||||
if ("serviceWorker" in navigator && "PushManager" in window) {
|
if (!("serviceWorker" in navigator && "PushManager" in window)) {
|
||||||
const applicationServerKey = this.urlBase64ToUint8Array(this.b64);
|
|
||||||
const options: PushSubscriptionOptions = {
|
|
||||||
userVisibleOnly: true,
|
|
||||||
applicationServerKey: applicationServerKey,
|
|
||||||
};
|
|
||||||
console.log(options);
|
|
||||||
|
|
||||||
navigator.serviceWorker.ready
|
|
||||||
.then((registration) => {
|
|
||||||
return registration.pushManager.subscribe(options);
|
|
||||||
})
|
|
||||||
.then((subscription) => {
|
|
||||||
console.log("Push subscription successful:", subscription);
|
|
||||||
resolve();
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
console.error("Push subscription failed:", error, options);
|
|
||||||
reject(error);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
const errorMsg = "Push messaging is not supported";
|
const errorMsg = "Push messaging is not supported";
|
||||||
console.warn(errorMsg);
|
console.warn(errorMsg);
|
||||||
reject(new Error(errorMsg));
|
return reject(new Error(errorMsg));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Notification.permission !== "granted") {
|
||||||
|
const errorMsg = "Notification permission not granted";
|
||||||
|
console.warn(errorMsg);
|
||||||
|
return reject(new Error(errorMsg));
|
||||||
|
}
|
||||||
|
|
||||||
|
const applicationServerKey = this.urlBase64ToUint8Array(this.b64);
|
||||||
|
const options: PushSubscriptionOptions = {
|
||||||
|
userVisibleOnly: true,
|
||||||
|
applicationServerKey: applicationServerKey,
|
||||||
|
};
|
||||||
|
|
||||||
|
navigator.serviceWorker.ready
|
||||||
|
.then((registration) => {
|
||||||
|
return registration.pushManager.subscribe(options);
|
||||||
|
})
|
||||||
|
.then((subscription) => {
|
||||||
|
console.log("Push subscription successful:", subscription);
|
||||||
|
resolve();
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error(
|
||||||
|
"Subscription or server communication failed:",
|
||||||
|
error,
|
||||||
|
options,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Inform the user about the issue
|
||||||
|
alert(
|
||||||
|
"We encountered an issue setting up push notifications. " +
|
||||||
|
"If you wish to revoke notification permissions, please do so in your browser settings.",
|
||||||
|
);
|
||||||
|
|
||||||
|
reject(error);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
placeholder="What was received"
|
placeholder="What was received"
|
||||||
v-model="description"
|
v-model="description"
|
||||||
/>
|
/>
|
||||||
<div class="flex flex-row mb-6">
|
<div class="flex flex-row">
|
||||||
<span
|
<span
|
||||||
class="rounded-l border border-r-0 border-slate-400 bg-slate-200 w-1/3 text-center px-2 py-2"
|
class="rounded-l border border-r-0 border-slate-400 bg-slate-200 w-1/3 text-center px-2 py-2"
|
||||||
>Hours</span
|
>Hours</span
|
||||||
@@ -33,7 +33,13 @@
|
|||||||
<fa icon="chevron-right" />
|
<fa icon="chevron-right" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-center mb-2 italic">Sign & Send to publish to the world</p>
|
<div v-if="showGivenToUser" class="mt-2 text-right">
|
||||||
|
<input type="checkbox" class="mr-2" v-model="givenToUser" />
|
||||||
|
<label class="text-sm">Given to you</label>
|
||||||
|
</div>
|
||||||
|
<p class="text-center mb-2 mt-6 italic">
|
||||||
|
Sign & Send to publish to the world
|
||||||
|
</p>
|
||||||
<button
|
<button
|
||||||
class="block w-full text-center text-lg font-bold uppercase bg-blue-600 text-white px-2 py-3 rounded-md mb-2"
|
class="block w-full text-center text-lg font-bold uppercase bg-blue-600 text-white px-2 py-3 rounded-md mb-2"
|
||||||
@click="confirm"
|
@click="confirm"
|
||||||
@@ -70,12 +76,14 @@ export default class GiftedDialog extends Vue {
|
|||||||
|
|
||||||
@Prop message = "";
|
@Prop message = "";
|
||||||
@Prop projectId = "";
|
@Prop projectId = "";
|
||||||
|
@Prop showGivenToUser = false;
|
||||||
|
|
||||||
activeDid = "";
|
activeDid = "";
|
||||||
apiServer = "";
|
apiServer = "";
|
||||||
|
|
||||||
giver?: GiverInputInfo;
|
giver?: GiverInputInfo; // undefined means no identified giver agent
|
||||||
description = "";
|
description = "";
|
||||||
|
givenToUser = false;
|
||||||
hours = "0";
|
hours = "0";
|
||||||
visible = false;
|
visible = false;
|
||||||
|
|
||||||
@@ -103,11 +111,17 @@ export default class GiftedDialog extends Vue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
open(giver: GiverInputInfo) {
|
open(giver: GiverInputInfo) {
|
||||||
|
this.description = "";
|
||||||
this.giver = giver;
|
this.giver = giver;
|
||||||
|
// if we show "given to user" selection, default checkbox to true
|
||||||
|
this.givenToUser = this.showGivenToUser;
|
||||||
|
this.hours = "0";
|
||||||
|
|
||||||
this.visible = true;
|
this.visible = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
close() {
|
close() {
|
||||||
|
// close the dialog but don't change values (since it might be submitting info)
|
||||||
this.visible = false;
|
this.visible = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,8 +135,13 @@ export default class GiftedDialog extends Vue {
|
|||||||
|
|
||||||
cancel() {
|
cancel() {
|
||||||
this.close();
|
this.close();
|
||||||
|
this.eraseValues();
|
||||||
|
}
|
||||||
|
|
||||||
|
eraseValues() {
|
||||||
this.description = "";
|
this.description = "";
|
||||||
this.giver = undefined;
|
this.giver = undefined;
|
||||||
|
this.givenToUser = this.showGivenToUser;
|
||||||
this.hours = "0";
|
this.hours = "0";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,14 +157,12 @@ export default class GiftedDialog extends Vue {
|
|||||||
1000,
|
1000,
|
||||||
);
|
);
|
||||||
// this is asynchronous, but we don't need to wait for it to complete
|
// this is asynchronous, but we don't need to wait for it to complete
|
||||||
this.recordGive(
|
await this.recordGive(
|
||||||
this.giver?.did as string | undefined,
|
this.giver?.did as string | undefined,
|
||||||
this.description,
|
this.description,
|
||||||
parseFloat(this.hours),
|
parseFloat(this.hours),
|
||||||
).then(() => {
|
).then(() => {
|
||||||
this.description = "";
|
this.eraseValues();
|
||||||
this.giver = undefined;
|
|
||||||
this.hours = "0";
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -209,7 +226,7 @@ export default class GiftedDialog extends Vue {
|
|||||||
this.apiServer,
|
this.apiServer,
|
||||||
identity,
|
identity,
|
||||||
giverDid,
|
giverDid,
|
||||||
this.activeDid,
|
this.givenToUser ? this.activeDid : undefined,
|
||||||
description,
|
description,
|
||||||
hours,
|
hours,
|
||||||
this.projectId,
|
this.projectId,
|
||||||
@@ -238,7 +255,7 @@ export default class GiftedDialog extends Vue {
|
|||||||
title: "Success",
|
title: "Success",
|
||||||
text: "That gift was recorded.",
|
text: "That gift was recorded.",
|
||||||
},
|
},
|
||||||
10000,
|
7000,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
import { register } from "register-service-worker";
|
import { register } from "register-service-worker";
|
||||||
|
|
||||||
if (process.env.NODE_ENV === "production") {
|
if (process.env.NODE_ENV === "production") {
|
||||||
register(`${process.env.BASE_URL}service-worker.js`, {
|
register("/additional-scripts.js", {
|
||||||
ready() {
|
ready() {
|
||||||
console.log(
|
console.log(
|
||||||
"App is being served from cache by a service worker.\n" +
|
"App is being served from cache by a service worker.\n" +
|
||||||
|
|||||||
@@ -66,7 +66,11 @@
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<GiftedDialog ref="customDialog" message="Received from"> </GiftedDialog>
|
<GiftedDialog
|
||||||
|
ref="customDialog"
|
||||||
|
message="Received from"
|
||||||
|
showGivenToUser="true"
|
||||||
|
/>
|
||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -20,16 +20,18 @@
|
|||||||
</h1>
|
</h1>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!--
|
<div @click="onCopyToClipboard()">
|
||||||
Play with display options: https://qr-code-styling.com/
|
<!--
|
||||||
See docs: https://www.npmjs.com/package/qr-code-generator-vue3
|
Play with display options: https://qr-code-styling.com/
|
||||||
-->
|
See docs: https://www.npmjs.com/package/qr-code-generator-vue3
|
||||||
<QRCodeVue3
|
-->
|
||||||
:value="this.qrValue"
|
<QRCodeVue3
|
||||||
:cornersSquareOptions="{ type: 'extra-rounded' }"
|
:value="this.qrValue"
|
||||||
:dotsOptions="{ type: 'square' }"
|
:cornersSquareOptions="{ type: 'extra-rounded' }"
|
||||||
class="flex justify-center"
|
:dotsOptions="{ type: 'square' }"
|
||||||
/>
|
class="flex justify-center"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<h1 class="text-4xl text-center font-light pt-4">Scan Contact Info</h1>
|
<h1 class="text-4xl text-center font-light pt-4">Scan Contact Info</h1>
|
||||||
<qrcode-stream @detect="onScanDetect" @error="onScanError" />
|
<qrcode-stream @detect="onScanDetect" @error="onScanError" />
|
||||||
@@ -40,6 +42,7 @@
|
|||||||
import QRCodeVue3 from "qr-code-generator-vue3";
|
import QRCodeVue3 from "qr-code-generator-vue3";
|
||||||
import { Component, Vue } from "vue-facing-decorator";
|
import { Component, Vue } from "vue-facing-decorator";
|
||||||
import { QrcodeStream } from "vue-qrcode-reader";
|
import { QrcodeStream } from "vue-qrcode-reader";
|
||||||
|
import { useClipboard } from "@vueuse/core";
|
||||||
|
|
||||||
import { accountsDB, db } from "@/db/index";
|
import { accountsDB, db } from "@/db/index";
|
||||||
import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
|
import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
|
||||||
@@ -179,5 +182,22 @@ export default class ContactQRScanShow extends Vue {
|
|||||||
-1,
|
-1,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onCopyToClipboard() {
|
||||||
|
useClipboard()
|
||||||
|
.copy(this.qrValue)
|
||||||
|
.then(() => {
|
||||||
|
console.log("Contact URL:", this.qrValue);
|
||||||
|
this.$notify(
|
||||||
|
{
|
||||||
|
group: "alert",
|
||||||
|
type: "toast",
|
||||||
|
title: "Copied",
|
||||||
|
text: "Contact URL was copied to clipboard.",
|
||||||
|
},
|
||||||
|
2000,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<!-- Quick Search -->
|
<!-- Quick Search -->
|
||||||
<div id="QuickSearch" class="mb-4 flex" v-on:keyup.enter="searchAll()">
|
<div id="QuickSearch" class="mb-4 flex" v-on:keyup.enter="searchSelected()">
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
v-model="searchTerms"
|
v-model="searchTerms"
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
class="block w-full rounded-l border border-r-0 border-slate-400 px-3 py-2"
|
class="block w-full rounded-l border border-r-0 border-slate-400 px-3 py-2"
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
@click="searchAll()"
|
@click="searchSelected()"
|
||||||
class="px-4 rounded-r bg-slate-200 border border-l-0 border-slate-400"
|
class="px-4 rounded-r bg-slate-200 border border-l-0 border-slate-400"
|
||||||
>
|
>
|
||||||
<fa icon="magnifying-glass" class="fa-fw"></fa>
|
<fa icon="magnifying-glass" class="fa-fw"></fa>
|
||||||
@@ -41,8 +41,10 @@
|
|||||||
Nearby
|
Nearby
|
||||||
<span
|
<span
|
||||||
class="font-semibold text-sm bg-slate-200 px-1.5 py-0.5 rounded-md"
|
class="font-semibold text-sm bg-slate-200 px-1.5 py-0.5 rounded-md"
|
||||||
>{{ localCount > -1 ? localCount : "?" }}</span
|
v-if="isLocalActive"
|
||||||
>
|
>
|
||||||
|
{{ localCount > -1 ? localCount : "?" }}
|
||||||
|
</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
@@ -59,8 +61,10 @@
|
|||||||
Anywhere
|
Anywhere
|
||||||
<span
|
<span
|
||||||
class="font-semibold text-sm bg-slate-200 px-1.5 py-0.5 rounded-md"
|
class="font-semibold text-sm bg-slate-200 px-1.5 py-0.5 rounded-md"
|
||||||
>{{ remoteCount > -1 ? remoteCount : "?" }}</span
|
v-if="isRemoteActive"
|
||||||
>
|
>
|
||||||
|
{{ remoteCount > -1 ? remoteCount : "?" }}
|
||||||
|
</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -156,12 +160,12 @@ export default class DiscoverView extends Vue {
|
|||||||
apiServer = "";
|
apiServer = "";
|
||||||
searchTerms = "";
|
searchTerms = "";
|
||||||
projects: ProjectData[] = [];
|
projects: ProjectData[] = [];
|
||||||
|
isLoading = false;
|
||||||
isLocalActive = true;
|
isLocalActive = true;
|
||||||
isRemoteActive = false;
|
isRemoteActive = false;
|
||||||
localCount = -1;
|
localCount = -1;
|
||||||
remoteCount = -1;
|
remoteCount = -1;
|
||||||
searchBox: { name: string; bbox: BoundingBox } | null = null;
|
searchBox: { name: string; bbox: BoundingBox } | null = null;
|
||||||
isLoading = false;
|
|
||||||
|
|
||||||
// make this function available to the Vue template
|
// make this function available to the Vue template
|
||||||
didInfo = didInfo;
|
didInfo = didInfo;
|
||||||
@@ -188,6 +192,19 @@ export default class DiscoverView extends Vue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public resetCounts() {
|
||||||
|
this.localCount = -1;
|
||||||
|
this.remoteCount = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async searchSelected() {
|
||||||
|
if (this.isLocalActive) {
|
||||||
|
await this.searchLocal();
|
||||||
|
} else {
|
||||||
|
await this.searchAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public async buildHeaders(): Promise<HeadersInit> {
|
public async buildHeaders(): Promise<HeadersInit> {
|
||||||
const headers: HeadersInit = {
|
const headers: HeadersInit = {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
@@ -213,6 +230,13 @@ export default class DiscoverView extends Vue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async searchAll(beforeId?: string) {
|
public async searchAll(beforeId?: string) {
|
||||||
|
this.resetCounts();
|
||||||
|
|
||||||
|
if (!beforeId) {
|
||||||
|
// this was an initial search so clear any previous results
|
||||||
|
this.projects = [];
|
||||||
|
}
|
||||||
|
|
||||||
let queryParams = "claimContents=" + encodeURIComponent(this.searchTerms);
|
let queryParams = "claimContents=" + encodeURIComponent(this.searchTerms);
|
||||||
|
|
||||||
if (beforeId) {
|
if (beforeId) {
|
||||||
@@ -275,13 +299,21 @@ export default class DiscoverView extends Vue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async searchLocal(beforeId?: string) {
|
public async searchLocal(beforeId?: string) {
|
||||||
|
this.resetCounts();
|
||||||
|
|
||||||
if (!this.searchBox) {
|
if (!this.searchBox) {
|
||||||
this.projects = [];
|
this.projects = [];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!beforeId) {
|
||||||
|
// this was an initial search so clear any previous results
|
||||||
|
this.projects = [];
|
||||||
|
}
|
||||||
|
|
||||||
const claimContents =
|
const claimContents =
|
||||||
"claimContents=" + encodeURIComponent(this.searchTerms);
|
"claimContents=" + encodeURIComponent(this.searchTerms);
|
||||||
|
|
||||||
let queryParams = [
|
let queryParams = [
|
||||||
claimContents,
|
claimContents,
|
||||||
"minLocLat=" + this.searchBox.bbox.minLat,
|
"minLocLat=" + this.searchBox.bbox.minLat,
|
||||||
@@ -376,7 +408,7 @@ export default class DiscoverView extends Vue {
|
|||||||
onClickLoadProject(id: string) {
|
onClickLoadProject(id: string) {
|
||||||
localStorage.setItem("projectId", id);
|
localStorage.setItem("projectId", id);
|
||||||
const route = {
|
const route = {
|
||||||
name: "project",
|
path: "/project/" + encodeURIComponent(id),
|
||||||
};
|
};
|
||||||
this.$router.push(route);
|
this.$router.push(route);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -189,6 +189,15 @@
|
|||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<h2 class="text-xl font-semibold">Where can I read more?</h2>
|
||||||
|
<p>
|
||||||
|
This is part of the
|
||||||
|
<a href="https://livesofgiving.org" class="text-blue-500">
|
||||||
|
Lives of Giving
|
||||||
|
</a>
|
||||||
|
initiative.
|
||||||
|
</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 }}
|
{{ package.version }}
|
||||||
|
|||||||
@@ -81,7 +81,11 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<GiftedDialog ref="customDialog" message="Received from"> </GiftedDialog>
|
<GiftedDialog
|
||||||
|
ref="customDialog"
|
||||||
|
message="Received from"
|
||||||
|
showGivenToUser="true"
|
||||||
|
/>
|
||||||
|
|
||||||
<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">
|
||||||
<h2 class="text-xl font-bold mb-4">Latest Activity</h2>
|
<h2 class="text-xl font-bold mb-4">Latest Activity</h2>
|
||||||
|
|||||||
@@ -45,7 +45,7 @@
|
|||||||
type="checkbox"
|
type="checkbox"
|
||||||
class="mr-2"
|
class="mr-2"
|
||||||
v-model="includeLocation"
|
v-model="includeLocation"
|
||||||
@change="includeLocation = true"
|
@click="includeLocation = !includeLocation"
|
||||||
/>
|
/>
|
||||||
<label for="includeLocation">Include Location</label>
|
<label for="includeLocation">Include Location</label>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -210,35 +210,37 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="fulfilledByThis" class="bg-slate-100 px-4 py-3 rounded-md">
|
<div class="grid items-start grid-cols-1 gap-4">
|
||||||
<h3 class="text-sm uppercase font-semibold mb-3">
|
<div
|
||||||
Contributions By This Project
|
v-if="fulfillersToThis.length > 0"
|
||||||
</h3>
|
class="bg-slate-100 px-4 py-3 rounded-md"
|
||||||
<button
|
|
||||||
@click="onClickLoadProject(fulfilledByThis.handleId)"
|
|
||||||
class="text-blue-500"
|
|
||||||
>
|
>
|
||||||
{{ fulfilledByThis.name }}
|
<h3 class="text-sm uppercase font-semibold mb-3">
|
||||||
</button>
|
Contributions To This Project
|
||||||
</div>
|
</h3>
|
||||||
|
<ul>
|
||||||
|
<li v-for="plan in fulfillersToThis" :key="plan.handleId">
|
||||||
|
<button
|
||||||
|
@click="onClickLoadProject(plan.handleId)"
|
||||||
|
class="text-blue-500"
|
||||||
|
>
|
||||||
|
{{ plan.name }}
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div
|
<div v-if="fulfilledByThis" class="bg-slate-100 px-4 py-3 rounded-md">
|
||||||
v-if="fulfillersToThis.length > 0"
|
<h3 class="text-sm uppercase font-semibold mb-3">
|
||||||
class="bg-slate-100 px-4 py-3 rounded-md"
|
Contributions By This Project
|
||||||
>
|
</h3>
|
||||||
<h3 class="text-sm uppercase font-semibold mb-3">
|
<button
|
||||||
Contributions To This Project
|
@click="onClickLoadProject(fulfilledByThis.handleId)"
|
||||||
</h3>
|
class="text-blue-500"
|
||||||
<ul>
|
>
|
||||||
<li v-for="plan in fulfillersToThis" :key="plan.handleId">
|
{{ fulfilledByThis.name }}
|
||||||
<button
|
</button>
|
||||||
@click="onClickLoadProject(plan.handleId)"
|
</div>
|
||||||
class="text-blue-500"
|
|
||||||
>
|
|
||||||
{{ plan.name }}
|
|
||||||
</button>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -174,7 +174,7 @@ export default class ProjectsView extends Vue {
|
|||||||
onClickLoadProject(id: string) {
|
onClickLoadProject(id: string) {
|
||||||
localStorage.setItem("projectId", id);
|
localStorage.setItem("projectId", id);
|
||||||
const route = {
|
const route = {
|
||||||
name: "project",
|
path: "/project/" + encodeURIComponent(id),
|
||||||
};
|
};
|
||||||
this.$router.push(route);
|
this.$router.push(route);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,33 +1,65 @@
|
|||||||
const notifications = require("./safari-notifications.js");
|
/* eslint-env serviceworker */
|
||||||
|
/* global workbox */
|
||||||
|
importScripts(
|
||||||
|
"https://storage.googleapis.com/workbox-cdn/releases/6.4.1/workbox-sw.js",
|
||||||
|
);
|
||||||
|
|
||||||
|
self.addEventListener("install", (event) => {
|
||||||
|
console.error(event);
|
||||||
|
importScripts(
|
||||||
|
"safari-notifications.js",
|
||||||
|
"nacl.js",
|
||||||
|
"noble-curves.js",
|
||||||
|
"noble-hashes.js",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
self.addEventListener("push", function (event) {
|
self.addEventListener("push", function (event) {
|
||||||
let payload;
|
event.waitUntil(
|
||||||
if (event.data) {
|
(async () => {
|
||||||
payload = JSON.parse(event.data.text());
|
try {
|
||||||
|
let payload;
|
||||||
|
if (event.data) {
|
||||||
|
payload = JSON.parse(event.data.text());
|
||||||
|
}
|
||||||
|
const message = await self.getNotificationCount();
|
||||||
|
console.error(message);
|
||||||
|
const title = payload ? payload.title : "Custom Title";
|
||||||
|
const options = {
|
||||||
|
body: message,
|
||||||
|
icon: payload ? payload.icon : "icon.png",
|
||||||
|
badge: payload ? payload.badge : "badge.png",
|
||||||
|
};
|
||||||
|
await self.registration.showNotification(title, options);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error in processing the push event:", error);
|
||||||
|
}
|
||||||
|
})(),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
self.addEventListener("message", (event) => {
|
||||||
|
if (event.data && event.data.type === "SEND_LOCAL_DATA") {
|
||||||
|
self.secret = event.data.data;
|
||||||
|
event.ports[0].postMessage({ success: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
const title = payload ? payload.title : "Custom Title";
|
|
||||||
const options = {
|
|
||||||
body: payload ? payload.body : "Custom body text",
|
|
||||||
icon: payload ? payload.icon : "icon.png",
|
|
||||||
badge: payload ? payload.badge : "badge.png",
|
|
||||||
};
|
|
||||||
|
|
||||||
event.waitUntil(self.registration.showNotification(title, options));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
self.addEventListener("activate", (event) => {
|
||||||
self.addEventListener("message", function (event) {
|
event.waitUntil(clients.claim());
|
||||||
const data = event.data;
|
console.log("Service worker activated", event);
|
||||||
|
|
||||||
const result = notifications.getNotificationCount()
|
|
||||||
|
|
||||||
switch (data.command) {
|
|
||||||
case "account":
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
console.log("Unknown command:", data.command);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
self.addEventListener("fetch", (event) => {
|
||||||
|
console.log(event.request);
|
||||||
|
});
|
||||||
|
|
||||||
|
self.addEventListener("error", (event) => {
|
||||||
|
console.error("Error in Service Worker:", event.message);
|
||||||
|
console.error("File:", event.filename);
|
||||||
|
console.error("Line:", event.lineno);
|
||||||
|
console.error("Column:", event.colno);
|
||||||
|
console.error("Error Object:", event.error);
|
||||||
|
});
|
||||||
|
|
||||||
|
workbox.precaching.precacheAndRoute(self.__WB_MANIFEST);
|
||||||
|
|||||||
1051
sw_scripts/nacl.js
Normal file
1051
sw_scripts/nacl.js
Normal file
File diff suppressed because it is too large
Load Diff
5248
sw_scripts/noble-curves.js
Normal file
5248
sw_scripts/noble-curves.js
Normal file
File diff suppressed because it is too large
Load Diff
3068
sw_scripts/noble-hashes.js
Normal file
3068
sw_scripts/noble-hashes.js
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -11,8 +11,9 @@ module.exports = defineConfig({
|
|||||||
iconPaths: {
|
iconPaths: {
|
||||||
faviconSVG: "img/icons/safari-pinned-tab.svg",
|
faviconSVG: "img/icons/safari-pinned-tab.svg",
|
||||||
},
|
},
|
||||||
|
workboxPluginMode: "InjectManifest",
|
||||||
workboxOptions: {
|
workboxOptions: {
|
||||||
importScripts: ["additional-scripts.js"],
|
swSrc: "./sw_scripts/additional-scripts.js",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user