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