🍼 Schlückchen
Baby Trink-Tagebuch Β· Beta

πŸ”‘ Neues Passwort setzen

Melde dich zuerst an, dann kannst du dein Passwort direkt Γ€ndern.
Hallo, … πŸ‘‹
πŸ‘€ …
πŸ”„ Reset Mitternacht
🍼
Milch
0
ml
πŸ₯£
Brei
0
g
πŸ“‹
EintrΓ€ge
0
heute

πŸ“‹ Heutiges Protokoll

πŸ“
Noch keine EintrΓ€ge heute
πŸ’¬

Mein Feedback

πŸ“Š Statistiken

–
βŒ€ Milch/Tag
–
βŒ€ Brei/Tag
–
Tage
Verlauf
Milch (ml)
Brei (g)
πŸ“‹ Tagesdetails – antippen fΓΌr Details
Lade…

βš™οΈ Admin

–
Nutzer
–
EintrΓ€ge
–
Neues FB
–
FB gesamt
πŸ’¬ Feedback
Lade…
πŸ‘₯ Nutzer
Lade…

βš™οΈ Einstellungen

πŸŽ‰ Party
Party starten
Party beitreten
πŸ‘€ Account
–
Benutzername
Benutzername Γ€ndern
Neues Passwort
Abmelden
Von diesem GerΓ€t abmelden
🍼 Babynahrung
Noch keine Nahrung hinzugefΓΌgt
βž• Neue Nahrung
Hersteller / Name
Typ
Packung (g)
πŸ’Š Medikamente verwalten
Noch keine Medikamente hinzugefΓΌgt
βž• Neues Medikament
Name
Dosierung
Einheit
ℹ️ App Info
Version
SchlΓΌckchen
Baby Trink-Tagebuch
πŸ“‹ Was ist neu?
Changelog β†’
⚠️ Gefahrenzone
Account lΓΆschen
Alle Daten werden unwiderruflich gelΓΆscht
πŸ‘‘ Admin
Geheimer Zugang
Schritt 1 von 2 Β· Code eingeben
Schritt 2 von 2 Β· Name eingeben
Dein Name wird als Benutzername angezeigt.

βž• Eintrag hinzufΓΌgen

Eigene Menge: ml
πŸ’Š Medikament wΓ€hlen
Oder freie Eingabe
⏰
bereit
πŸ’Š Medikament dabei? (optional)

0
ml Milch
0
g Brei

πŸ“‹ Was ist neu?

v1.0.1.0
April 2026
✨
Neu
πŸ“ Notiz bei neuen EintrΓ€gen – direkt beim Eintragen hinzufΓΌgen
✨
Neu
πŸ’Š Medikament bei Mahlzeit – Name, Menge und Einheit direkt beim Eintrag
✨
Neu
πŸ’¬ Antwort-Benachrichtigung – Popup wenn Entwickler auf Feedback antwortet
πŸ›
Fix
StabilitΓ€t und Performance verbessert
πŸ›
Fix
Zoom deaktiviert – App fΓΌhlt sich wie eine native App an
πŸ’¬

Neue Antwort!

Der Entwickler hat auf dein Feedback geantwortet

