Times are randomised across morning, afternoon, evening and night.
iPhone: add app to home screen first. Requires iOS 16.4+.
Preferences
👤
Your name
Not set
›
🗑
Clear all data
Deletes all check-ins and settings
About
ℹ️
Better Minute
Version 6.0 • Not a medical service
🔒
Privacy
All data stored locally on your device only
✨
Done.
Small steps still count.
/* ── NOTIFICATIONS ── */
var DEFAULT_TIMES=['08:30','13:00','18:30','21:00'];
var NOTIF_MSGS=[
{title:'Time for a check-in',body:'How are you feeling right now? It takes 60 seconds.'},
{title:'Better Minute',body:'A quick pause can shift everything. How are you doing?'},
{title:'Check in with yourself',body:'Your mood matters. Take one minute for you.'},
{title:'How are you feeling?',body:'Morning, afternoon or night - you deserve a moment.'},
{title:'One minute for you',body:'Whatever is happening, Better Minute is here.'},
{title:'Your daily check-in',body:'Small habit, big difference. How are you right now?'},
{title:'Pause for a second',body:'How has your day been treating you so far?'},
{title:'Better Minute reminder',body:'Check in, breathe, get a personalised suggestion.'},
{title:'Quick question',body:'On a scale of terrible to great - where are you today?'},
{title:'You have got a moment',body:'Use it to check in. It takes less than a minute.'}
];
function initNotifications(){
if(!('Notification' in window)){updateNotifStatus();return;}
if(Notification.permission==='granted'){scheduleAllNotifications();updateNotifStatus();hideBanner();return;}
if(Notification.permission==='denied'){showBannerIfDue('denied');updateNotifStatus();return;}
showBannerIfDue('default');updateNotifStatus();
}
function showBannerIfDue(state){
try{var last=parseInt(localStorage.getItem('bm_notif_last_prompt')||'0');if(Date.now()-last<24*60*60*1000)return;}catch(e){}
setTimeout(function(){
var banner=document.getElementById('notif-banner');if(!banner)return;
if(state==='denied'){
var t=document.getElementById('notif-banner-title');
var b=document.getElementById('notif-banner-body');
var btn=document.getElementById('notif-enable-btn');
if(t)t.innerHTML='🔔 Reminders are off';
if(b)b.textContent='Notifications are blocked. Fix it: Settings > '+getBrowserName()+' > Notifications > Allow.';
if(btn){btn.textContent='Got it';btn.onclick=function(){hideBanner();recordPromptShown();};}
}
banner.style.display='block';recordPromptShown();
},3000);
}
function recordPromptShown(){try{localStorage.setItem('bm_notif_last_prompt',Date.now().toString());}catch(e){}}
function hideBanner(){var b=document.getElementById('notif-banner');if(b)b.style.display='none';}
function getBrowserName(){var ua=navigator.userAgent;if(/safari/i.test(ua)&&!/chrome/i.test(ua))return 'Safari';if(/chrome/i.test(ua))return 'Chrome';if(/firefox/i.test(ua))return 'Firefox';return 'your browser';}
function updateNotifStatus(){
var txt=document.getElementById('notif-status-text');
var arr=document.getElementById('notif-toggle-arr');
if(!txt)return;
if(!('Notification' in window)){txt.textContent='Not available on this browser';return;}
if(Notification.permission==='granted'){
var c=4;try{c=parseInt(localStorage.getItem('bm_notif_count')||'4');}catch(e){}
txt.textContent='On - '+c+' random reminder'+(c>1?'s':'')+' per day';
if(arr)arr.innerHTML='✓';
} else if(Notification.permission==='denied'){
txt.textContent='Blocked - enable in your phone Settings';
if(arr)arr.innerHTML='!';
} else {
txt.textContent='Off - tap to turn on';
if(arr)arr.innerHTML='›';
}
}
function requestNotifPermission(){
if(!('Notification' in window)){var m=document.getElementById('notif-msg');if(m)m.textContent='Not supported on this browser';return;}
if(Notification.permission==='denied'){
var m=document.getElementById('notif-msg');
if(m)m.textContent='Blocked. Go to Settings > '+getBrowserName()+' > Notifications > Allow.';
hideBanner();return;
}
Notification.requestPermission().then(function(perm){
hideBanner();
if(perm==='granted'){
scheduleAllNotifications();updateNotifStatus();renderNotifTimeUI();
var w=document.getElementById('notif-time-wrap');if(w)w.style.display='block';
var m=document.getElementById('notif-msg');
if(m){var c=4;try{c=parseInt(localStorage.getItem('bm_notif_count')||'4');}catch(e){}
m.textContent='Reminders on! You will get '+c+' random nudges per day.';
setTimeout(function(){if(m)m.textContent='';},4000);}
} else {updateNotifStatus();}
});
}
function pad2(n){return n<10?'0'+n:String(n);}
function getRandomTimes(count){
var windows=[[7*60,10*60],[11*60,14*60],[16*60,19*60],[20*60,22*60]];
var times=[];
windows.slice(0,count).forEach(function(w){
var mins=w[0]+Math.floor(Math.random()*(w[1]-w[0]));
times.push(pad2(Math.floor(mins/60))+':'+pad2(mins%60));
});
return times.sort();
}
function scheduleAllNotifications(){
if(Notification.permission!=='granted')return;
if(window._notifTimers)window._notifTimers.forEach(function(t){clearTimeout(t);});
window._notifTimers=[];
var count=4;try{count=parseInt(localStorage.getItem('bm_notif_count')||'4');}catch(e){}
var today=new Date().toDateString();
var lastDay='';try{lastDay=localStorage.getItem('bm_notif_day')||'';}catch(e){}
var times;
if(lastDay===today){try{times=JSON.parse(localStorage.getItem('bm_notif_times'));}catch(e){times=getRandomTimes(count);}}
else{times=getRandomTimes(count);try{localStorage.setItem('bm_notif_times',JSON.stringify(times));localStorage.setItem('bm_notif_day',today);}catch(e){}}
var now=new Date();
times.forEach(function(timeStr){
var p=timeStr.split(':');
var next=new Date();next.setHours(parseInt(p[0])||9,parseInt(p[1])||0,0,0);
if(next<=now)next.setDate(next.getDate()+1);
var t=setTimeout(function(){
fireNotification();
var daily=setInterval(function(){
var c2=4;try{c2=parseInt(localStorage.getItem('bm_notif_count')||'4');}catch(e){}
var nt=getRandomTimes(c2);
try{localStorage.setItem('bm_notif_times',JSON.stringify(nt));localStorage.setItem('bm_notif_day',new Date().toDateString());}catch(e){}
fireNotification();
},24*60*60*1000);
window._notifTimers.push(daily);
},next-now);
window._notifTimers.push(t);
});
}
function fireNotification(){
if(Notification.permission!=='granted')return;
var today=new Date().toDateString();
var checked=S.log.length>0&&new Date(S.log[0].time).toDateString()===today;
var msg=checked?{title:'Great work today',body:'You already checked in. Keep the streak going tomorrow!'}:NOTIF_MSGS[Math.floor(Math.random()*NOTIF_MSGS.length)];
if('serviceWorker' in navigator){
navigator.serviceWorker.ready.then(function(reg){
reg.showNotification(msg.title,{body:msg.body,icon:'/icon-192.png',badge:'/icon-192.png',tag:'bm-checkin',renotify:true,vibrate:[200,100,200],data:{url:'/'}});
}).catch(function(){try{new Notification(msg.title,{body:msg.body,icon:'/icon-192.png'});}catch(e){}});
} else {try{new Notification(msg.title,{body:msg.body,icon:'/icon-192.png'});}catch(e){}}
}
function renderNotifTimeUI(){
var wrap=document.getElementById('notif-time-wrap');if(!wrap)return;
var count=4;try{count=parseInt(localStorage.getItem('bm_notif_count')||'4');}catch(e){}
wrap.innerHTML=
'
Times are randomised daily across morning, afternoon, evening and night windows.
'+
''+
'
iPhone: add app to home screen first. Requires iOS 16.4+.
'+
'';
wrap.querySelectorAll('.notif-count-btn').forEach(function(btn){
btn.addEventListener('click',function(){
wrap.querySelectorAll('.notif-count-btn').forEach(function(b){b.style.borderColor='var(--bdr2)';b.style.background='var(--surf)';b.style.color='var(--ink2)';});
btn.style.borderColor='var(--ink)';btn.style.background='var(--ink)';btn.style.color='#fff';
try{localStorage.setItem('bm_notif_count',btn.dataset.count);}catch(e){}
});
});
var sb=document.getElementById('notif-save-btn');
if(sb)sb.addEventListener('click',function(){
var c=4;try{c=parseInt(localStorage.getItem('bm_notif_count')||'4');}catch(e){}
try{localStorage.removeItem('bm_notif_day');}catch(e){}
scheduleAllNotifications();updateNotifStatus();
var m=document.getElementById('notif-msg');
if(m){m.textContent='Saved! '+c+' random reminder'+(c>1?'s':'')+' per day.';setTimeout(function(){if(m)m.textContent='';},3000);}
});
}
var _enBtn=document.getElementById('notif-enable-btn');
if(_enBtn)_enBtn.addEventListener('click',requestNotifPermission);
var _disBtn=document.getElementById('notif-dismiss-btn');
if(_disBtn)_disBtn.addEventListener('click',function(){hideBanner();recordPromptShown();});
var _nRow=document.getElementById('notif-row');
if(_nRow)_nRow.addEventListener('click',function(){
if(Notification.permission==='granted'){
var w=document.getElementById('notif-time-wrap');
if(w){w.style.display=(w.style.display==='none'||!w.style.display)?'block':'none';if(w.style.display==='block')renderNotifTimeUI();}
} else {requestNotifPermission();}
});
setTimeout(initNotifications,600);
if('serviceWorker' in navigator){
window.addEventListener('load',function(){
navigator.serviceWorker.register('sw.js').catch(function(){});
});
}
function fetchAI(seg,a){
var el=document.getElementById('ai-txt');
setTimeout(function(){el.textContent=generateSmartMessage(seg,a);},700);
}
/* ── DONE ── */
document.getElementById('btn-done').addEventListener('click',markDone);
document.getElementById('btn-skip-result').addEventListener('click',function(){goTo('s-home');});
document.getElementById('result-back').addEventListener('click',function(){goTo('s-home');});
function markDone(){
var a=S.assess,seg=a.moodMeta||MOODS[2];
S.log.unshift({mood:seg.id,moodScore:seg.score,time:new Date(),emoji:seg.em,label:seg.label,emotions:a.emotion||[],context:a.context||[],intensity:a.intensity||null,energy:a.energy||[],notes:a.notes||''});
saveLog();stopBreathe();
document.getElementById('done-ring').innerHTML=seg.em;
document.getElementById('done-title').textContent=seg.label+'.';
document.getElementById('done-msg').textContent=DONE_MSGS[seg.id]||DONE_MSGS.okay;
goTo('s-done');
}
/* ── BREATHE ── */
document.getElementById('b-ring').addEventListener('click',function(){S.breathing?stopBreathe():startBreathe();});
function startBreathe(){
S.breathing=true;S.bcount=0;
var ring=document.getElementById('b-ring'),inner=document.getElementById('b-inner'),phase=document.getElementById('b-phase');
ring.classList.add('go');
var seq=[{lbl:'Breathe in',dur:4000,n:'4'},{lbl:'Hold',dur:7000,n:'7'},{lbl:'Breathe out',dur:8000,n:'8'},{lbl:'Rest',dur:1000,n:'...'}];
var i=0;
function cycle(){
if(!S.breathing)return;
var s=seq[i%seq.length];phase.textContent=s.lbl+'...';inner.textContent=s.n;
if(i%seq.length===2)S.bcount++;
if(S.bcount>=5){stopBreathe();phase.textContent='5 breaths complete';return;}
S.btimer=setTimeout(cycle,s.dur);i++;
}
cycle();
}
function stopBreathe(){
S.breathing=false;clearTimeout(S.btimer);
var ring=document.getElementById('b-ring'),inner=document.getElementById('b-inner'),phase=document.getElementById('b-phase');
if(ring)ring.classList.remove('go');if(inner)inner.textContent='Tap to start';if(phase)phase.textContent='';
}
/* ── HISTORY ── */
function refreshHist(){
document.getElementById('hist-meta').textContent=S.log.length+' check-in'+(S.log.length!==1?'s':'')+' total';
renderChart();renderHistInsight();renderLog();
}
function renderChart(){
var bars=document.getElementById('chart-bars');bars.innerHTML='';
var days=document.getElementById('chart-days');days.innerHTML='';
var today=new Date();
var cmap={terrible:'#C47A7A',low:'#D4935A',okay:'#6A9DC8',good:'#7BA08A',great:'#9B8EC4'};
for(var i=6;i>=0;i--){
var d=new Date(today);d.setDate(today.getDate()-i);
var ents=S.log.filter(function(e){return new Date(e.time).toDateString()===d.toDateString();});
var avg=ents.length?ents.reduce(function(s,e){var seg=MOODS.find(function(x){return x.id===e.mood;});return s+(seg?seg.score:3);},0)/ents.length:0;
var bar=document.createElement('div');bar.className='c-bar';
bar.style.height=(avg?avg/5*100:4)+'%';
bar.style.background=ents.length?(cmap[ents[0].mood]||'#7BA08A'):'var(--surf)';
bars.appendChild(bar);
var lbl=document.createElement('span');lbl.textContent=d.toLocaleDateString('en-GB',{weekday:'short'}).slice(0,2);
days.appendChild(lbl);
}
}
function renderHistInsight(){
var card=document.getElementById('hist-insight'),txt=document.getElementById('hi-txt');
if(S.log.length<3){card.classList.remove('show');return;}
var counts={};S.log.forEach(function(e){counts[e.mood]=(counts[e.mood]||0)+1;});
var top=Object.entries(counts).sort(function(a,b){return b[1]-a[1];})[0];
var evLow=S.log.filter(function(e){var hh=new Date(e.time).getHours();return(e.mood==='low'||e.mood==='terrible')&&hh>=20;}).length;
var amGood=S.log.filter(function(e){var hh=new Date(e.time).getHours();return(e.mood==='good'||e.mood==='great')&&hh<12;}).length;
if(evLow>=2)txt.innerHTML='Evening pattern spotted - You tend to feel low at night. A wind-down routine before 9pm might help.';
else if(amGood>=2)txt.innerHTML='Morning person - Your best moods tend to be in the morning. Protect that time.';
else txt.innerHTML='Most common: '+top[0]+' - You've logged this '+top[1]+' time'+(top[1]>1?'s':'')+' recently.';
card.classList.add('show');
}
function renderLog(){
var sec=document.getElementById('log-section');
if(!S.log.length){sec.innerHTML='
No check-ins yet. Tap the check-in button to start.
';return;}
var dotBg={terrible:'rgba(196,122,122,.15)',low:'rgba(212,147,90,.15)',okay:'rgba(106,157,200,.15)',good:'rgba(123,160,138,.15)',great:'rgba(155,142,196,.15)'};
var groups={};
S.log.forEach(function(e){var ds=new Date(e.time).toLocaleDateString('en-GB',{weekday:'long',day:'numeric',month:'long'});if(!groups[ds])groups[ds]=[];groups[ds].push(e);});
sec.innerHTML='';
Object.keys(groups).forEach(function(date){
var dl=document.createElement('div');dl.className='log-date-label';dl.textContent=date;sec.appendChild(dl);
groups[date].forEach(function(e){
var row=document.createElement('div');row.className='log-item';
var ctx=[].concat((e.emotions||[]).slice(0,2),(e.context||[]).slice(0,1)).join(' - ');
var ts=new Date(e.time).toLocaleTimeString('en-GB',{hour:'2-digit',minute:'2-digit'});
row.innerHTML='
'+e.emoji+'
'+
'
'+e.label+'
'+(ctx||'No context added')+'
'+
'
'+ts+'
';
sec.appendChild(row);
});
});
}
/* ── PROFILE ── */
function refreshProf(){
var n=S.name;
document.getElementById('prof-av').textContent=n?n[0].toUpperCase():'B';
document.getElementById('prof-name').textContent=n||'Your Space';
document.getElementById('name-disp').textContent=n||'Not set';
document.getElementById('name-inp').value=n||'';
document.getElementById('prof-meta').textContent=S.log.length?'Member since '+new Date(S.log[S.log.length-1].time).toLocaleDateString('en-GB',{month:'long',year:'numeric'}):'No check-ins yet';
updateNotifStatus();
}
document.getElementById('name-row').addEventListener('click',function(){var w=document.getElementById('name-wrap');w.style.display=(w.style.display==='none'||!w.style.display)?'block':'none';});
document.getElementById('name-save').addEventListener('click',function(){
var val=document.getElementById('name-inp').value.trim();
S.name=val;try{localStorage.setItem('bm_name',val);}catch(e){}
document.getElementById('name-disp').textContent=val||'Not set';
document.getElementById('prof-name').textContent=val||'Your Space';
document.getElementById('prof-av').textContent=val?val[0].toUpperCase():'B';
});
document.getElementById('clear-row').addEventListener('click',function(){
var lbl=document.getElementById('clear-lbl');
if(S.clearPending){try{localStorage.clear();}catch(e){}S.log=[];S.name='';S.onboarded=false;S.clearPending=false;lbl.textContent='';goTo('s-ob');}
else{S.clearPending=true;lbl.textContent='Tap again to confirm';setTimeout(function(){S.clearPending=false;lbl.textContent='';},3500);}
});
/* ── NOTIFICATIONS ── */
var DEFAULT_TIMES=['08:30','13:00','18:30','21:00'];
var NOTIF_MSGS=[
{title:'Time for a check-in',body:'How are you feeling right now? It takes 60 seconds.'},
{title:'Better Minute',body:'A quick pause can shift everything. How are you doing?'},
{title:'Check in with yourself',body:'Your mood matters. Take one minute for you.'},
{title:'How are you feeling?',body:'Morning, afternoon or night - you deserve a moment.'},
{title:'One minute for you',body:'Whatever is happening, Better Minute is here.'},
{title:'Your daily check-in',body:'Small habit, big difference. How are you right now?'},
{title:'Pause for a second',body:'How has your day been treating you so far?'},
{title:'Better Minute reminder',body:'Check in, breathe, get a personalised suggestion.'},
{title:'Quick question',body:'On a scale of terrible to great - where are you today?'},
{title:'You have got a moment',body:'Use it to check in. It takes less than a minute.'}
];
function initNotifications(){
if(!('Notification' in window)){updateNotifStatus();return;}
if(Notification.permission==='granted'){scheduleAllNotifications();updateNotifStatus();hideBanner();return;}
if(Notification.permission==='denied'){showBannerIfDue('denied');updateNotifStatus();return;}
showBannerIfDue('default');updateNotifStatus();
}
function showBannerIfDue(state){
try{var last=parseInt(localStorage.getItem('bm_notif_last_prompt')||'0');if(Date.now()-last<24*60*60*1000)return;}catch(e){}
setTimeout(function(){
var banner=document.getElementById('notif-banner');if(!banner)return;
if(state==='denied'){
var t=document.getElementById('notif-banner-title');
var b=document.getElementById('notif-banner-body');
var btn=document.getElementById('notif-enable-btn');
if(t)t.innerHTML='🔔 Reminders are off';
if(b)b.textContent='Notifications are blocked. Fix it: Settings > '+getBrowserName()+' > Notifications > Allow.';
if(btn){btn.textContent='Got it';btn.onclick=function(){hideBanner();recordPromptShown();};}
}
banner.style.display='block';recordPromptShown();
},3000);
}
function recordPromptShown(){try{localStorage.setItem('bm_notif_last_prompt',Date.now().toString());}catch(e){}}
function hideBanner(){var b=document.getElementById('notif-banner');if(b)b.style.display='none';}
function getBrowserName(){var ua=navigator.userAgent;if(/safari/i.test(ua)&&!/chrome/i.test(ua))return 'Safari';if(/chrome/i.test(ua))return 'Chrome';if(/firefox/i.test(ua))return 'Firefox';return 'your browser';}
function updateNotifStatus(){
var txt=document.getElementById('notif-status-text');
var arr=document.getElementById('notif-toggle-arr');
if(!txt)return;
if(!('Notification' in window)){txt.textContent='Not available on this browser';return;}
if(Notification.permission==='granted'){
var c=4;try{c=parseInt(localStorage.getItem('bm_notif_count')||'4');}catch(e){}
txt.textContent='On - '+c+' random reminder'+(c>1?'s':'')+' per day';
if(arr)arr.innerHTML='✓';
} else if(Notification.permission==='denied'){
txt.textContent='Blocked - enable in your phone Settings';
if(arr)arr.innerHTML='!';
} else {
txt.textContent='Off - tap to turn on';
if(arr)arr.innerHTML='›';
}
}
function requestNotifPermission(){
if(!('Notification' in window)){var m=document.getElementById('notif-msg');if(m)m.textContent='Not supported on this browser';return;}
if(Notification.permission==='denied'){
var m=document.getElementById('notif-msg');
if(m)m.textContent='Blocked. Go to Settings > '+getBrowserName()+' > Notifications > Allow.';
hideBanner();return;
}
Notification.requestPermission().then(function(perm){
hideBanner();
if(perm==='granted'){
scheduleAllNotifications();updateNotifStatus();renderNotifTimeUI();
var w=document.getElementById('notif-time-wrap');if(w)w.style.display='block';
var m=document.getElementById('notif-msg');
if(m){var c=4;try{c=parseInt(localStorage.getItem('bm_notif_count')||'4');}catch(e){}
m.textContent='Reminders on! You will get '+c+' random nudges per day.';
setTimeout(function(){if(m)m.textContent='';},4000);}
} else {updateNotifStatus();}
});
}
function pad2(n){return n<10?'0'+n:String(n);}
function getRandomTimes(count){
var windows=[[7*60,10*60],[11*60,14*60],[16*60,19*60],[20*60,22*60]];
var times=[];
windows.slice(0,count).forEach(function(w){
var mins=w[0]+Math.floor(Math.random()*(w[1]-w[0]));
times.push(pad2(Math.floor(mins/60))+':'+pad2(mins%60));
});
return times.sort();
}
function scheduleAllNotifications(){
if(Notification.permission!=='granted')return;
if(window._notifTimers)window._notifTimers.forEach(function(t){clearTimeout(t);});
window._notifTimers=[];
var count=4;try{count=parseInt(localStorage.getItem('bm_notif_count')||'4');}catch(e){}
var today=new Date().toDateString();
var lastDay='';try{lastDay=localStorage.getItem('bm_notif_day')||'';}catch(e){}
var times;
if(lastDay===today){try{times=JSON.parse(localStorage.getItem('bm_notif_times'));}catch(e){times=getRandomTimes(count);}}
else{times=getRandomTimes(count);try{localStorage.setItem('bm_notif_times',JSON.stringify(times));localStorage.setItem('bm_notif_day',today);}catch(e){}}
var now=new Date();
times.forEach(function(timeStr){
var p=timeStr.split(':');
var next=new Date();next.setHours(parseInt(p[0])||9,parseInt(p[1])||0,0,0);
if(next<=now)next.setDate(next.getDate()+1);
var t=setTimeout(function(){
fireNotification();
var daily=setInterval(function(){
var c2=4;try{c2=parseInt(localStorage.getItem('bm_notif_count')||'4');}catch(e){}
var nt=getRandomTimes(c2);
try{localStorage.setItem('bm_notif_times',JSON.stringify(nt));localStorage.setItem('bm_notif_day',new Date().toDateString());}catch(e){}
fireNotification();
},24*60*60*1000);
window._notifTimers.push(daily);
},next-now);
window._notifTimers.push(t);
});
}
function fireNotification(){
if(Notification.permission!=='granted')return;
var today=new Date().toDateString();
var checked=S.log.length>0&&new Date(S.log[0].time).toDateString()===today;
var msg=checked?{title:'Great work today',body:'You already checked in. Keep the streak going tomorrow!'}:NOTIF_MSGS[Math.floor(Math.random()*NOTIF_MSGS.length)];
if('serviceWorker' in navigator){
navigator.serviceWorker.ready.then(function(reg){
reg.showNotification(msg.title,{body:msg.body,icon:'/icon-192.png',badge:'/icon-192.png',tag:'bm-checkin',renotify:true,vibrate:[200,100,200],data:{url:'/'}});
}).catch(function(){try{new Notification(msg.title,{body:msg.body,icon:'/icon-192.png'});}catch(e){}});
} else {try{new Notification(msg.title,{body:msg.body,icon:'/icon-192.png'});}catch(e){}}
}
function renderNotifTimeUI(){
var wrap=document.getElementById('notif-time-wrap');if(!wrap)return;
var count=4;try{count=parseInt(localStorage.getItem('bm_notif_count')||'4');}catch(e){}
wrap.innerHTML=
'