@@ -4,6 +4,7 @@ Brief: Main entry point for the app.
44
55import * as utils from './utils.js' ;
66
7+ const idb = new utils . idb ( ) ;
78const checkImgURL = 'https://img.icons8.com/color/30/approval--v1.png' ;
89const crossImgURL = 'https://img.icons8.com/emoji/30/cross-mark-emoji.png' ;
910let myWorker = null ;
@@ -45,26 +46,31 @@ function updateViewCount (type, increment=1) {
4546 cache . setItem ( id , viewCount ) ;
4647}
4748
48- async function inbox ( dataArray ) {
49+ async function inbox ( dataArray , fresh = true ) {
4950 const container = document . querySelector ( '#inbox section' ) ;
5051 const inboxUnread = document . getElementById ( 'unread' ) ;
5152
5253 // Loop over all messages
5354 for ( const el of dataArray ) {
55+ if ( ! el ) continue
5456 const dataID = el . id ;
5557 if ( messagesReceived . includes ( dataID ) ) continue ;
58+
5659 messagesReceived . push ( dataID ) ;
60+ idb . set ( dataID , structuredClone ( el ) ) ; // Do this before mutating el or el.data
61+
5762 const data = el . data ;
5863
59- const origin = data . FormID ?? 'NA' ;
64+ const origin = data . FormID ?? 'Undefined' ;
65+ delete data . FormID ;
6066
6167 if ( origin . startsWith ( '_view_' ) ) {
6268 updateViewCount ( origin . substring ( '_view_' . length ) ) ;
6369 continue ;
6470 }
6571
6672 const chatID = data . ChatID ;
67- if ( chatID ) delete data . ChatID ;
73+ delete data . ChatID ;
6874
6975 if ( 'geolocation' in el && ! ( 'Location' in data ) ) data . Location = el . geolocation ;
7076
@@ -128,13 +134,13 @@ async function inbox (dataArray) {
128134 categoryUnread . toggleAttribute ( 'hidden' , true ) ;
129135 } else {
130136 /* the element was toggled closed */
131- const rowList = tableBody . getElementsByTagName ( 'tr' ) ;
132137 // Unaccentuate old messages
133- for ( let i = 1 ; i <= rowList . length ; i ++ ) {
134- // Looping from bottom [rowList.length - i] to avoid unaccentuating new incoming messages
135- // rowList.length is live, hence not assigned to const
136- rowList [ rowList . length - i ] . classList . remove ( 'table-primary' ) ;
137- }
138+ // querySelectorAll returns a live nodelist which may change whenever another event handler updates document
139+ // Hence using a shallow copy (Array.from) to isolate
140+ Array . from ( tableBody . querySelectorAll ( 'tr.table-primary' ) )
141+ . forEach ( ( el ) => {
142+ el . classList . remove ( 'table-primary' ) ;
143+ } ) ;
138144 }
139145 } ) ;
140146 }
@@ -165,16 +171,17 @@ async function inbox (dataArray) {
165171 document . getElementById ( category ) . prepend ( row ) ;
166172
167173 // Accentuate row as new
168- row . className = 'table-primary' ;
174+ if ( fresh ) row . className = 'table-primary' ;
169175
170176 // Update unread message count
171- if ( ! row . checkVisibility ( ) ) {
177+ if ( fresh && ! row . checkVisibility ( ) ) {
172178 inboxUnread . innerText = parseInt ( inboxUnread . innerText ) + 1 ;
173179 const categoryUnread = document . getElementById ( `${ category } Unread` ) ;
174180 categoryUnread . innerText = parseInt ( categoryUnread . innerText ) + 1 ;
175181 categoryUnread . toggleAttribute ( 'hidden' , false ) ;
176182 }
177183 }
184+ idb . flush ( ) ; // Store messages to indexedDB, against id
178185}
179186
180187window . reply = async function reply ( chatID ) {
@@ -227,6 +234,15 @@ window.sync = function sync () {
227234 if ( myWorker ) myWorker . postMessage ( { cmd : 'syncNow' } ) ;
228235} ;
229236
237+ window . clearInbox = function clearInbox ( force = false ) {
238+ if ( ! ( force || confirm ( 'Are you sure you want to delete all inboxed messages?' ) ) ) return ;
239+ idb . clear ( ) ;
240+ document . querySelectorAll ( '#inbox section details' )
241+ . forEach ( ( el ) => {
242+ el . remove ( ) ;
243+ } ) ;
244+ }
245+
230246function updateSyncStatusBadge ( ) {
231247 const badge = document . getElementById ( 'serverStatus' ) ;
232248 if ( myWorker ) {
@@ -321,8 +337,6 @@ window.startWorker = function startWorker () {
321337
322338 logThis ( 'Started sync' ) ;
323339 updateSyncStatusBadge ( ) ;
324-
325- renderForms ( ) ;
326340} ;
327341
328342window . stopWorker = function stopWorker ( ) {
@@ -347,17 +361,20 @@ window.toggleWorker = function toggleWorker () {
347361} ;
348362
349363window . signout = function signout ( ) {
364+ if ( ! confirm ( 'Are you sure you want to log out? This will delete all your data from this device.' ) ) return ;
350365 stopWorker ( ) ;
351366 OneSignalDeferred . push ( async function ( OneSignal ) {
352367 await OneSignal . logout ( ) ;
353368 } ) ;
354369 localStorage . clear ( ) ;
355370 sessionStorage . clear ( ) ;
356371 cache = null ;
372+ clearInbox ( true ) ;
357373 main ( ) ;
358374} ;
359375
360376window . signIn = async function signIn ( callerForm ) {
377+ idb . clear ( ) ; // Just in case previous logout didnt clear IndexedDB completely
361378 const data = new FormData ( callerForm ) ;
362379 const appKey = data . get ( 'appKey' ) ;
363380 try {
@@ -481,6 +498,9 @@ function main() {
481498 OneSignalLogin ( ) ;
482499 if ( ! pageIsRefreshed ) spaGoTo ( 'inbox' ) ; // go to inbox on fresh load
483500 startWorker ( ) ;
501+ renderForms ( ) ;
502+ // Load earlier messages from indexedDB, sorted chronologically
503+ idb . vals ( ( el1 , el2 ) => el1 . time - el2 . time ) . then ( ( dataArray ) => inbox ( dataArray , false ) ) ;
484504 } else {
485505 spaShow ( 'login' ) ;
486506 }
0 commit comments