Antworten
b.classList.toggle('on',(i===0&&t==='login')||(i===1&&t==='reg'))); aerr(''); } function aerr(msg){const e=g('aerr');e.textContent=msg;e.style.display=msg?'block':'none';} async function doRegister(){ var uname=val('r-user'),pw=val('r-pw'); var email=g('r-email')?g('r-email').value.trim():''; if(!uname||!email||!pw)return aerr('Alle Felder ausfΓΌllen.'); if(pw.length<8)return aerr('Passwort mind. 8 Zeichen.'); dis('r-btn',true); var ux=await sb.from('profiles').select('id').eq('username',uname).maybeSingle(); if(ux.data){dis('r-btn',false);return aerr('Name bereits vergeben.');} var sr=await sb.auth.signUp({email:email,password:pw,options:{data:{username:uname,role:'tester'}}}); dis('r-btn',false); if(sr.error)return aerr(sr.error.message); toast('Registriert! Bitte anmelden.','ok'); authTab('login'); } async function doLogin(){ var uname=val('l-user'),pw=val('l-pw'); if(!uname||!pw)return aerr('Bitte alle Felder ausfΓΌllen.'); dis('l-btn',true); if(uname.toLowerCase()==='admin'){ adminLoggingIn=true; var ar=await sb.auth.signInWithPassword({email:ADMIN_INTERNAL_EMAIL,password:pw}); dis('l-btn',false); if(ar.error){adminLoggingIn=false;return aerr('Passwort falsch.');} return; } var prof=await sb.from('profiles').select('email').eq('username',uname).maybeSingle(); if(!prof.data||!prof.data.email){dis('l-btn',false);return aerr('Name nicht gefunden.');} var lr=await sb.auth.signInWithPassword({email:prof.data.email,password:pw}); dis('l-btn',false); if(lr.error)return aerr('Name oder Passwort falsch.'); } async function doLogout(){ if((curProfile&&curProfile.role)==='admin'){ localStorage.removeItem('admin_device_verified'); localStorage.removeItem('admin_name'); localStorage.removeItem('admin_verified_version'); } else { await sb.auth.signOut(); } curUser=curProfile=null;todayEntries=[]; showScreen('auth'); } // ── ADMIN LOGIN ──────────────────────────── function initAdminScreen(){ if(g('al-step1'))g('al-step1').classList.remove('hidden'); if(g('al-step2'))g('al-step2').classList.add('hidden'); if(g('al-code'))g('al-code').value=''; showAlErr(''); } function showAlErr(msg){var e=g('al-err');if(e){e.textContent=msg;e.style.display=msg?'block':'none';}} function doAdminCheckCode(){ var code=g('al-code').value.trim().toUpperCase().replace(/\s/g,''); if(!code){showAlErr('Bitte Code eingeben.');return;} if(code!==ADMIN_CODE_LOCAL){showAlErr('UngΓΌltiger Admin-Code.');return;} showAlErr(''); g('al-step1').classList.add('hidden'); g('al-step2').classList.remove('hidden'); if(g('al-username'))g('al-username').focus(); } async function doAdminLogin(){ var username=g('al-username').value.trim(); if(!username){showAlErr('Bitte Name eingeben.');return;} dis('al-btn-login',true);showAlErr(''); var res=await sb.auth.signInWithPassword({email:ADMIN_INTERNAL_EMAIL,password:ADMIN_INTERNAL_PW}); if(res.error){ // Versuche Account zu erstellen var res2=await sb.auth.signUp({email:ADMIN_INTERNAL_EMAIL,password:ADMIN_INTERNAL_PW,options:{data:{username:username,role:'admin'}}}); if(res2.error){ dis('al-btn-login',false); showAlErr('Fehler: Admin-Konto konnte nicht erstellt werden. Bitte prΓΌfe Supabase.'); return; } // Nochmal einloggen nach Erstellung var res3=await sb.auth.signInWithPassword({email:ADMIN_INTERNAL_EMAIL,password:ADMIN_INTERNAL_PW}); if(res3.error){dis('al-btn-login',false);showAlErr('Fehler beim Einloggen.');return;} } // Anzeigename setzen if(res.data&&res.data.user){ await sb.from('profiles').upsert({id:res.data.user.id,username:username,role:'admin',channel:'admin'}); } dis('al-btn-login',false); } function doAdminFirstLogin(){doAdminCheckCode();} async function doAdminReturnLogin(){doAdminLogin();} async function adminSignIn(name){return true;} function adminForgetDevice(){} function applyProfile(){ if(!curProfile)return; if(g('party-quick-btn'))g('party-quick-btn').style.display='block'; const b=g('ubadge'); if(b){ b.textContent='βš™οΈ Einstellungen'; b.className='ubadge'+(curProfile.role==='admin'?' adm':''); } if(g('hallo-name'))g('hallo-name').textContent=curProfile.username; if(g('n-admin'))g('n-admin').classList.toggle('hidden',curProfile.role!=='admin'); const fb=g('feedback-card'); if(fb)fb.style.display=curProfile.role==='admin'?'none':''; // Show changelog on update const lastSeen=localStorage.getItem('schlueckchen_last_version'); if(lastSeen && lastSeen!==APP_VERSION)setTimeout(()=>openChangelog(),800); localStorage.setItem('schlueckchen_last_version',APP_VERSION); } // ── BOOT ─────────────────────────────────── async function bootApp(user){ if(curUser&&curUser.id===user.id)return; curUser=user; var isAdmin=user.email===ADMIN_INTERNAL_EMAIL; var res=await sb.from('profiles').select('*').eq('id',user.id).single(); if(!res.data){ var uname=user.user_metadata&&user.user_metadata.username||(isAdmin?'Admin':'Nutzer'); var role=isAdmin?'admin':(user.user_metadata&&user.user_metadata.role||'tester'); await sb.from('profiles').upsert({id:user.id,username:uname,role:role,channel:isAdmin?'admin':'stable'}); curProfile={id:user.id,username:uname,role:role,channel:isAdmin?'admin':'stable'}; } else { curProfile=res.data; if(isAdmin&&curProfile.role!=='admin'){ curProfile.role='admin'; await sb.from('profiles').update({role:'admin',channel:'admin'}).eq('id',user.id); } } applyProfile(); await loadToday(); await loadHistory(); if(curProfile.role!=='admin')await loadMyFeedback(); setTimeout(function(){checkForNewReplies();},1500); showScreen('app'); } // ── DATA ─────────────────────────────────── function todayKey(){return new Date().toISOString().slice(0,10);} function clearDay(){ if(!todayEntries.length){toast('Keine EintrΓ€ge vorhanden');return;} // Custom confirm dialog (confirm() blocked in some mobile browsers) const ov=document.createElement('div'); ov.style.cssText='position:fixed;inset:0;background:rgba(0,0,0,.5);z-index:9999;display:flex;align-items:center;justify-content:center;padding:24px'; ov.innerHTML='
' +'
πŸ—‘οΈ
' +'
LΓΆschen?
' +'
Alle heutigen EintrΓ€ge werden gelΓΆscht.
' +'
' +'' +'' +'
'; document.body.appendChild(ov); ov.querySelector('#cn').onclick=()=>ov.remove(); ov.querySelector('#cy').onclick=async()=>{ ov.remove(); const ids=todayEntries.map(e=>e.id); for(const id of ids) await sb.from('feeding_entries').delete().eq('id',id); todayEntries=[]; renderSum();renderLog();toast('πŸ—‘οΈ Alle gelΓΆscht'); }; } // ── RENDER ───────────────────────────────── function renderDate(){ const d=new Date(); g('today-str').textContent=DAYS[d.getDay()]+', '+d.getDate()+'. '+MO[d.getMonth()]+' '+d.getFullYear(); } function renderSum(){ const milk=todayEntries.filter(e=>e.type==='milk').reduce((s,e)=>s+Number(e.amount),0); const brei=todayEntries.filter(e=>e.type==='brei').reduce((s,e)=>s+Number(e.amount),0); g('s-milk').textContent=milk;g('s-brei').textContent=brei;g('s-cnt').textContent=todayEntries.length; } function renderLog(){ var empty=g('logempty'),list=g('loglist'); if(!todayEntries.length){empty.classList.remove('hidden');list.classList.add('hidden');return;} empty.classList.add('hidden');list.classList.remove('hidden'); var sp={small:'Klein',medium:'Mittel',large:'Groß'}; while(list.firstChild)list.removeChild(list.firstChild); todayEntries.forEach(function(e){ var typeLabel=e.type==='medi'?'Medikament':e.type==='milk'?'Milch':'Brei'; var dotType=e.type==='medi'?'milk':e.type; var icon=e.type==='milk'?'🍼':e.type==='medi'?'πŸ’Š':'πŸ₯£'; var timeStr=(e.entry_time||'').slice(0,5); var row=document.createElement('div'); row.className='litem'; var dot=document.createElement('div'); dot.className='ldot '+dotType; dot.textContent=icon; row.appendChild(dot); var meta=document.createElement('div'); meta.className='lmeta'; var ltype=document.createElement('div'); ltype.className='ltype'; var byStr=(e.added_by&&e.added_by!==curUser.id)?' Β· von Gast':''; ltype.textContent=typeLabel+(e.spoon_size?' Β· '+sp[e.spoon_size]+' LΓΆffel':'')+byStr; meta.appendChild(ltype); var amtRow=document.createElement('div'); amtRow.style.display='flex'; amtRow.style.alignItems='baseline'; amtRow.style.flexWrap='wrap'; amtRow.style.gap='4px'; var amt=document.createElement('span'); amt.className='lamount '+e.type; amt.textContent=e.amount; amtRow.appendChild(amt); var unit=document.createElement('span'); unit.className='lunit'; unit.textContent=' '+e.unit; amtRow.appendChild(unit); if(e.note&&e.type!=='medi'){ // Split note by ' Β· ' to show note and medi separately var parts=e.note.split(' Β· πŸ’Š '); var noteText=parts[0]; var mediText=parts[1]?parts.slice(1).join(' Β· '):null; if(noteText&&!noteText.startsWith('πŸ’Š')){ var noteSpan=document.createElement('span'); noteSpan.style.cssText='font-size:11px;color:var(--text-l);font-weight:700'; noteSpan.textContent='Β· πŸ“ '+noteText; amtRow.appendChild(noteSpan); } if(mediText){ var mediSpan=document.createElement('span'); mediSpan.style.cssText='font-size:11px;color:var(--purple);font-weight:700'; mediSpan.textContent='Β· πŸ’Š '+mediText; amtRow.appendChild(mediSpan); } else if(noteText&¬eText.startsWith('πŸ’Š')){ var mediSpan2=document.createElement('span'); mediSpan2.style.cssText='font-size:11px;color:var(--purple);font-weight:700'; mediSpan2.textContent='Β· '+noteText; amtRow.appendChild(mediSpan2); } } meta.appendChild(amtRow); row.appendChild(meta); var time=document.createElement('div'); time.className='ltime'; time.textContent=timeStr+' Uhr'; row.appendChild(time); var btn=document.createElement('button'); btn.className='ldel'; btn.textContent='βœ•'; (function(id){btn.addEventListener('click',function(){delEntry(id);});})(e.id); row.appendChild(btn); list.appendChild(row); }); } function renderHist(history){ const card=g('histcard'); if(!(history&&history.length)){card.classList.add('hidden');return;} card.classList.remove('hidden'); g('histlist').innerHTML=history.map(h=>{ const[,m,d]=h.summary_date.split('-'); return`
${parseInt(d)}. ${MO[parseInt(m)-1]}
🍼 ${h.milk_total_ml}mlπŸ₯£ ${h.brei_total_g}gβ€Ί
`; }).join(''); } function renderMyFeedback(data){ const list=g('my-feedback-list'); if(!(data&&data.length)){list.innerHTML='';return;} list.innerHTML=data.map(f=>`
${{general:'πŸ’¬',bug:'πŸ›',feature:'✨',praise:'🌟'}[f.category]||'πŸ’¬'} ${f.category} ${new Date(f.created_at).toLocaleDateString('de')} ${f.status==='resolved'?'βœ“ Beantwortet':''}
${f.message}
${(f.feedback_replies&&f.feedback_replies.length)?`
${f.feedback_replies.map(r=>`
πŸ‘‘ ${r.message}
`).join('')}
`:''}
`).join(''); } function renderAmtGrid(){ var p=selType==='milk'?MILK_P:BREI_P; var u=selType==='milk'?'ml':'g'; var html=''; for(var i=0;i'+v+'
'+u+'
'; } g('agrid').innerHTML=html; } // ── CONTROLS ─────────────────────────────── function pickType(t){ try{ var _gstored=localStorage.getItem('schlk_guest_party'); if(_gstored){ var _gperm='eingeschraenkt'; try{_gperm=JSON.parse(_gstored).perm||'eingeschraenkt';}catch(e){} if(t==='medi')return; if(t==='brei'&&_gperm==='eingeschraenkt')return; } selType=t;selAmt=null;selSpoon=null;selMedi=null; if(g('tb-milk'))g('tb-milk').className='tbtn milk'+(t==='milk'?' on':''); if(g('tb-brei'))g('tb-brei').className='tbtn brei'+(t==='brei'?' on':''); if(g('tb-medi'))g('tb-medi').className='tbtn'+(t==='medi'?' on':''); if(g('spoonrow'))g('spoonrow').classList.toggle('show',t==='brei'); if(g('agrid'))g('agrid').style.display=t==='medi'?'none':'grid'; if(g('medi-section'))g('medi-section').style.display=t==='medi'?'block':'none'; var freerow=document.querySelector('.freerow');if(freerow)freerow.style.display=t==='medi'?'none':'flex'; if(t==='medi'){ if(g('addbtn')){g('addbtn').className='addbtn';g('addbtn').style.background='linear-gradient(135deg,var(--purple),#6A4FB0)';g('addbtn').textContent='πŸ’Š Medikament eintragen';} renderMediQuick(); } else { if(g('addbtn')){g('addbtn').style.background='';g('addbtn').className='addbtn '+t;g('addbtn').textContent=t==='milk'?'🍼 Milch eintragen':'πŸ₯£ Brei eintragen';} } if(t!=='medi'&&g('ubadge2')){g('ubadge2').textContent=t==='milk'?'ml':'g';g('ubadge2').className='ubadge2 '+t;} if(g('cval'))g('cval').value=''; clearSpoonSel(); renderAmtGrid(); }catch(ex){toast('❌ pickType FEHLER: '+ex.message,'err');} } function pickAmt(v){ selAmt=Number(v); selSpoon=null; clearSpoonSel(); if(g('cval'))g('cval').value=''; renderAmtGrid(); } function pickSpoon(size,gr){ selSpoon={size,gr};selAmt=gr; ['s','m','l'].forEach(x=>g('sp-'+x).className='spbtn'); g('sp-'+size[0]).className='spbtn on';renderAmtGrid(); } function clearSpoonSel(){['s','m','l'].forEach(x=>g('sp-'+x).className='spbtn');} function onCustom(){const v=parseInt(g('cval').value);if(v>0){selAmt=v;selSpoon=null;clearSpoonSel();renderAmtGrid();}else selAmt=null;} function setNow(){const n=new Date();if(!g('etime'))return;g('etime').value=String(n.getHours()).padStart(2,'0')+':'+String(n.getMinutes()).padStart(2,'0');} function toggleHist(){const l=g('histlist'),t=g('histtog'),h=l.classList.contains('hidden');l.classList.toggle('hidden',!h);t.classList.toggle('open',h);} // ── POPUP ────────────────────────────────── function openAddPopup(){ setNow(); selAmt=null;selSpoon=null;selMedi=null; pickType(selType); // Show quick-select buttons for saved medis var mediList=getMediList(); var quick=g('emedi-quick'); if(quick){ quick.innerHTML=''; mediList.forEach(function(m){ var btn=document.createElement('button'); btn.style.cssText='border:2px solid #EEE;border-radius:20px;padding:4px 10px;font-size:11px;font-weight:800;cursor:pointer;background:var(--cream);color:var(--text-l);transition:all .2s;font-family:Nunito,sans-serif'; btn.textContent='πŸ’Š '+m.name+(m.dose?' '+m.dose+' '+m.unit:''); (function(med){ btn.onclick=function(){ if(g('emedi'))g('emedi').value=med.name; if(g('emedi-dose'))g('emedi-dose').value=med.dose||''; if(g('emedi-unit'))g('emedi-unit').value=med.unit||'Tropfen'; currentMedi=med.name;currentMediDose=med.dose||'';currentMediUnit=med.unit||'Tropfen'; quick.querySelectorAll('button').forEach(function(b){b.style.background='var(--cream)';b.style.borderColor='#EEE';b.style.color='var(--text-l)';}); btn.style.background='var(--lav)';btn.style.borderColor='var(--purple)';btn.style.color='var(--purple)'; }; })(m); quick.appendChild(btn); }); } currentMedi='';currentMediDose='';currentMediUnit='Tropfen'; if(g('emedi'))g('emedi').value=''; if(g('emedi-dose'))g('emedi-dose').value=''; if(g('emedi-unit'))g('emedi-unit').value='Tropfen'; g('add-popup').classList.remove('hidden'); document.body.style.overflow='hidden'; if(guestPartyOwnerId){ if(g('tb-medi'))g('tb-medi').style.display='none'; if(g('medi-section'))g('medi-section').style.display='none'; var stored=localStorage.getItem('schlk_guest_party'); if(stored){ try{var gp=JSON.parse(stored);if(gp.perm==='eingeschraenkt'){if(g('tb-brei'))g('tb-brei').style.display='none';if(g('enote'))g('enote').style.display='none';if(g('spoonrow'))g('spoonrow').style.display='none';}}catch(e){} } } } function closeAddPopup(){g('add-popup').classList.add('hidden');document.body.style.overflow='';currentNote='';currentMedi='';currentMediDose='';currentMediUnit='Tropfen';if(g('enote'))g('enote').value='';if(g('emedi'))g('emedi').value='';if(g('emedi-dose'))g('emedi-dose').value='';if(g('emedi-unit'))g('emedi-unit').value='Tropfen';} function closeAddPopupOutside(e){if(e.target===g('add-popup'))closeAddPopup();} // ── DAY MODAL ────────────────────────────── async function openDayModal(date,label,milk,brei){ g('modal-date-title').textContent=label; g('modal-milk').textContent=milk+'ml'; g('modal-brei').textContent=brei+'g'; g('day-modal').classList.remove('hidden'); document.body.style.overflow='hidden'; g('modal-entries').innerHTML='
Lade…
'; const sp={small:'Klein',medium:'Mittel',large:'Groß'}; let entries=[]; { const{data}=await sb.from('feeding_entries').select('*').eq('user_id',curUser.id).eq('entry_date',date).order('entry_time',{ascending:true}); entries=data||[]; } if(!entries.length){g('modal-entries').innerHTML='
Keine EintrΓ€ge
';return;} g('modal-entries').innerHTML=entries.map(e=>`
${e.type==='milk'?'🍼':'πŸ₯£'}
${e.type==='milk'?'Milch':'Brei'}${e.spoon_size?' Β· '+sp[e.spoon_size]+' LΓΆffel':''}
${e.amount} ${e.unit}
${(e.entry_time||'').slice(0,5)} Uhr
`).join(''); } function closeDayModal(event){ if(event&&event.target!==g('day-modal'))return; g('day-modal').classList.add('hidden');document.body.style.overflow=''; } // ── FEEDBACK ─────────────────────────────── function pickCat(c){selCat=c;['general','bug','feature','praise'].forEach(x=>g('cat-'+x).classList.toggle('on',x===c));} // ── STATS ────────────────────────────────── function setPeriod(p){ statPeriod=p;['week','month','all'].forEach(x=>g('pt-'+x).classList.toggle('on',x===p));renderStats(); } function renderStats(){ let data=[...allStats]; const today=new Date(); if(statPeriod==='week'){const c=new Date(today);c.setDate(today.getDate()-7);data=data.filter(d=>new Date(d.summary_date)>=c);} else if(statPeriod==='month'){const c=new Date(today);c.setDate(today.getDate()-30);data=data.filter(d=>new Date(d.summary_date)>=c);} if(!data.length){ g('avg-milk').textContent='–';g('avg-brei').textContent='–';g('avg-days').textContent='0'; g('chart-bars').innerHTML='
Noch keine Daten
'; g('stat-detail-list').innerHTML='
Noch keine Daten
'; return; } const avgMilk=Math.round(data.reduce((s,d)=>s+Number(d.milk_total_ml),0)/data.length); const avgBrei=Math.round(data.reduce((s,d)=>s+Number(d.brei_total_g),0)/data.length); g('avg-milk').textContent=avgMilk+'ml';g('avg-brei').textContent=avgBrei+'g';g('avg-days').textContent=data.length; const chartData=[...data].reverse().slice(-14); const maxVal=Math.max(...chartData.map(d=>Math.max(Number(d.milk_total_ml),Number(d.brei_total_g))),1); g('chart-bars').innerHTML=chartData.map(d=>{ const mh=Math.max(Math.round(Number(d.milk_total_ml)/maxVal*100),d.milk_total_ml>0?4:0); const bh=Math.max(Math.round(Number(d.brei_total_g)/maxVal*100),d.brei_total_g>0?4:0); const[,m,day]=d.summary_date.split('-'); return`
${mh>0?`
`:''} ${bh>0?`
`:''}
${parseInt(day)}.${MO[parseInt(m)-1].slice(0,3)}
`; }).join(''); g('stat-detail-list').innerHTML=[...data].map(d=>{ const[,m,day]=d.summary_date.split('-'); return`
${parseInt(day)}. ${MO[parseInt(m)-1]}
🍼 ${d.milk_total_ml}mlπŸ₯£ ${d.brei_total_g}gβ€Ί
`; }).join(''); } // ── ADMIN ────────────────────────────────── // ── SETTINGS ─────────────────────────────── function initSettings(){ if(curProfile)g('set-username-display').textContent=curProfile.username; g('set-version').textContent=APP_VERSION;loadNahrung();loadMedi(); } async function changeUsername(){ const n=g('set-new-username').value.trim();if(!n)return toast('Bitte Namen eingeben.'); const{error:une}=await sb.from('profiles').update({username:n}).eq('id',curUser.id);if(une)return toast('Fehler','err'); curProfile.username=n;g('set-username-display').textContent=n; g('ubadge').textContent=curProfile.role==='admin'?n+' Β· '+APP_VERSION:'πŸ‘€ '+n; g('set-new-username').value='';toast('βœ… Name geΓ€ndert!','ok'); } async function changePassword(){ const pw=g('set-new-pw').value;if(!pw||pw.length<8)return toast('Mind. 8 Zeichen!'); const{error:pwe}=await sb.auth.updateUser({password:pw});if(pwe)return toast('Fehler','err'); g('set-new-pw').value='';toast('βœ… Passwort geΓ€ndert!','ok'); } // CHANGELOG function openChangelog(){ g('changelog-overlay').classList.remove('hidden'); document.body.style.overflow='hidden'; } function closeChangelog(e){ if(e&&e.target!==g('changelog-overlay'))return; g('changelog-overlay').classList.add('hidden'); document.body.style.overflow=''; } // MEDIKAMENTE function getMediList(){return JSON.parse(localStorage.getItem('schlueckchen_medis')||'[]');} function saveMediList(l){localStorage.setItem('schlueckchen_medis',JSON.stringify(l));} function loadMedi(){ const list=getMediList(),c=g('medi-list'); if(!list.length){c.innerHTML='
Noch keine Medikamente hinzugefΓΌgt
';return;} c.innerHTML=list.map((m,i)=>`
πŸ’Š
${m.name}
${m.dose} ${m.unit}
`).join(''); } function addMedi(){ const name=g('medi-name').value.trim(),dose=g('medi-dose').value.trim(),unit=g('medi-unit').value; if(!name)return toast('Bitte Namen eingeben.'); const l=getMediList();l.push({name,dose,unit});saveMediList(l); g('medi-name').value='';g('medi-dose').value=''; loadMedi();renderMediQuick();toast('βœ… HinzugefΓΌgt!','ok'); } function delMedi(i){const l=getMediList();l.splice(i,1);saveMediList(l);loadMedi();renderMediQuick();} function renderMediQuick(){ const list=getMediList(),c=g('medi-quick-list'); if(!c)return; if(!list.length){c.innerHTML='
Keine Medikamente gespeichert – zuerst in Einstellungen hinzufΓΌgen
';return;} c.innerHTML=list.map((m,i)=>``).join(''); } function selectMediQuick(i){ selMedi=getMediList()[i]; g('medi-quick-list').querySelectorAll('button').forEach((b,j)=>{ b.style.background=j===i?'var(--lav)':'var(--cream)'; b.style.borderColor=j===i?'var(--purple)':'#EEE'; b.style.color=j===i?'var(--purple)':'var(--text-l)'; }); g('medi-free-name').value=selMedi.name; g('medi-free-dose').value=selMedi.dose; g('medi-free-unit').value=selMedi.unit; } function getNahrungList(){return JSON.parse(localStorage.getItem('schlueckchen_nahrung')||'[]');} function saveNahrungList(l){localStorage.setItem('schlueckchen_nahrung',JSON.stringify(l));} function loadNahrung(){ const list=getNahrungList(),c=g('nahrung-list'); if(!list.length){c.innerHTML='
Noch keine Nahrung hinzugefΓΌgt
';return;} c.innerHTML=list.map((n,i)=>`
${n.type==='milk'?'🍼':'πŸ₯£'}
${n.name}
${n.grams}g Packung Β· ${n.type==='milk'?'Milch':'Brei'}
`).join(''); } function addNahrung(){ const name=g('nahrung-name').value.trim(),type=g('nahrung-type').value,grams=parseInt(g('nahrung-grams').value); if(!name)return toast('Bitte Namen eingeben.');if(!grams||grams<=0)return toast('Bitte Packungsgrâße eingeben.'); const l=getNahrungList();l.push({name,type,grams});saveNahrungList(l); g('nahrung-name').value='';g('nahrung-grams').value='';loadNahrung();toast('βœ… HinzugefΓΌgt!','ok'); } function delNahrung(i){const l=getNahrungList();l.splice(i,1);saveNahrungList(l);loadNahrung();} function showDirectPwSet(){ g('pw-set-overlay').classList.remove('hidden'); document.body.style.overflow='hidden'; } function closePwSet(e){ if(e&&e.target!==g('pw-set-overlay'))return; g('pw-set-overlay').classList.add('hidden'); document.body.style.overflow=''; } async function doDirectPwSet(){ const email=g('pw-set-email').value.trim(); const current=g('pw-set-current').value; const newPw=g('pw-set-new').value; const confirm=g('pw-set-confirm').value; const errEl=g('pw-set-err'); errEl.style.display='none'; if(!email||!current||!newPw||!confirm){errEl.textContent='Alle Felder ausfΓΌllen.';errEl.style.display='block';return;} if(newPw.length<8){errEl.textContent='Mind. 8 Zeichen.';errEl.style.display='block';return;} if(newPw!==confirm){errEl.textContent='PasswΓΆrter stimmen nicht ΓΌberein.';errEl.style.display='block';return;} g('pw-set-btn').disabled=true; const{error:le}=await sb.auth.signInWithPassword({email,password:current}); if(le){g('pw-set-btn').disabled=false;errEl.textContent='Aktuelles Passwort falsch.';errEl.style.display='block';return;} const{error:ue}=await sb.auth.updateUser({password:newPw}); g('pw-set-btn').disabled=false; if(ue){errEl.textContent='Fehler: '+ue.message;errEl.style.display='block';return;} closePwSet();toast('Passwort geΓ€ndert!','ok'); } function showDeleteAccount(){ const ov=document.createElement('div'); ov.style.cssText='position:fixed;inset:0;background:rgba(0,0,0,.5);z-index:9999;display:flex;align-items:center;justify-content:center;padding:24px'; ov.innerHTML='
⚠️
Account lΓΆschen?
Alle Daten werden permanent gelΓΆscht.
'; document.body.appendChild(ov); ov.querySelector('#del-no').onclick=()=>ov.remove(); ov.querySelector('#del-yes').onclick=async()=>{ov.remove();await deleteAccount();}; } async function deleteAccount(){ if(!curUser)return; try{ await sb.from('feeding_entries').delete().eq('user_id',curUser.id); await sb.from('daily_summaries').delete().eq('user_id',curUser.id); await sb.from('feedback').delete().eq('user_id',curUser.id); await sb.from('profiles').delete().eq('id',curUser.id); await sb.auth.signOut(); curUser=curProfile=null;todayEntries=[]; showScreen('auth');toast('Account gelΓΆscht.','ok'); }catch(e){toast('Fehler: '+e.message,'err');} } // ── PULL TO REFRESH (Admin) ──────────────── // ── SCREENS ──────────────────────────────── function showScreen(name){ var scr=['auth','app','admin','stats','adminlogin','settings']; for(var _i=0;_iel.classList.remove('show'),2800);} function applyUpdate(){window.location.reload();} // ── BOOT ─────────────────────────────────── // PRODUCTION DB FUNCTIONS async function loadToday(){ if(!curUser)return; var res=await sb.from('feeding_entries').select('*').eq('user_id',curUser.id).eq('entry_date',todayKey()).order('entry_time',{ascending:false}); if(res.error){console.error('loadToday:',res.error.message);return;} todayEntries=res.data||[];renderSum();renderLog(); } async function loadHistory(){ if(!curUser)return; var res=await sb.from('daily_summaries').select('*').eq('user_id',curUser.id).neq('summary_date',todayKey()).order('summary_date',{ascending:false}).limit(30); renderHist(res.data||[]); } async function loadMyFeedback(){ if(!curUser)return; var res=await sb.from('feedback').select('*,feedback_replies(id,message,created_at)').eq('user_id',curUser.id).order('created_at',{ascending:false}).limit(10); renderMyFeedback(res.data||[]); } async function loadStats(){ if(!curUser)return; var res=await sb.from('daily_summaries').select('*').eq('user_id',curUser.id).order('summary_date',{ascending:false}).limit(90); allStats=res.data||[];renderStats(); } async function loadAdminData(){ var btn=g('admin-refresh-btn'); if(btn){btn.textContent='⏳';btn.disabled=true;} try{ var ur=await sb.from('profiles').select('*').order('created_at',{ascending:false}); var er=await sb.from('feeding_entries').select('id',{count:'exact',head:true}); var fr=await sb.from('feedback').select('id,username,category,message,status,created_at,feedback_replies(id,message,created_at)').order('created_at',{ascending:false}); if(ur.error)console.error('profiles:',ur.error.message); if(fr.error)console.error('feedback:',fr.error.message); var fbData=fr.data||[]; if(g('a-users'))g('a-users').textContent=(ur.data||[]).length; if(g('a-entries'))g('a-entries').textContent=er.count||0; if(g('a-feedback-new'))g('a-feedback-new').textContent=fbData.filter(function(f){return f.status==='new';}).length; if(g('a-feedback-total'))g('a-feedback-total').textContent=fbData.length; var catIcon={general:'πŸ’¬',bug:'πŸ›',feature:'✨',praise:'🌟'}; if(g('a-fblist')){ if(!fbData.length){g('a-fblist').innerHTML='
Kein Feedback vorhanden
';} else{ var html=''; fbData.forEach(function(f){ html+='
'; html+='
@'+(f.username||'?')+''; html+=''+(catIcon[f.category]||'πŸ’¬')+' '+f.category+''; html+=''+f.status+'
'; html+='
'+f.message+'
'; if(f.feedback_replies&&f.feedback_replies.length){ html+='
'; f.feedback_replies.forEach(function(r){html+='
πŸ‘‘ '+r.message+'
';}); html+='
'; } html+='
'; html+=''; html+=''; html+=''; html+='
'; }); g('a-fblist').innerHTML=html; } } if(g('a-ulist')){ var uhtml=''; (ur.data||[]).forEach(function(u){uhtml+='';}); uhtml+='
NameRolleSeit
'+(u.username||'?')+''+u.role+''+new Date(u.created_at).toLocaleDateString('de')+'
'; g('a-ulist').innerHTML=uhtml; } }catch(err){console.error('loadAdminData:',err);toast('Fehler beim Laden','err');} if(btn){btn.textContent='πŸ”„';btn.disabled=false;} } function _ar(el){adminReply(el.dataset.fid);} function _ad(el){adminDelFb(el.dataset.fid);} function addEntry(){ if(!curUser){toast('❌ Nicht eingeloggt!','err');return;} var etimeEl=g('etime'); var time=etimeEl?etimeEl.value:''; if(!time){ var n=new Date(); time=String(n.getHours()).padStart(2,'0')+':'+String(n.getMinutes()).padStart(2,'0'); } var note=(currentNote||'').trim()||(g('enote')?g('enote').value.trim():''); var medi=(currentMedi||'').trim()||(g('emedi')?g('emedi').value.trim():''); var mediDose=currentMediDose||(g('emedi-dose')?g('emedi-dose').value:''); var mediUnit=currentMediUnit||'Tropfen'; var mediLabel=medi?(medi+(mediDose?' Β· '+mediDose+' '+mediUnit:'')):null; var fullNote=[note,mediLabel?'πŸ’Š '+mediLabel:null].filter(Boolean).join(' Β· ')||null; if(selType==='medi'){ var mname=(g('medi-free-name')?g('medi-free-name').value.trim():'')||(selMedi?selMedi.name:''); var mdose=(g('medi-free-dose')?g('medi-free-dose').value.trim():'')||'1'; var munit=(g('medi-free-unit')?g('medi-free-unit').value:'')||'Tropfen'; if(!mname)return toast('⚠️ Bitte Medikament wΓ€hlen!'); var tId=guestPartyOwnerId||curUser.id; sb.from('feeding_entries').insert({user_id:tId,added_by:curUser.id,type:'medi',amount:parseFloat(mdose)||1,unit:munit,entry_time:time+':00',entry_date:todayKey(),note:mname+(note?' Β· '+note:'')}).then(function(res){ if(res.error)return toast('❌ '+res.error.message,'err'); loadToday();closeAddPopup();toast('πŸ’Š '+mname+' eingetragen!','ok'); }); return; } var amt=selAmt||(g('cval')&&g('cval').value?Number(g('cval').value):0); if(!amt||amt<=0)return toast('⚠️ Bitte Menge wΓ€hlen!'); var tId=guestPartyOwnerId||curUser.id; sb.from('feeding_entries').insert({user_id:tId,added_by:curUser.id,type:selType,amount:amt,unit:selType==='milk'?'ml':'g',entry_time:time+':00',entry_date:todayKey(),spoon_size:selSpoon?selSpoon.size:null,note:fullNote}).then(function(res){ if(res.error)return toast('❌ '+res.error.message,'err'); selAmt=null;selSpoon=null;clearSpoonSel(); if(g('cval'))g('cval').value=''; if(g('enote'))g('enote').value=''; currentNote='';currentMedi='';currentMediDose='';currentMediUnit='Tropfen'; closeAddPopup(); toast('βœ… '+amt+(selType==='milk'?'ml':'g')+' '+(selType==='milk'?'Milch':'Brei')+' gespeichert!','ok'); loadToday(); }); } async function delEntry(id){ await sb.from('feeding_entries').delete().eq('id',id); todayEntries=todayEntries.filter(function(e){return e.id!==id;}); renderSum();renderLog(); } function sendFeedback(){ var msg=g('fbtext').value.trim(); if(!msg)return toast('Bitte Nachricht eingeben.'); sb.from('feedback').insert({user_id:curUser.id,username:curProfile.username,message:msg,category:selCat,status:'new'}).then(function(res){ if(res.error)return toast('Fehler','err'); g('fbtext').value='';toast('πŸ’¬ Danke!','ok');loadMyFeedback(); }); } async function adminReply(fbId){ var input=g('fri-'+fbId); if(!input||!input.value.trim())return toast('Bitte Antwort eingeben.'); var msg=input.value.trim(); var res=await sb.from('feedback_replies').insert({feedback_id:fbId,admin_id:curUser.id,message:msg}); if(res.error)return toast('Fehler: '+res.error.message,'err'); await sb.from('feedback').update({status:'resolved'}).eq('id',fbId); input.value='';toast('βœ… Antwort gesendet!','ok');loadAdminData(); } async function adminDelFb(fbId){ var card=g('fbc-'+fbId);if(!card)return; var ov=document.createElement('div'); ov.style.cssText='position:fixed;inset:0;background:rgba(0,0,0,.5);z-index:9999;display:flex;align-items:center;justify-content:center;padding:24px'; ov.innerHTML='
πŸ—‘οΈ
Feedback lΓΆschen?
'; document.body.appendChild(ov); ov.querySelector('#dn').onclick=function(){ov.remove();}; ov.querySelector('#dy').onclick=async function(){ov.remove();await sb.from('feedback').delete().eq('id',fbId);card.remove();toast('πŸ—‘οΈ GelΓΆscht');}; } async function checkForNewReplies(){ if(!curUser||curProfile.role==='admin')return; try{ var lastSeen=localStorage.getItem('last_reply_'+curUser.id)||'1970-01-01'; var res=await sb.from('feedback_replies').select('message,created_at,feedback!inner(message,user_id)').eq('feedback.user_id',curUser.id).gt('created_at',lastSeen).order('created_at',{ascending:false}).limit(5); if(res.data&&res.data.length){ showReplyNotif(res.data.map(function(r){return {original:r.feedback&&r.feedback.message||'Dein Feedback',reply:r.message,date:new Date(r.created_at).toLocaleDateString('de')};})); } }catch(e){console.log('Reply check:',e);} } setNow();renderDate();renderAmtGrid(); checkPartyUrl(); var cachedV=localStorage.getItem('schlk_cache_v'); if(cachedV&&cachedV!==APP_VERSION){localStorage.setItem('schlk_cache_v',APP_VERSION);window.location.reload(true);} else{localStorage.setItem('schlk_cache_v',APP_VERSION);} var adminLoggingIn=false; var guestPartyOwnerId=null; sb.auth.getSession().then(function(res){ var s=(res.data&&res.data.session)?res.data.session:null; if(s&&s.user.email===ADMIN_INTERNAL_EMAIL&&!adminLoggingIn){ sb.auth.signOut(); showScreen('auth'); return; } if(s){bootApp(s.user);}else{showScreen('auth');} }); sb.auth.onAuthStateChange(function(_,session){ if(!session){curUser=null;curProfile=null;showScreen('auth');return;} bootApp(session.user); }); var partyPerm='eingeschraenkt'; var partyDur=120; var activeParty=null; var partyCodeInterval=null; var partyMembersInterval=null; function openPartyQuick(){g('party-quick-overlay').classList.remove('hidden');} function closePartyQuick(){g('party-quick-overlay').classList.add('hidden');} function openActiveParty(){if(activeParty){g('party-active-overlay').classList.remove('hidden');}else{openPartyQuick();}} function openPartyCreate(){g('party-create-overlay').classList.remove('hidden');} function closePartyCreate(){g('party-create-overlay').classList.add('hidden');} function openPartyJoin(){g('party-join-overlay').classList.remove('hidden');if(g('party-join-code'))g('party-join-code').value='';if(g('party-join-err'))g('party-join-err').style.display='none';} function closePartyJoin(){g('party-join-overlay').classList.add('hidden');} function selectPerm(p){partyPerm=p;var ps=['eingeschraenkt','teilweise','voll'];for(var i=0;i0?pLeft+'min':''; if(partyExp<=now)endParty(); } async function renewPartyCode(){ if(!activeParty)return; var code=genPartyCode();var codeExp=new Date(Date.now()+15*60*1000); var r=await sb.from('parties').update({code:code,code_expires_at:codeExp.toISOString()}).eq('id',activeParty.id); if(!r.error){activeParty.code=code;activeParty.code_expires_at=codeExp.toISOString();} } async function refreshPartyMembers(){ if(!activeParty)return; var r=await sb.from('party_members').select('user_id').eq('party_id',activeParty.id); var el=g('party-members-list');if(!el)return; if(r.error){el.innerHTML='
Fehler: '+r.error.message+'
';return;} if(!r.data||r.data.length===0){el.innerHTML='
Noch niemand beigetreten
';return;} var html=''; for(var i=0;iRaus
'; } el.innerHTML=html; } async function kickMember(userId){ if(!activeParty)return; await sb.from('party_members').delete().eq('party_id',activeParty.id).eq('user_id',userId); toast('Gast entfernt','ok'); setTimeout(refreshPartyMembers,500); } async function endParty(){ if(!activeParty)return; await sb.from('parties').update({active:false}).eq('id',activeParty.id); if(partyCodeInterval)clearInterval(partyCodeInterval); if(partyMembersInterval)clearInterval(partyMembersInterval); partyCodeInterval=null;partyMembersInterval=null; activeParty=null; g('party-active-overlay').classList.add('hidden'); if(g('party-timer-mini'))g('party-timer-mini').textContent=''; if(g('party-quick-btn'))g('party-quick-btn').style.display='block'; toast('Party beendet','ok'); } async function joinParty(){ if(!curUser)return; var code=g('party-join-code').value.trim(); if(!code||code.length!==4){var e=g('party-join-err');if(e){e.textContent='Bitte 4-stelligen Code eingeben.';e.style.display='block';}return;} var r=await sb.from('parties').select('*').eq('code',code).eq('active',true).single(); if(r.error||!r.data){var e=g('party-join-err');if(e){e.textContent='Code ungueltig.';e.style.display='block';}return;} var party=r.data; if(new Date(party.expires_at)<=new Date()){var e=g('party-join-err');if(e){e.textContent='Party abgelaufen.';e.style.display='block';}return;} var r2=await sb.from('party_members').insert({party_id:party.id,user_id:curUser.id}); if(r2.error&&r2.error.code!=='23505'){var e=g('party-join-err');if(e){e.textContent='Fehler: '+r2.error.message;e.style.display='block';}return;} guestPartyOwnerId=party.owner_id; localStorage.setItem('schlk_guest_party',JSON.stringify({id:party.id,perm:party.permission,owner:party.owner_id})); closePartyJoin();applyGuestMode(party.permission);toast('Party beigetreten!','ok'); } function applyGuestMode(perm){ var existing=g('guest-banner');if(existing)existing.remove(); var banner=document.createElement('div'); banner.className='guest-banner';banner.id='guest-banner'; banner.textContent='Party aktiv - '+(perm==='eingeschraenkt'?'Nur Milch':perm==='teilweise'?'Milch und Brei':'Alles erlaubt'); var leaveBtn=document.createElement('button'); leaveBtn.textContent='Verlassen'; leaveBtn.ontouchstart=function(){}; leaveBtn.onclick=leaveParty; leaveBtn.style.cssText='border:none;background:rgba(255,255,255,0.3);color:white;border-radius:8px;padding:3px 10px;font-size:11px;font-weight:800;cursor:pointer;margin-left:8px'; banner.appendChild(leaveBtn); var app=g('s-app');if(app)app.insertBefore(banner,app.firstChild); if(perm==='eingeschraenkt'){ if(g('tb-brei'))g('tb-brei').style.display='none'; if(g('tb-medi'))g('tb-medi').style.display='none'; if(g('medi-section'))g('medi-section').style.display='none'; if(g('enote'))g('enote').style.display='none'; if(g('spoonrow'))g('spoonrow').style.display='none'; } else if(perm==='teilweise'){ if(g('tb-medi'))g('tb-medi').style.display='none'; if(g('medi-section'))g('medi-section').style.display='none'; } if(g('n-stats'))g('n-stats').style.display='none'; if(g('party-quick-btn'))g('party-quick-btn').style.display='none'; } async function leaveParty(){ var stored=localStorage.getItem('schlk_guest_party'); if(stored){ try{ var p=JSON.parse(stored); if(p&&p.id&&curUser){await sb.from('party_members').delete().eq('party_id',p.id).eq('user_id',curUser.id);} }catch(e){} } localStorage.removeItem('schlk_guest_party'); guestPartyOwnerId=null; var banner=g('guest-banner');if(banner)banner.remove(); if(g('tb-brei'))g('tb-brei').style.display=''; if(g('tb-medi'))g('tb-medi').style.display=''; if(g('medi-section'))g('medi-section').style.display=''; if(g('enote'))g('enote').style.display=''; if(g('spoonrow'))g('spoonrow').style.display=''; if(g('n-stats'))g('n-stats').style.display=''; if(g('party-quick-btn'))g('party-quick-btn').style.display='block'; toast('Party verlassen','ok'); } function checkGuestParty(){ var stored=localStorage.getItem('schlk_guest_party');if(!stored)return; try{ var p=JSON.parse(stored); if(p&&p.id){ if(p.owner)guestPartyOwnerId=p.owner; sb.from('parties').select('active,permission,expires_at,owner_id').eq('id',p.id).single().then(function(r){ if(r.data&&r.data.active&&new Date(r.data.expires_at)>new Date()){ guestPartyOwnerId=r.data.owner_id;applyGuestMode(r.data.permission); } else { localStorage.removeItem('schlk_guest_party');guestPartyOwnerId=null; } }); } }catch(e){} } function checkPartyUrl(){ var params=new URLSearchParams(window.location.search); var code=params.get('party'); if(!code)return; localStorage.setItem('schlk_pending_party',code); if(curUser&&g('party-join-code')){ g('party-join-code').value=code; setTimeout(openPartyJoin,500); } } function checkPendingParty(){ var code=localStorage.getItem('schlk_pending_party');if(!code||!curUser)return; localStorage.removeItem('schlk_pending_party'); if(g('party-join-code')){g('party-join-code').value=code;openPartyJoin();} } setInterval(function(){ if(curUser)loadToday(); if(activeParty)refreshPartyMembers(); },15000);schlk_pending_party'); if(g('party-join-code')){g('party-join-code').value=code;openPartyJoin();} } setInterval(function(){ if(curUser)loadToday(); if(activeParty)refreshPartyMembers(); },15000);
πŸŽ‰ Party
Party starten
BERECHTIGUNG
DAUER
πŸŽ‰ Party laeuft!
Laeuft noch...
----
Aendert sich in 15:00
MITGLIEDER
Noch niemand beigetreten
Party beitreten