feat: prepare for push notification
This commit is contained in:
@@ -68,7 +68,7 @@
|
|||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div id="root">
|
<div id="root">
|
||||||
请开启javascript,或 <a href="#" onClick="force_reload">强制刷新</a>
|
请开启javascript,或等待资源加载完成,或<a href="#" onClick="force_reload">强制刷新</a>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -39,6 +39,8 @@ class App extends Component {
|
|||||||
|
|
||||||
window.BACKEND =
|
window.BACKEND =
|
||||||
localStorage['BACKEND'] || process.env.REACT_APP_BACKEND || '/';
|
localStorage['BACKEND'] || process.env.REACT_APP_BACKEND || '/';
|
||||||
|
|
||||||
|
if (process.env.NODE_ENV === 'production') {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
fetch('https://api.github.com/users/hole-thu')
|
fetch('https://api.github.com/users/hole-thu')
|
||||||
.then((resp) => resp.json())
|
.then((resp) => resp.json())
|
||||||
@@ -55,6 +57,7 @@ class App extends Component {
|
|||||||
});
|
});
|
||||||
}, 12345);
|
}, 12345);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static is_darkmode() {
|
static is_darkmode() {
|
||||||
if (window.config.color_scheme === 'dark') return true;
|
if (window.config.color_scheme === 'dark') return true;
|
||||||
|
|||||||
@@ -14,6 +14,9 @@ import renderMd from './Markdown';
|
|||||||
|
|
||||||
export { format_time, Time, TitleLine };
|
export { format_time, Time, TitleLine };
|
||||||
|
|
||||||
|
const pushServerPublicKey =
|
||||||
|
'BLM6zZy2CWlsfQ9KsALDgrjPXBf8E3cJ7qQ5vZipN_IjOfeDXFjeYb_zRLzwglyiwr9QpVL9Lt1TS_sZKewJYuY';
|
||||||
|
|
||||||
export const STORAGE_BASE = `${process.env.REACT_APP_STORAGE || '/'}`;
|
export const STORAGE_BASE = `${process.env.REACT_APP_STORAGE || '/'}`;
|
||||||
|
|
||||||
export function get_api_base() {
|
export function get_api_base() {
|
||||||
@@ -24,6 +27,22 @@ export function get_api_base_2() {
|
|||||||
return `${window.BACKEND}_api/v2`;
|
return `${window.BACKEND}_api/v2`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function get_push_subscription() {
|
||||||
|
if (!('serviceWorker' in navigator)) return;
|
||||||
|
let serviceWorker = await navigator.serviceWorker.ready;
|
||||||
|
if (!('pushManager' in serviceWorker)) return;
|
||||||
|
let subscription = await serviceWorker.pushManager.getSubscription();
|
||||||
|
//subscription.unsubscribe();
|
||||||
|
if (!subscription) {
|
||||||
|
subscription = await serviceWorker.pushManager.subscribe({
|
||||||
|
userVisibleOnly: true,
|
||||||
|
applicationServerKey: pushServerPublicKey,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
console.log('subscription:', JSON.stringify(subscription));
|
||||||
|
return subscription;
|
||||||
|
}
|
||||||
|
|
||||||
// https://stackoverflow.com/questions/3446170/escape-string-for-use-in-javascript-regex
|
// https://stackoverflow.com/questions/3446170/escape-string-for-use-in-javascript-regex
|
||||||
function escape_regex(string) {
|
function escape_regex(string) {
|
||||||
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
|
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
|
||||||
|
|||||||
24
src/Flows.js
24
src/Flows.js
@@ -9,6 +9,7 @@ import {
|
|||||||
ClickHandler,
|
ClickHandler,
|
||||||
ColoredSpan,
|
ColoredSpan,
|
||||||
HighlightedMarkdown,
|
HighlightedMarkdown,
|
||||||
|
get_push_subscription,
|
||||||
} from './Common';
|
} from './Common';
|
||||||
import './Flows.css';
|
import './Flows.css';
|
||||||
import LazyLoad, { forceCheck } from 'react-lazyload';
|
import LazyLoad, { forceCheck } from 'react-lazyload';
|
||||||
@@ -749,6 +750,29 @@ class FlowSidebar extends PureComponent {
|
|||||||
</a>
|
</a>
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
|
{!!this.props.token && !!this.state.attention && (
|
||||||
|
<span>
|
||||||
|
<a
|
||||||
|
href="###"
|
||||||
|
style={{ display: 'none' }}
|
||||||
|
onClick={() => {
|
||||||
|
console.log('set notifi');
|
||||||
|
get_push_subscription().then((sc) => {
|
||||||
|
if (!sc) return;
|
||||||
|
fetch('/_test', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify(sc),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span className="icon icon-star">提醒</span>
|
||||||
|
</a>
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
{!!this.state.filter_name && (
|
{!!this.state.filter_name && (
|
||||||
<div className="box box-tip flow-item filter-name-bar">
|
<div className="box box-tip flow-item filter-name-bar">
|
||||||
|
|||||||
@@ -61,22 +61,27 @@ export function InfoSidebar(props) {
|
|||||||
href="###"
|
href="###"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if ('serviceWorker' in navigator) {
|
if ('serviceWorker' in navigator) {
|
||||||
navigator.serviceWorker
|
navigator.serviceWorker.ready.then((serviceWorker) => {
|
||||||
.getRegistrations()
|
const waitingServiceWorker = serviceWorker.waiting;
|
||||||
.then((registrations) => {
|
if (waitingServiceWorker) {
|
||||||
for (let registration of registrations) {
|
cache().clear();
|
||||||
console.log('unregister', registration);
|
waitingServiceWorker.addEventListener(
|
||||||
registration.unregister();
|
'statechange',
|
||||||
|
(event) => {
|
||||||
|
if (event.target.state === 'activated') {
|
||||||
|
window.location.reload();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
waitingServiceWorker.postMessage({ type: 'SKIP_WAITING' });
|
||||||
|
} else {
|
||||||
|
alert('没有已下载的更新');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
cache().clear();
|
|
||||||
setTimeout(() => {
|
|
||||||
window.location.reload(true);
|
|
||||||
}, 200);
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
强制检查更新
|
立即更新
|
||||||
</a>
|
</a>
|
||||||
(当前版本:【{process.env.REACT_APP_BUILD_INFO || '---'}{' '}
|
(当前版本:【{process.env.REACT_APP_BUILD_INFO || '---'}{' '}
|
||||||
{process.env.NODE_ENV}】 会自动在后台检查更新并在下次访问时更新)
|
{process.env.NODE_ENV}】 会自动在后台检查更新并在下次访问时更新)
|
||||||
|
|||||||
@@ -71,3 +71,28 @@ self.addEventListener('message', (event) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Any other custom service worker logic can go here.
|
// Any other custom service worker logic can go here.
|
||||||
|
function receivePushNotification(event) {
|
||||||
|
console.log('[Service Worker] Push Received.');
|
||||||
|
|
||||||
|
const { title, pid, text } = event.data.json();
|
||||||
|
|
||||||
|
const options = {
|
||||||
|
data: `${self.location.origin}/##${pid}`,
|
||||||
|
body: text,
|
||||||
|
};
|
||||||
|
|
||||||
|
event.waitUntil(self.registration.showNotification(title, options));
|
||||||
|
}
|
||||||
|
|
||||||
|
function openPushNotification(event) {
|
||||||
|
console.log(
|
||||||
|
'[Service Worker] Notification click Received.',
|
||||||
|
event.notification.data,
|
||||||
|
);
|
||||||
|
|
||||||
|
event.notification.close();
|
||||||
|
event.waitUntil(self.clients.openWindow(event.notification.data));
|
||||||
|
}
|
||||||
|
|
||||||
|
self.addEventListener('push', receivePushNotification);
|
||||||
|
self.addEventListener('notificationclick', openPushNotification);
|
||||||
|
|||||||
Reference in New Issue
Block a user