1- < div class ="mb-3 "
2- id ="notifications-settings "
3- x-cloak
4- x-data ="notificationsSettings() "
5- x-init ="init() ">
6- < h6 > Настройки напоминаний</ h6 >
7-
8- < div class ="border rounded-3 p-3 bg-white mb-4 "
9- x-show ="!isActive "
10- >
11- < div class ="d-flex align-items-center justify-content-between mb-2 ">
12- < span class ="badge bg-secondary "> Отключено</ span >
13- </ div >
14- < div class ="text-muted small mb-3 " style ="height: 2.5em ">
15- Напоминания не активированы на этом устройстве.
16- </ div >
17- < button @click ="enable() "
18- class ="btn btn-outline-secondary w-100 ">
19- Включить напоминания
20- </ button >
21- </ div >
22-
23- < div class ="border rounded-3 p-3 bg-white mb-4 "
24- x-show ="isActive "
25- >
26- < div class ="d-flex justify-content-between align-items-center mb-2 ">
27- < span class ="badge bg-success "> Активно</ span >
28- </ div >
29- < div class ="text-muted small mb-3 " style ="height: 2.5em ">
30- Напоминания о планировании приёмов: каждый понедельник, 09:00 утра
31- </ div >
32- < button @click ="disable() "
33- class ="btn btn-outline-danger w-100 ">
34- Отключить напоминания
35- </ button >
36- </ div >
1+ < div id ="notifications-settings ">
372
383 < script >
39- document . addEventListener ( 'alpine:init' , ( ) => {
40- Alpine . data ( 'notificationsSettings' , ( ) => ( {
41- isActive : false ,
42-
43- async init ( ) {
44- if ( ! ( 'serviceWorker' in navigator ) || ! ( 'PushManager' in window ) ) {
45- console . warn ( "Push isn't supported by the browser" ) ;
46- return ;
47- }
48-
49- const existing = await this . getSubscription ( ) ;
50- if ( ! existing ) {
51- this . isActive = false ;
52- return ;
53- }
54-
55- this . isActive = true ;
56- console . info ( "Notification settings initialized" )
57- } ,
58-
59- async enable ( ) {
60- console . info ( "Enabling notifications" )
61- const perm = await this . ensurePermission ( ) ;
62- console . debug ( 'enable(): permission' , perm ) ;
63- if ( perm !== 'granted' ) {
64- return ;
65- }
66-
67- const sub = await this . subscribe ( ) ;
68- console . debug ( 'enable(): sub' , sub ) ;
69- if ( ! sub ) {
70- return ;
71- }
72-
73- const saved = await this . saveSubscription ( sub ) ;
74- console . debug ( 'enable(): savedSub' , saved ) ;
75- if ( ! saved ) {
76- return ;
77- }
78-
79- this . isActive = true ;
80- } ,
81-
82- async disable ( ) {
83- const swReg = await navigator . serviceWorker . ready ;
84- const sub = await swReg . pushManager . getSubscription ( ) ;
85- if ( ! sub ) {
86- this . isActive = false ;
87- return ;
88- }
89-
90- const { keys} = sub . toJSON ( ) ;
91- const p256dh = keys ?. p256dh ;
92- await fetch ( `/pushes/web/subscriptions/${ p256dh } ` , {
93- method : 'DELETE' ,
94- } ) ;
4+ Alpine . data ( 'notificationsSettings' , ( ) => ( {
5+ isActive : false ,
956
96- await sub . unsubscribe ( ) ;
7+ async init ( ) {
8+ if ( ! ( 'serviceWorker' in navigator ) || ! ( 'PushManager' in window ) ) {
9+ console . warn ( "Push isn't supported by the browser" ) ;
10+ return ;
11+ }
12+
13+ const existing = await this . getSubscription ( ) ;
14+ if ( ! existing ) {
9715 this . isActive = false ;
98- } ,
99-
100- async ensurePermission ( ) {
101- if ( Notification . permission === 'denied' ) {
102- console . info ( 'Notifications are denied' ) ;
103- return 'denied' ;
104- }
105- if ( Notification . permission === 'default' ) {
106- return await Notification . requestPermission ( ) ;
107- }
108- return Notification . permission ;
109- } ,
110-
111- async subscribe ( ) {
112- if ( ! ( 'serviceWorker' in navigator ) || ! ( 'PushManager' in window ) ) {
113- console . debug ( 'subscribe(): PushManager unavailable' ) ;
114- return null ;
115- }
116-
117- try {
118- console . debug ( 'subscribe(): fetching VAPID key' ) ;
119- let resp = await fetch ( '/pushes/web/public-key' ) ;
120- const vapidKey = ( await resp . text ( ) ) . trim ( ) ;
121- console . debug ( 'subscribe(): fetch status' , resp . status , resp . redirected ) ;
122-
123- const swReg = await navigator . serviceWorker . ready ;
124- console . debug ( 'subscribe(): service worker scope' , swReg . scope ) ;
125-
126- let subscription = await swReg . pushManager . subscribe ( {
127- userVisibleOnly : true ,
128- applicationServerKey : urlBase64ToUint8Array ( vapidKey )
129- } ) ;
130- console . debug ( 'subscribe(): success' ) ;
131-
132- return subscription ;
133- } catch ( e ) {
134- console . error ( 'Push subscription failed' , e ) ;
135- return null ;
136- }
137- } ,
138-
139- async saveSubscription ( sub ) {
140- const response = await fetch ( '/pushes/web/subscriptions' , {
141- method : 'POST' ,
142- headers : { 'Content-Type' : 'application/json' } ,
143- body : JSON . stringify ( sub )
144- } ) ;
145- if ( ! response . ok || response . redirected ) {
146- return false ;
147- }
148- return true ;
149- } ,
16+ return ;
17+ }
18+
19+ this . isActive = true ;
20+ console . info ( "Notification settings initialized" )
21+ } ,
22+
23+ async enable ( ) {
24+ console . info ( "Enabling notifications" )
25+ const perm = await this . ensurePermission ( ) ;
26+ console . debug ( 'enable(): permission' , perm ) ;
27+ if ( perm !== 'granted' ) {
28+ return ;
29+ }
30+
31+ const sub = await this . subscribe ( ) ;
32+ console . debug ( 'enable(): sub' , sub ) ;
33+ if ( ! sub ) {
34+ return ;
35+ }
36+
37+ const saved = await this . saveSubscription ( sub ) ;
38+ console . debug ( 'enable(): savedSub' , saved ) ;
39+ if ( ! saved ) {
40+ return ;
41+ }
42+
43+ this . isActive = true ;
44+ } ,
45+
46+ async disable ( ) {
47+ const swReg = await navigator . serviceWorker . ready ;
48+ const sub = await swReg . pushManager . getSubscription ( ) ;
49+ if ( ! sub ) {
50+ this . isActive = false ;
51+ return ;
52+ }
53+
54+ const { keys} = sub . toJSON ( ) ;
55+ const p256dh = keys ?. p256dh ;
56+ await fetch ( `/pushes/web/subscriptions/${ p256dh } ` , {
57+ method : 'DELETE' ,
58+ } ) ;
59+
60+ await sub . unsubscribe ( ) ;
61+ this . isActive = false ;
62+ } ,
63+
64+ async ensurePermission ( ) {
65+ if ( Notification . permission === 'denied' ) {
66+ console . info ( 'Notifications are denied' ) ;
67+ return 'denied' ;
68+ }
69+ if ( Notification . permission === 'default' ) {
70+ return await Notification . requestPermission ( ) ;
71+ }
72+ return Notification . permission ;
73+ } ,
74+
75+ async subscribe ( ) {
76+ if ( ! ( 'serviceWorker' in navigator ) || ! ( 'PushManager' in window ) ) {
77+ console . debug ( 'subscribe(): PushManager unavailable' ) ;
78+ return null ;
79+ }
80+
81+ try {
82+ console . debug ( 'subscribe(): fetching VAPID key' ) ;
83+ let resp = await fetch ( '/pushes/web/public-key' ) ;
84+ const vapidKey = ( await resp . text ( ) ) . trim ( ) ;
85+ console . debug ( 'subscribe(): fetch status' , resp . status , resp . redirected ) ;
15086
151- async getSubscription ( ) {
15287 const swReg = await navigator . serviceWorker . ready ;
153- return swReg . pushManager . getSubscription ( ) ;
154- } ,
88+ console . debug ( 'subscribe(): service worker scope' , swReg . scope ) ;
15589
156- } ) ) ;
157- } ) ;
90+ let subscription = await swReg . pushManager . subscribe ( {
91+ userVisibleOnly : true ,
92+ applicationServerKey : urlBase64ToUint8Array ( vapidKey )
93+ } ) ;
94+ console . debug ( 'subscribe(): success' ) ;
95+
96+ return subscription ;
97+ } catch ( e ) {
98+ console . error ( 'Push subscription failed' , e ) ;
99+ return null ;
100+ }
101+ } ,
102+
103+ async saveSubscription ( sub ) {
104+ const response = await fetch ( '/pushes/web/subscriptions' , {
105+ method : 'POST' ,
106+ headers : { 'Content-Type' : 'application/json' } ,
107+ body : JSON . stringify ( sub )
108+ } ) ;
109+ if ( ! response . ok || response . redirected ) {
110+ return false ;
111+ }
112+ return true ;
113+ } ,
114+
115+ async getSubscription ( ) {
116+ const swReg = await navigator . serviceWorker . ready ;
117+ return swReg . pushManager . getSubscription ( ) ;
118+ } ,
119+
120+ } ) ) ;
158121
159122 function urlBase64ToUint8Array ( base64String ) {
160123 const padding = '=' . repeat ( ( 4 - ( base64String . length % 4 ) ) % 4 ) ;
@@ -167,4 +130,44 @@ <h6>Настройки напоминаний</h6>
167130 return outputArray ;
168131 }
169132 </ script >
133+ < div class ="mb-3 "
134+ x-cloak
135+ x-data ="notificationsSettings() "
136+ x-init ="init() ">
137+ < h6 > Настройки напоминаний</ h6 >
138+
139+ < div class ="border rounded-3 p-3 bg-white mb-4 "
140+ x-show ="!isActive "
141+ >
142+ < div class ="d-flex align-items-center justify-content-between mb-2 ">
143+ < span class ="badge bg-secondary "> Отключено</ span >
144+ </ div >
145+ < div class ="text-muted small mb-3 " style ="height: 2.5em ">
146+ Напоминания не активированы на этом устройстве.
147+ </ div >
148+ < button @click ="enable() "
149+ class ="btn btn-outline-secondary w-100 ">
150+ Включить напоминания
151+ </ button >
152+ </ div >
153+
154+ < div class ="border rounded-3 p-3 bg-white mb-4 "
155+ x-show ="isActive "
156+ >
157+ < div class ="d-flex justify-content-between align-items-center mb-2 ">
158+ < span class ="badge bg-success "> Активно</ span >
159+ </ div >
160+ < div class ="text-muted small mb-3 " style ="height: 2.5em ">
161+ Напоминания о планировании приёмов: каждый
162+ < span id ="fill-sched-remainder-day " th:text ="${fillScheduleRemainderDay} "> понедельник</ span >
163+ в
164+ < span id ="fill-sched-remainder-time " th:text ="${fillScheduleRemainderTime} "> 09:00</ span >
165+ </ div >
166+ < button @click ="disable() "
167+ class ="btn btn-outline-danger w-100 ">
168+ Отключить напоминания
169+ </ button >
170+ </ div >
171+
172+ </ div >
170173</ div >
0 commit comments