1
+ // Global array of distraction emails
2
+ let distractionEmails = [
3
+ {
4
+ subject : "HELP! Database broken!" ,
5
+
6
+ body : "I think I broke the database... all the queries are slow. Should I turn it off and on again?" ,
7
+ signature : "- The Intern" ,
8
+ sound : new Audio ( "../sounds/youve-got-mail.mp3" )
9
+ } ,
10
+ {
11
+ subject : "URGENT: Database Crisis" ,
12
+
13
+ body : "Fix the database now or you're fired. Customers are leaving." ,
14
+ signature : "- Your CTO" ,
15
+ sound : new Audio ( "../sounds/futuristic-ding.mp3" )
16
+ } ,
17
+ {
18
+ subject : "We need to talk about Alex" ,
19
+
20
+ body : "I've been seeing a lot of messages from someone named Alex. Who is this person? Are you hiding something from me?" ,
21
+ signature : "- Your Spouse" ,
22
+ sound : new Audio ( "../sounds/four-bells.mp3" )
23
+ } ,
24
+ {
25
+ subject : "Your Replacement is Being Hired" ,
26
+
27
+ body : "I've already posted your job on LinkedIn. Better hurry up with that database fix if you want to keep it." ,
28
+ signature : "- Your CTO" ,
29
+ sound : new Audio ( "../sounds/email.mp3" )
30
+ } ,
31
+ {
32
+ subject : "Taking Over Database Fix" ,
33
+
34
+ body : "Hey, I've started working on the database fix. The CTO says I'll get your job if I solve it first. Just FYI 😉" ,
35
+ signature : "- Your 'Friend' at Work" ,
36
+ sound : new Audio ( "../sounds/boing.mp3" )
37
+ } ,
38
+ {
39
+ subject : "Intern's Gone, You're Next" ,
40
+
41
+ body : "Just fired the intern for breaking the database. You're the only one left to blame. Clock is ticking." ,
42
+ signature : "- Your CTO" ,
43
+ sound : new Audio ( "../sounds/tune.mp3" )
44
+ }
45
+ ] ;
46
+
47
+ // Initialize the email index from localStorage or default to 0
48
+ let currentEmailIndex = parseInt ( localStorage . getItem ( 'currentEmailIndex' ) ) || 0 ;
49
+
50
+ // Get active popups from localStorage or initialize empty array
51
+ let activePopups = JSON . parse ( localStorage . getItem ( 'activePopups' ) ) || [ ] ;
52
+
53
+ // Get shown thresholds from localStorage or initialize empty array
54
+ let shownThresholds = JSON . parse ( localStorage . getItem ( 'shownThresholds' ) ) || [ ] ;
55
+
56
+ // Shared function to create and display a popup
57
+ function createPopup ( popupInfo , position = null ) {
58
+ // Play notification sound for new emails (not for restored ones)
59
+ if ( ! position ) {
60
+ popupInfo . email . sound . play ( ) . catch ( error => console . error ( "Error playing sound:" , error ) ) ;
61
+ }
62
+
63
+ return fetch ( '../components/distractionEmail.html' )
64
+ . then ( response => response . text ( ) )
65
+ . then ( data => {
66
+ // Replace the static IDs with unique ones
67
+ data = data . replace ( 'id="distractionPopup"' , `id="${ popupInfo . overlayId } "` ) ;
68
+ data = data . replace ( 'id="distractionPopupContent"' , `id="${ popupInfo . contentId } "` ) ;
69
+
70
+ // Replace the email content
71
+ data = data . replace ( '{{subject}}' , popupInfo . email . subject ) ;
72
+ data = data . replace ( '{{from}}' , popupInfo . email . from ) ;
73
+ data = data . replace ( '{{body}}' , popupInfo . email . body ) ;
74
+ data = data . replace ( '{{signature}}' , popupInfo . email . signature ) ;
75
+
76
+ // Insert the popup
77
+ const timesUpContainer = document . getElementById ( 'timesUpPopupContainer' ) ;
78
+ if ( timesUpContainer ) {
79
+ timesUpContainer . insertAdjacentHTML ( 'beforebegin' , data ) ;
80
+ } else {
81
+ document . body . innerHTML += data ;
82
+ }
83
+
84
+ // Show the popup
85
+ const overlay = document . getElementById ( popupInfo . overlayId ) ;
86
+ const popup = document . getElementById ( popupInfo . contentId ) ;
87
+ overlay . style . display = 'block' ;
88
+
89
+ // Position the popup
90
+ if ( position ) {
91
+ popup . style . left = position . left + 'px' ;
92
+ popup . style . top = position . top + 'px' ;
93
+ } else {
94
+ // Get viewport size
95
+ const vw = window . innerWidth ;
96
+ const vh = window . innerHeight ;
97
+
98
+ // Get popup size (after display:block)
99
+ popup . style . left = '0px' ;
100
+ popup . style . top = '0px' ;
101
+ const rect = popup . getBoundingClientRect ( ) ;
102
+ const pw = rect . width ;
103
+ const ph = rect . height ;
104
+
105
+ // Add buffer zone (50px from edges)
106
+ const buffer = 50 ;
107
+ const maxLeft = Math . max ( buffer , vw - pw - buffer ) ;
108
+ const maxTop = Math . max ( buffer , vh - ph - buffer ) ;
109
+ const left = Math . random ( ) * ( maxLeft - buffer ) + buffer ;
110
+ const top = Math . random ( ) * ( maxTop - buffer ) + buffer ;
111
+
112
+ popup . style . left = left + 'px' ;
113
+ popup . style . top = top + 'px' ;
114
+
115
+ // Update position in popupInfo
116
+ popupInfo . position = { left, top } ;
117
+ localStorage . setItem ( 'activePopups' , JSON . stringify ( activePopups ) ) ;
118
+ }
119
+
120
+ // Add close handler
121
+ const closeBtn = overlay . querySelector ( '.popup-close' ) ;
122
+ closeBtn . onclick = function ( ) {
123
+ overlay . style . display = 'none' ;
124
+ activePopups = activePopups . filter ( p => p . id !== popupInfo . id ) ;
125
+ localStorage . setItem ( 'activePopups' , JSON . stringify ( activePopups ) ) ;
126
+ } ;
127
+ } )
128
+ . catch ( error => console . error ( "Error creating popup:" , error ) ) ;
129
+ }
130
+
131
+ function showDistractionPopup ( ) {
132
+ // Get the next email in sequence
133
+ const email = distractionEmails [ currentEmailIndex ] ;
134
+ currentEmailIndex = ( currentEmailIndex + 1 ) % distractionEmails . length ;
135
+ localStorage . setItem ( 'currentEmailIndex' , currentEmailIndex . toString ( ) ) ;
136
+
137
+ // Generate unique IDs for this popup instance
138
+ const uniqueId = 'distraction_' + currentEmailIndex ;
139
+ const overlayId = uniqueId + '_overlay' ;
140
+ const contentId = uniqueId + '_content' ;
141
+
142
+ // Store popup info in activePopups
143
+ const popupInfo = {
144
+ id : uniqueId ,
145
+ overlayId : overlayId ,
146
+ contentId : contentId ,
147
+ email : email ,
148
+ position : null
149
+ } ;
150
+ activePopups . push ( popupInfo ) ;
151
+ localStorage . setItem ( 'activePopups' , JSON . stringify ( activePopups ) ) ;
152
+
153
+ // Create and show the popup
154
+ createPopup ( popupInfo ) ;
155
+ }
156
+
157
+ // Function to restore active popups
158
+ function restoreActivePopups ( ) {
159
+ activePopups . forEach ( popupInfo => {
160
+ createPopup ( popupInfo , popupInfo . position ) ;
161
+ } ) ;
162
+ }
163
+
164
+ // Start showing popups based on remaining time
165
+ window . addEventListener ( 'DOMContentLoaded' , function ( ) {
166
+ // Restore any existing popups first
167
+ restoreActivePopups ( ) ;
168
+
169
+ // Check timer every second
170
+ const checkInterval = setInterval ( ( ) => {
171
+ const timerDisplay = document . getElementById ( 'timerDisplay' ) ;
172
+ const timeText = timerDisplay . innerText ;
173
+ const remainingTime = parseFloat ( timeText ) ;
174
+
175
+ if ( remainingTime <= 0 ) {
176
+ clearInterval ( checkInterval ) ;
177
+ return ;
178
+ }
179
+
180
+ // Show popups at specific time thresholds (85s, 70s, etc.)
181
+ const thresholds = [ 110 , 90 , 70 , 50 , 30 , 10 ] ;
182
+ // const thresholds = [118, 116, 114, 112, 110, 108];
183
+ thresholds . forEach ( threshold => {
184
+ if ( remainingTime <= threshold && ! shownThresholds . includes ( threshold ) ) {
185
+ showDistractionPopup ( ) ;
186
+ shownThresholds . push ( threshold ) ;
187
+ localStorage . setItem ( 'shownThresholds' , JSON . stringify ( shownThresholds ) ) ;
188
+ }
189
+ } ) ;
190
+ } , 500 ) ;
191
+ } ) ;
0 commit comments