Skip to content

Commit

Permalink
Fix SDK handling of Chrome silent push notification permissions prompt (
Browse files Browse the repository at this point in the history
#44)

* Add a check to determine whether the native push perms prompt is shown

* Implement new push manager state for blocked native prompt request

* Fix existing issue where channel prompt would show after declining push notifications

* Acknowlege new requesting-silent state when rending prompts

* [WIP] assume native prompt shown for all browsers excl chrome and edge

* Apply native prompt detection for chrome only

* Remove dom loaded check as it already is and add guards for requesting-silent manager state

* Uprev, refresh install, audit fix and generate bundles

* Remove unused imports and tidy up

* Update bundle

Co-authored-by: Rob Dick <r.dick@kumulos.com>
  • Loading branch information
robdick and krobd authored Oct 20, 2021
1 parent b9cb61c commit 5d7b3f4
Show file tree
Hide file tree
Showing 14 changed files with 70 additions and 19 deletions.
2 changes: 1 addition & 1 deletion dist/index.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/worker.js

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@kumulos/web",
"version": "1.10.1",
"version": "1.10.2",
"description": "Official SDK for integrating Kumulos services with your web projects",
"main": "dist/index.js",
"types": "types/src/index.d.ts",
Expand Down
2 changes: 1 addition & 1 deletion src/core/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { authedFetch, cyrb53, uuidv4 } from './utils';
import { del, get, set } from './storage';
import { Channel } from './channels';

const SDK_VERSION = '1.10.1';
const SDK_VERSION = '1.10.2';
const SDK_TYPE = 10;
const EVENTS_BASE_URL = 'https://events.kumulos.com';
export const PUSH_BASE_URL = 'https://push.kumulos.com';
Expand Down
1 change: 1 addition & 0 deletions src/core/push/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export interface PushOpsManager {
): Promise<PushSubscriptionState>;
getCurrentSubscriptionState(ctx: Context): Promise<PushSubscriptionState>;
handleAutoResubscription(ctx: Context): Promise<void>;
isNativePromptShown(): Promise<boolean>;
}

export interface KumulosPushNotification {
Expand Down
4 changes: 4 additions & 0 deletions src/core/push/safari.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,4 +138,8 @@ export default class SafariPushManager implements PushOpsManager {

return this.pushRegister(ctx);
}

async isNativePromptShown(): Promise<boolean> {
return Promise.resolve(true);
}
}
34 changes: 33 additions & 1 deletion src/core/push/w3c.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { Context, EventType, trackEvent } from '..';
import { PushOpsManager, PushSubscriptionState, TokenType } from '.';
import { base64UrlEncode, cyrb53 } from '../utils';
import { base64UrlEncode, cyrb53, getBrowserName } from '../utils';
import { get, set } from '../storage';

const BLUR_EVENT_TIMEOUT_MILLIS = 2000;

function hasSameKey(vapidKey: string, subscription: PushSubscription): boolean {
const existingSubKey = subscription.options.applicationServerKey;

Expand Down Expand Up @@ -182,4 +184,34 @@ export default class W3cPushManager implements PushOpsManager {
console.error(e);
}
}

isNativePromptShown(): Promise<boolean> {
const browserName = getBrowserName();

if ('chrome' !== browserName) {
return Promise.resolve(true);
}

return new Promise(resolve => {
let blurEventFired = false;

const checkForBlur = () => {
if (blurEventFired) {
return;
}

clearTimeout(cancelBlurTimeout);
window.removeEventListener('blur', checkForBlur);
blurEventFired = true;

resolve(true);
};
window.addEventListener('blur', checkForBlur);

const cancelBlurTimeout = setTimeout(() => {
window.removeEventListener('blur', checkForBlur);
resolve(false);
}, BLUR_EVENT_TIMEOUT_MILLIS);
});
}
}
23 changes: 14 additions & 9 deletions src/prompts/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export type PromptManagerState =
| 'loading'
| 'ready'
| 'requesting'
| 'requesting-silent'
| 'postaction';

// loading -> ready
Expand Down Expand Up @@ -88,13 +89,19 @@ export class PromptManager {
};

