Browse Source

Merge pull request 'allow to customize the push-server for testing' (#80) from set-push-server into master

Reviewed-on: https://gitea.anomalistdesign.com/trent_larson/crowd-funder-for-time-pwa/pulls/80
pull/90/head
trentlarson 12 months ago
parent
commit
feea1a1d3b
  1. 4
      CHANGELOG.md
  2. 7
      README.md
  3. 60
      src/App.vue
  4. 11
      src/constants/app.ts
  5. 3
      src/db/index.ts
  6. 2
      src/db/tables/settings.ts
  7. 71
      src/views/AccountViewView.vue
  8. 2
      src/views/ProjectViewView.vue
  9. 10
      web-push.md

4
CHANGELOG.md

@ -8,8 +8,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
### Added
- Web push notifications
## [0.1.3] - 2023.11
## [0.1.3] - 2023.11.08 - 910f57ec7d2e50803ae3d04f4b927e0f5219fbde
### Added
- Contact name editing
### Changed

7
README.md

@ -94,10 +94,9 @@ For your own web-push tests, change the 'vapid' URL in App.vue, and install apps
### Clear/Reset data & restart
* Data: Clear the browser cache for localhost.
* Notifications:
* Under browser settings, look for "notification" and remove this server.
* Under about:debugging, find the service worker and Unregister.
* Clear cache for localhost.
* Unregister service worker (in Chrome, go to `chrome://serviceworker-internals/`; in Firefox, go to `about:serviceworkers` or `about:debugging`).
* Clear notification permission (in Chrome, go to `chrome://settings/content/notifications`; in Firefox, go to `about:preferences` and search).

60
src/App.vue

@ -261,7 +261,7 @@
<script lang="ts">
import { Vue, Component } from "vue-facing-decorator";
import axios, { AxiosError } from "axios";
import axios from "axios";
interface ServiceWorkerMessage {
type: string;
data: string;
@ -285,22 +285,64 @@ interface VapidResponse {
};
}
import { AppString } from "@/constants/app";
import { db } from "@/db/index";
import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
interface Notification {
group: string;
type: string;
title: string;
text: string;
}
@Component
export default class App extends Vue {
$notify!: (notification: Notification, timeout?: number) => void;
b64 = "";
mounted() {
axios
.get("https://timesafari-pwa.anomalistlabs.com/web-push/vapid")
async mounted() {
try {
await db.open();
const settings = await db.settings.get(MASTER_SETTINGS_KEY);
let pushUrl: string = AppString.DEFAULT_PUSH_SERVER;
if (settings?.webPushServer) {
pushUrl = settings.webPushServer;
}
await axios
.get(pushUrl + "/web-push/vapid")
.then((response: VapidResponse) => {
this.b64 = response.data.vapidKey;
console.log(this.b64);
this.b64 = response.data?.vapidKey || "";
console.log("Got vapid key:", this.b64);
navigator.serviceWorker.addEventListener("controllerchange", () => {
console.log("New service worker is now controlling the page");
});
})
.catch((error: AxiosError) => {
console.error("API error", error);
});
if (!this.b64) {
this.$notify(
{
group: "alert",
type: "danger",
title: "Error Setting Notifications",
text: "Could not set notifications.",
},
-1,
);
}
} catch (error) {
console.error("Got an error initializing notifications:", error);
this.$notify(
{
group: "alert",
type: "danger",
title: "Error Setting Notifications",
text: "Got an error setting notifications.",
},
-1,
);
}
}
private sendMessageToServiceWorker(

11
src/constants/app.ts

@ -11,13 +11,20 @@ export enum AppString {
LOCAL_ENDORSER_API_SERVER = "http://localhost:3000",
DEFAULT_ENDORSER_API_SERVER = TEST_ENDORSER_API_SERVER,
PROD_PUSH_SERVER = "https://timesafari.app",
TEST1_PUSH_SERVER = "https://test.timesafari.app",
TEST2_PUSH_SERVER = "https://timesafari-pwa.anomalistlabs.com",
DEFAULT_PUSH_SERVER = TEST1_PUSH_SERVER,
}
/**
* See notiwind package
* The possible values for "group" and "type" are in App.vue.
* From the notiwind package
*/
export interface NotificationIface {
group: string;
group: string; // "alert" | "modal"
type: string; // "toast" | "info" | "success" | "warning" | "danger"
title: string;
text: string;

3
src/db/index.ts

@ -45,5 +45,8 @@ db.on("populate", () => {
db.settings.add({
id: MASTER_SETTINGS_KEY,
apiServer: AppString.DEFAULT_ENDORSER_API_SERVER,
// remember that things you add from now on aren't automatically in the DB for old users
webPushServer: AppString.DEFAULT_PUSH_SERVER,
});
});

2
src/db/tables/settings.ts

@ -20,9 +20,9 @@ export type Settings = {
lastViewedClaimId?: string; // Last viewed claim ID
lastNotifiedClaimId?: string; // Last notified claim ID
isRegistered?: boolean;
webPushServer?: string; // Web Push server URL
// Array of named search boxes defined by bounding boxes
searchBoxes?: Array<{
name: string;
bbox: BoundingBox;

71
src/views/AccountViewView.vue

@ -324,30 +324,71 @@
<fa icon="floppy-disk" class="fa-fw" color="white"></fa>
</button>
<button
class="px-4 rounded bg-slate-200 border border-slate-400"
@click="setApiServerInput(Constants.PROD_ENDORSER_API_SERVER)"
class="px-3 rounded bg-slate-200 border border-slate-400"
@click="apiServerInput = AppConstants.PROD_ENDORSER_API_SERVER"
>
Use Prod
</button>
<button
class="px-4 rounded bg-slate-200 border border-slate-400"
@click="setApiServerInput(Constants.TEST_ENDORSER_API_SERVER)"
class="px-3 rounded bg-slate-200 border border-slate-400"
@click="apiServerInput = AppConstants.TEST_ENDORSER_API_SERVER"
>
Use Test
</button>
<button
class="px-4 rounded bg-slate-200 border border-slate-400"
@click="setApiServerInput(Constants.LOCAL_ENDORSER_API_SERVER)"
class="px-3 rounded bg-slate-200 border border-slate-400"
@click="apiServerInput = AppConstants.LOCAL_ENDORSER_API_SERVER"
>
Use Local
</button>
</div>
<div class="flex py-4">
<h2 class="text-slate-500 text-sm font-bold mb-2">
Notification Push Server
</h2>
<input
type="text"
class="block w-full rounded border border-slate-400 px-3 py-2"
v-model="webPushServerInput"
/>
<button
v-if="webPushServerInput != webPushServer"
class="px-4 rounded bg-red-500 border border-slate-400"
@click="onClickSavePushServer()"
>
<fa icon="floppy-disk" class="fa-fw" color="white"></fa>
</button>
<button
class="px-3 rounded bg-slate-200 border border-slate-400"
@click="webPushServerInput = AppConstants.PROD_PUSH_SERVER"
>
Use Prod
</button>
<button
class="px-3 rounded bg-slate-200 border border-slate-400"
@click="webPushServerInput = AppConstants.TEST1_PUSH_SERVER"
>
Use Test 1
</button>
<button
class="px-3 rounded bg-slate-200 border border-slate-400"
@click="webPushServerInput = AppConstants.TEST2_PUSH_SERVER"
>
Use Test 2
</button>
</div>
<span class="px-4 text-sm" v-if="!webPushServerInput">
When that setting is blank, this app will use the default web push
server URL:
{{ AppConstants.DEFAULT_PUSH_SERVER }}
</span>
</div>
</section>
</template>
<script lang="ts">
import { AxiosError } from "axios";
import { AxiosError, AxiosRequestConfig } from "axios";
import "dexie-export-import";
import { Component, Vue } from "vue-facing-decorator";
import { useClipboard } from "@vueuse/core";
@ -381,7 +422,7 @@ interface IAccount {
export default class AccountViewView extends Vue {
$notify!: (notification: Notification, timeout?: number) => void;
Constants = AppString;
AppConstants = AppString;
activeDid = "";
apiServer = "";
@ -392,6 +433,8 @@ export default class AccountViewView extends Vue {
numAccounts = 0;
publicHex = "";
publicBase64 = "";
webPushServer = "";
webPushServerInput = "";
limits: RateLimits | null = null;
limitsMessage = "";
loadingLimits = true; // might as well now that we do it on mount, to avoid flashing the registration message
@ -516,6 +559,8 @@ export default class AccountViewView extends Vue {
(settings?.firstName || "") +
(settings?.lastName ? ` ${settings.lastName}` : ""); // pre v 0.1.3
this.isRegistered = !!settings?.isRegistered;
this.webPushServer = (settings?.webPushServer as string) || "";
this.webPushServerInput = (settings?.webPushServer as string) || "";
this.showContactGives = !!settings?.showContactGivesInline;
}
@ -740,7 +785,7 @@ export default class AccountViewView extends Vue {
private async fetchRateLimits(identity: IIdentifier) {
const url = `${this.apiServer}/api/report/rateLimits`;
const headers = await this.getHeaders(identity);
return await this.axios.get(url, { headers });
return await this.axios.get(url, { headers } as AxiosRequestConfig);
}
/**
@ -844,8 +889,12 @@ export default class AccountViewView extends Vue {
this.apiServer = this.apiServerInput;
}
setApiServerInput(value: string) {
this.apiServerInput = value;
async onClickSavePushServer() {
await db.open();
db.settings.update(MASTER_SETTINGS_KEY, {
webPushServer: this.webPushServerInput,
});
this.webPushServer = this.webPushServerInput;
}
}
</script>

2
src/views/ProjectViewView.vue

@ -625,7 +625,7 @@ export default class ProjectViewView extends Vue {
}
openOfferDialog() {
(this.$refs.customOfferDialog as OfferDialog).open();
(this.$refs.customOfferDialog as typeof OfferDialog).open();
}
}
</script>

10
web-push.md

@ -390,3 +390,13 @@ While notifications are turned on, the user can tap on the App Notifications tog
- "Turn off Notifications" to fully turn them off (which means the user will need to go through the dialogs agains to turn them back on).
- "Leave it On" to make no changes and dismiss the dialog.
# NOTIFICATION STATES
* Unpermissioned. Push server cannot send notifications to the user because it does not have permission.
This may be the same as when the user gave permission in the past but has since revoked it at the OS or browser
level, outside the app. (User can change to Permissioned when the user gives permission.)
* Permissioned. (User can change to Unpermissioned via the OS or browser settings.)
* Active. (User can change to Muted when the user mutes notifications.)
* Muted. (User can change to Active when the user toggles it.)
(Turning mute off automatically after some amount of time is not planned in version 1.)

Loading…
Cancel
Save