@@ -19,7 +19,7 @@ const supabase = createClient(supabaseUrl, supabaseServiceKey);
1919
2020// Configure webpush
2121webpush . setVapidDetails (
22- 'mailto:admin@starsailors.app ' ,
22+ 'mailto:teddy@scroobl.es ' ,
2323 vapidPublicKey ,
2424 vapidPrivateKey
2525) ;
@@ -48,6 +48,19 @@ async function findUsersWithUnclassifiedDiscoveries() {
4848
4949 console . log ( `Found ${ linkedAnomalies ?. length || 0 } linked anomalies` ) ;
5050
51+ // Get already notified anomalies from push_anomaly_log
52+ const { data : notifiedAnomalies , error : notifiedError } = await supabase
53+ . from ( 'push_anomaly_log' )
54+ . select ( 'anomaly_id' ) ;
55+
56+ if ( notifiedError ) {
57+ console . error ( 'Error fetching notified anomalies:' , notifiedError ) ;
58+ return [ ] ;
59+ }
60+
61+ console . log ( `Found ${ notifiedAnomalies ?. length || 0 } already notified anomalies` ) ;
62+ const notifiedAnomalyIds = new Set ( notifiedAnomalies ?. map ( log => log . anomaly_id ) || [ ] ) ;
63+
5164 // Get all classifications
5265 const { data : classifications , error : classError } = await supabase
5366 . from ( 'classifications' )
@@ -75,12 +88,18 @@ async function findUsersWithUnclassifiedDiscoveries() {
7588 linkedAnomalies ?. forEach ( linkedAnomaly => {
7689 const userId = linkedAnomaly . author ;
7790 const anomalyId = linkedAnomaly . anomaly_id ;
91+ const linkedAnomalyId = linkedAnomaly . id ;
7892
93+ // Skip if already notified about this linked anomaly
94+ if ( notifiedAnomalyIds . has ( linkedAnomalyId ) ) {
95+ return ;
96+ }
97+
7998 // Check if this user has classified this specific anomaly
8099 const userClassifications = userClassifiedAnomalies . get ( userId ) || new Set ( ) ;
81100
82101 if ( ! userClassifications . has ( anomalyId ) ) {
83- // This is an unclassified discovery
102+ // This is an unclassified discovery that hasn't been notified about
84103 if ( ! usersWithUnclassified . has ( userId ) ) {
85104 usersWithUnclassified . set ( userId , [ ] ) ;
86105 }
@@ -94,7 +113,7 @@ async function findUsersWithUnclassifiedDiscoveries() {
94113 }
95114 } ) ;
96115
97- console . log ( `Found ${ usersWithUnclassified . size } users with unclassified discoveries` ) ;
116+ console . log ( `Found ${ usersWithUnclassified . size } users with unclassified discoveries (excluding already notified) ` ) ;
98117
99118 return Array . from ( usersWithUnclassified . entries ( ) ) . map ( ( [ userId , discoveries ] ) => ( {
100119 userId,
@@ -107,6 +126,34 @@ async function findUsersWithUnclassifiedDiscoveries() {
107126 }
108127}
109128
129+ async function logNotifiedAnomalies ( discoveries ) {
130+ try {
131+ if ( discoveries . length === 0 ) return ;
132+
133+ console . log ( `Logging ${ discoveries . length } anomalies as notified...` ) ;
134+
135+ const logEntries = discoveries . map ( discovery => ( {
136+ anomaly_id : discovery . linkedAnomalyId
137+ } ) ) ;
138+
139+ const { data, error } = await supabase
140+ . from ( 'push_anomaly_log' )
141+ . insert ( logEntries )
142+ . select ( ) ;
143+
144+ if ( error ) {
145+ console . error ( 'Error logging notified anomalies:' , error ) ;
146+ return false ;
147+ }
148+
149+ console . log ( `Successfully logged ${ data ?. length || 0 } anomalies as notified` ) ;
150+ return true ;
151+ } catch ( error ) {
152+ console . error ( 'Error in logNotifiedAnomalies:' , error ) ;
153+ return false ;
154+ }
155+ }
156+
110157async function sendNotificationsToUser ( userId , discoveries ) {
111158 try {
112159 // Get user's push subscriptions with deduplication by endpoint
@@ -151,8 +198,22 @@ async function sendNotificationsToUser(userId, discoveries) {
151198 const payload = JSON . stringify ( {
152199 title,
153200 body,
154- icon : '/assets/Captn.jpg' ,
155- url : '/structures/telescope' // Or wherever users go to classify
201+ icon : '/assets/Captn.jpg' , // Keep using Captn.jpg for both iOS and Android
202+ badge : '/assets/Captn.jpg' , // Badge for Android
203+ image : '/assets/Captn.jpg' , // Large image for rich notifications
204+ url : '/structures/telescope' , // Or wherever users go to classify
205+ tag : 'unclassified-discoveries' , // Prevent multiple notifications from stacking
206+ requireInteraction : true , // Keep notification visible until user interacts
207+ actions : [
208+ {
209+ action : 'classify' ,
210+ title : '🔬 Classify Now'
211+ } ,
212+ {
213+ action : 'dismiss' ,
214+ title : 'Later'
215+ }
216+ ]
156217 } ) ;
157218
158219 // Send notifications to all user's endpoints
@@ -179,6 +240,14 @@ async function sendNotificationsToUser(userId, discoveries) {
179240 const successful = results . filter ( r => r . success ) . length ;
180241 const failed = results . filter ( r => ! r . success ) . length ;
181242
243+ if ( successful > 0 ) {
244+ // Log the anomalies as notified only if at least one notification was successful
245+ const logged = await logNotifiedAnomalies ( discoveries ) ;
246+ if ( ! logged ) {
247+ console . warn ( `Failed to log anomalies for user ${ userId } , but notifications were sent` ) ;
248+ }
249+ }
250+
182251 console . log ( `User ${ userId } : ${ successful } notifications sent, ${ failed } failed` ) ;
183252 return { success : true , sent : successful , failed } ;
184253
0 commit comments