private onRequestNativePrompt = async (prompt: PushPromptConfig) => {
if ('requesting' === this.state) {
if ('requesting' === this.state || 'requesting-silent' === this.state) {
return;
}

this.currentlyRequestingPrompt = prompt;

this.setState('requesting');
this.pushOpsManager?.isNativePromptShown().then(isNativePromptShown => {
if (isNativePromptShown) {
this.setState('requesting');
} else {
this.setState('requesting-silent');
}
});

this.subscriptionState = await this.pushOpsManager?.requestPermissionAndRegisterForPush(
this.context
Expand Down Expand Up @@ -131,11 +138,10 @@ export class PromptManager {

this.hideAndSuppressPrompts(prompt);

await this.handlePromptActions(prompt);

await this.handleUserChannelSelection(channelSelections);

if (this.subscriptionState === 'subscribed') {
await this.handlePromptActions(prompt);
await this.handleUserChannelSelection(channelSelections);

this.ui?.showToast(prompt.labels?.thanksForSubscribing!);
}
};
Expand Down Expand Up @@ -373,9 +379,6 @@ export class PromptManager {
.listChannels();
this.setState('ready');
break;
case 'requesting':
this.render();
break;
case 'ready':
this.currentlyRequestingPrompt = undefined;
this.currentPostAction = undefined;
Expand All @@ -386,6 +389,8 @@ export class PromptManager {
this.render();
break;
case 'postaction':
case 'requesting':
case 'requesting-silent':
this.render();
break;
}
Expand Down
10 changes: 8 additions & 2 deletions src/prompts/ui.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,10 @@ export default class Ui extends Component<UiProps, UiState> {
}

maybeRenderPromptBackgroundMask() {
if ('requesting' === this.props.promptManagerState) {
if (
'requesting' === this.props.promptManagerState ||
'requesting-silent' === this.props.promptManagerState
) {
return null;
}

Expand All @@ -293,7 +296,10 @@ export default class Ui extends Component<UiProps, UiState> {
}

renderPrompt(prompt: PushPromptConfig) {
if ('requesting' === this.props.promptManagerState) {
if (
'requesting' === this.props.promptManagerState ||
'requesting-silent' === this.props.promptManagerState
) {
return null;
}

Expand Down
1 change: 1 addition & 0 deletions types/src/core/push/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export interface PushOpsManager {
requestPermissionAndRegisterForPush(ctx: Context): Promise<PushSubscriptionState>;
getCurrentSubscriptionState(ctx: Context): Promise<PushSubscriptionState>;
handleAutoResubscription(ctx: Context): Promise<void>;
isNativePromptShown(): Promise<boolean>;
}
export interface KumulosPushNotification {
id: number;
Expand Down
1 change: 1 addition & 0 deletions types/src/core/push/safari.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ export default class SafariPushManager implements PushOpsManager {
requestPermissionAndRegisterForPush(ctx: Context): Promise<PushSubscriptionState>;
getCurrentSubscriptionState(ctx: Context): Promise<PushSubscriptionState>;
handleAutoResubscription(ctx: Context): Promise<void>;
isNativePromptShown(): Promise<boolean>;
}
1 change: 1 addition & 0 deletions types/src/core/push/w3c.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ export default class W3cPushManager implements PushOpsManager {
requestPermissionAndRegisterForPush(ctx: Context): Promise<import('.').PushSubscriptionState>;
getCurrentSubscriptionState(ctx: Context): Promise<PushSubscriptionState>;
handleAutoResubscription(ctx: Context): Promise<void>;
isNativePromptShown(): Promise<boolean>;
}
2 changes: 1 addition & 1 deletion types/src/prompts/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Context, PushPromptConfig } from '../core';
import Kumulos from '..';
import RootFrame from '../core/root-frame';
export declare type PromptManagerState = 'loading' | 'ready' | 'requesting' | 'postaction';
export declare type PromptManagerState = 'loading' | 'ready' | 'requesting' | 'requesting-silent' | 'postaction';
export declare class PromptManager {
private readonly kumulosClient;
private readonly context;
Expand Down

0 comments on commit 5d7b3f4

Please sign in to comment.