PageSourceSearch

https://video.tractor-club.com/firebase-messaging-sw.js

js tractor-club.com collected 2026-10-02 12:11:40 UTC 3,190 bytes, 126 lines download raw bytes

1// firebase-messaging-sw.js
2
3importScripts('https://www.gstatic.com/firebasejs/10.12.0/firebase-app-compat.js')
4importScripts('https://www.gstatic.com/firebasejs/10.12.0/firebase-messaging-compat.js')
5
6firebase.initializeApp({
7  apiKey: "AIzaSyAX3qy4xTSWiYRUp_ixrN5WW5CRanF-sDk",
8  authDomain: "tractorfc-notif.firebaseapp.com/",
9  projectId: "tractorfc-notif",
10  messagingSenderId: "365905624254",
11  appId: "1:365905624254:web:23b1d7d5b1aa3e2fc332ef",
12}) 
13
14const messaging = firebase.messaging()
15
16/**
17 * Build notification options based on event type
18 */
19function buildNotification(payload) {
20  const data = payload.data || {}
21
22  const baseOptions = {
23    body: data.body || '',
24    icon: data.icon || '/mono-logo.png',
25    badge: data.badge || '/mono-logo.png',
26    image: data.image,               
27    tag: data.tag || 'general',      
28    renotify: true,
29    vibrate: [100, 50, 100],
30    data: {
31      url: data.url || '/',          // deep link
32      eventType: data.type,
33      entityId: data.entityId,
34    },
35  }
36
37  // 🔀 Different templates based on event type
38  switch (data.type) {
39    case 'match_start':
40      return {
41        title: data.title || 'Match Started ⚽',
42        options: {
43          ...baseOptions,
44          actions: [
45            { action: 'watch', title: 'Watch Live' },
46          ],
47          tag: `match-${data.entityId}`,
48        },
49      }
50
51    case 'goal':
52      return {
53        title: data.title || 'GOAL ⚽',
54        options: {
55          ...baseOptions,
56          vibrate: [200, 100, 200],
57          tag: `goal-${data.entityId}`,
58        },
59      }
60
61    case 'announcement':
62      return {
63        title: data.title || 'Announcement 📢',
64        options: {
65          ...baseOptions,
66          actions: [
67            { action: 'open', title: 'Open' },
68          ],
69        },
70      }
71
72    default:
73      return {
74        title: data.title || 'Tractor FC',
75        options: baseOptions,
76      }
77  }
78}
79
80// Handle background messages
81messaging.onBackgroundMessage((payload) => {
82
83  // Prevent duplicates from notification payloads
84  if (payload.notification) return
85
86  const notification = buildNotification(payload)
87
88  if (notification.title && notification.options.body) {
89    self.registration.showNotification(
90      notification.title,
91      notification.options
92    )
93  }
94})
95
96// Handle notification click
97self.addEventListener('notificationclick', (event) => {
98  event.notification.close()
99
100  const action = event.action
101  const data = event.notification.data || {}
102  const baseUrl = self.location.origin
103
104  let targetUrl = baseUrl
105
106  if (action === 'watch') {
107    targetUrl = new URL(data.url || '/', baseUrl).href
108  } else if (action === 'open') {
109    targetUrl = new URL(data.url || '/', baseUrl).href
110  } else if (data.url) {
111    targetUrl = new URL(data.url, baseUrl).href
112  }
113
114  event.waitUntil(
115    clients.matchAll({ type: 'window', includeUncontrolled: true }).then((clientList) => {
116      for (const client of clientList) {
117        if (client.url === targetUrl && 'focus' in client) {
118          return client.focus()
119        }
120      }
121      if (clients.openWindow) {
122        return clients.openWindow(targetUrl)
123      }
124    })
125  )
126})

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.