| Server IP : 202.61.199.114 / Your IP : 216.73.217.139 Web Server : nginx/1.22.1 System : Linux de.arni-solutions.de 6.1.0-49-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.174-1 (2026-05-26) x86_64 User : web20 ( 1018) PHP Version : 8.4.23 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : ON Directory : /proc/3951580/root/tmp/ |
Upload File : |
<!DOCTYPE html><html lang="de"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no, viewport-fit=cover"><meta name="robots" content="noindex,nofollow"><meta name="apple-mobile-web-app-capable" content="yes"><meta name="mobile-web-app-capable" content="yes"><meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"><meta name="theme-color" content="#0d2c44"><title>Check-in · AA - DA 961</title><style>@font-face{font-family:"EuroPlate";src:url("https://seaside.pacim.de/assets/fonts/EuroPlate.ttf") format("truetype");font-display:swap;}
:root{--navy:#0d2c44;--navy2:#11436b;--blue:#1b6ca8;--green:#2fb344;--red:#d63939;--gold:#f3b53f;--ink:#16384f;--muted:#5b7488;--line:#e6eef4;}
*{box-sizing:border-box;margin:0;padding:0;}
html{-webkit-text-size-adjust:100%;text-size-adjust:100%;}
body{font-family:-apple-system,Segoe UI,Roboto,Helvetica,Arial,sans-serif;background:#eef3f7;color:var(--ink);min-height:100vh;display:flex;flex-direction:column;align-items:center;padding:16px 12px 40px;touch-action:manipulation;}
.d-none{display:none!important;}
.card{width:100%;max-width:460px;background:#fff;border-radius:18px 18px 0 0;overflow:hidden;box-shadow:0 14px 40px rgba(13,44,68,.16);}
.hd{position:relative;background:linear-gradient(135deg,var(--navy) 0%,var(--navy2) 65%,var(--blue) 130%);color:#fff;padding:20px 22px 18px;}
.hd .back{position:absolute;top:14px;right:18px;color:#cfe2f2;font-size:13px;text-decoration:none;font-weight:600;}
.hd .k{font-size:11px;font-weight:700;letter-spacing:.16em;text-transform:uppercase;opacity:.8;}
.hd .t{font-size:22px;font-weight:800;margin-top:3px;}
.hd .no{font-size:13px;opacity:.85;margin-top:2px;}
.bd{padding:16px 22px 4px;}
.plate-wrap{position:relative;margin:2px 0 14px;}
.plate{border:2px solid #111;border-radius:8px;text-align:center;font-family:"EuroPlate",ui-monospace,monospace;font-size:30px;letter-spacing:1px;padding:9px 6px;color:#111;cursor:text;}
.plate.editing{outline:2px solid var(--blue);outline-offset:1px;padding-right:64px;text-align:left;padding-left:14px;}
.plate-save{position:absolute;right:6px;top:6px;bottom:6px;width:50px;border:0;border-radius:6px;background:var(--green);color:#fff;cursor:pointer;display:flex;align-items:center;justify-content:center;}
.plate-save svg{width:22px;height:22px;}
.muted{color:var(--muted);font-weight:400;}
.row{display:flex;justify-content:space-between;gap:12px;padding:9px 0;border-top:1px solid var(--line);font-size:14.5px;}
.row:first-of-type{border-top:0;}
.row .l{color:var(--muted);} .row .v{font-weight:600;text-align:right;}
.badges{display:flex;gap:8px;margin:14px 0 2px;}
.badge{flex:1;border-radius:12px;padding:11px;text-align:center;font-weight:700;font-size:14px;}
.b-open{background:rgba(214,57,57,.10);color:var(--red);} .b-ok{background:rgba(47,179,68,.12);color:#1d7a33;} .b-warn{background:rgba(243,181,63,.16);color:#8a6400;}
/* Status-Badge im Header (ganz unten rechts, flush in der Ecke) */
.hstat{position:absolute;right:0;bottom:0;font-size:12.5px;font-weight:700;padding:6px 14px;border-radius:8px 0 0 0;white-space:nowrap;}
.hstat.s-blue{background:#2f86d6;color:#fff;} .hstat.s-orange{background:#f59f00;color:#3a2c00;}
.hstat.s-green{background:#2fb344;color:#fff;} .hstat.s-red{background:#d63939;color:#fff;}
.btn.btn-out{background:#eef4f9;color:var(--navy);}
.btn-cancel{margin-top:22px;background:#fff;color:var(--navy);border:0;border-radius:12px;padding:15px 28px;font-size:16px;font-weight:700;cursor:pointer;}
.done-skip{margin-top:14px;font-size:12.5px;opacity:.7;}
.sec{padding:14px 22px;border-top:1px solid var(--line);}
.sec-h{font-weight:700;font-size:15px;color:var(--navy);margin-bottom:10px;}
.fld-l{display:block;font-size:12px;font-weight:700;color:var(--muted);text-transform:uppercase;letter-spacing:.04em;margin:8px 0 5px;}
.sel{width:100%;padding:12px;border:1px solid var(--line);border-radius:10px;font-size:15px;background:#fff;color:var(--ink);}
.amount{margin:12px 0;font-size:15px;}
.amount strong{font-size:22px;color:var(--navy);}
.pay-types{display:flex;gap:8px;}
.pt{flex:1;padding:13px 6px;border:2px solid var(--line);background:#fff;border-radius:12px;font-size:14px;font-weight:700;color:var(--ink);cursor:pointer;}
.pt.on{border-color:var(--blue);background:rgba(27,108,168,.08);color:var(--blue);}
.btn{display:block;width:100%;border:0;border-radius:12px;padding:15px;font-size:16px;font-weight:700;text-align:center;cursor:pointer;margin-top:12px;}
.btn-pay{background:var(--green);color:#fff;} .btn-primary{background:var(--blue);color:#fff;} .btn-light{background:#eef4f9;color:var(--navy);}
.btn-warn{background:#f59f00;color:#fff;} .btn-checkin{background:var(--green);color:#fff;} .btn-danger{background:var(--red);color:#fff;}
.btn[disabled]{background:#e7eef4;color:#9bacba;cursor:not-allowed;}
.lnk{background:none;border:0;color:#1d7a33;font-weight:700;text-decoration:underline;cursor:pointer;font-size:13.5px;padding:0;margin-left:4px;}
.modal{width:100%;max-width:420px;background:#fff;border-radius:0;overflow:hidden;box-shadow:0 20px 60px rgba(0,0,0,.35);}
.modal-h{display:flex;align-items:center;justify-content:space-between;background:var(--navy);color:#fff;padding:15px 18px;font-size:16px;font-weight:800;}
.modal-x{background:none;border:0;color:#cfe2f2;font-size:26px;line-height:1;cursor:pointer;padding:0 2px;}
.modal-b{padding:16px 18px 20px;}
.hint{font-size:12px;color:var(--muted);text-align:center;margin-top:8px;}
.modal-err{background:rgba(214,57,57,.10);color:var(--red);border-radius:10px;padding:11px 13px;font-size:13.5px;font-weight:600;margin-top:12px;}
.note{border-radius:10px;padding:12px 14px;font-size:14px;}
.note.ok{background:rgba(47,179,68,.10);color:#1d7a33;} .note.warn{background:rgba(243,181,63,.16);color:#8a6400;}
.note.info{background:rgba(27,108,168,.10);color:#155a8a;}
.status{padding:6px 22px 16px;font-size:13.5px;font-weight:600;text-align:center;}
.status.ok{color:#1d7a33;} .status.err{color:var(--red);}
.foot{margin-top:16px;font-size:12px;color:var(--muted);text-align:center;}
.overlay{position:fixed;inset:0;background:rgba(13,44,68,.92);display:flex;align-items:center;justify-content:center;z-index:50;}
.done-box{text-align:center;color:#fff;padding:30px;}
.check{width:92px;height:92px;border-radius:50%;background:var(--green);color:#fff;margin:0 auto 18px;display:flex;align-items:center;justify-content:center;}
.check svg{width:50px;height:50px;}
/* Check-out-Countdown: deutlich anders (rot/orange) als der Check-in-Countdown (navy/grün) */
.overlay.out{background:rgba(122,28,28,.94);}
.overlay.out .check{background:#e8590c;}
.done-t{font-size:24px;font-weight:800;} .done-x{font-size:15px;opacity:.85;margin-top:8px;}
.err{max-width:440px;background:#fff;border-radius:18px;padding:34px 26px;text-align:center;box-shadow:0 14px 40px rgba(13,44,68,.16);margin:60px auto;}
.err h1{font-size:40px;color:var(--navy);} .err p{color:var(--muted);margin-top:8px;}
/* ---- Fahrzeugfotos ---- */
.ph-head{display:flex;align-items:center;justify-content:space-between;gap:10px;}
.ph-title{display:flex;align-items:center;gap:7px;margin:0;} .ph-title svg{width:18px;height:18px;}
.ph-count{background:var(--blue);color:#fff;border-radius:999px;font-size:12px;font-weight:800;padding:1px 8px;min-width:20px;text-align:center;}
.ph-count.zero{display:none;}
.ph-add{display:inline-flex;align-items:center;gap:5px;background:var(--blue);color:#fff;border:0;border-radius:10px;padding:9px 14px;font-size:14px;font-weight:700;cursor:pointer;}
.ph-add svg{width:16px;height:16px;}
.ph-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:6px;margin-top:12px;}
.ph-thumb{position:relative;aspect-ratio:1/1;border-radius:10px;overflow:hidden;background:#e6eef4;cursor:pointer;}
.ph-thumb img{width:100%;height:100%;object-fit:cover;display:block;}
.ph-ndot{position:absolute;right:5px;bottom:5px;width:18px;height:18px;border-radius:50%;background:rgba(13,44,68,.82);display:flex;align-items:center;justify-content:center;}
.ph-ndot svg{width:11px;height:11px;stroke:#fff;}
.ph-empty{color:var(--muted);font-size:13.5px;margin-top:10px;}
.ph-upmodal{max-width:460px;}
.ph-pick{display:flex;gap:10px;}
.ph-pickbtn{flex:1;display:flex;flex-direction:column;align-items:center;gap:6px;border:1.5px dashed var(--line);border-radius:12px;padding:18px 8px;cursor:pointer;color:var(--navy);font-weight:700;font-size:14px;}
.ph-pickbtn svg{width:30px;height:30px;color:var(--blue);} .ph-pickbtn:active{background:#f2f7fb;}
.ph-tiles{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-top:14px;}
.ph-tile{border:1px solid var(--line);border-radius:10px;overflow:hidden;background:#fff;}
.ph-tibox{position:relative;aspect-ratio:4/3;background:#e6eef4;}
.ph-tibox img{width:100%;height:100%;object-fit:cover;display:block;}
.ph-rm{position:absolute;top:4px;right:4px;width:26px;height:26px;border:0;border-radius:50%;background:rgba(13,44,68,.85);color:#fff;font-size:18px;line-height:24px;cursor:pointer;}
.ph-st{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;color:#fff;font-size:12.5px;font-weight:700;background:rgba(13,44,68,.55);}
.ph-bar{position:absolute;left:0;bottom:0;height:4px;background:var(--green);width:0;transition:width .15s;}
.ph-tnote{width:100%;border:0;border-top:1px solid var(--line);padding:8px 9px;font-size:13px;background:#fff;}
.ph-tile.done .ph-tibox{outline:2px solid var(--green);outline-offset:-2px;}
.ph-tile.err .ph-tibox{outline:2px solid var(--red);outline-offset:-2px;}
.lb{background:rgba(8,20,30,.96);}
.lb-bar{position:absolute;top:0;left:0;right:0;display:flex;align-items:center;justify-content:space-between;padding:10px 12px;z-index:4;color:#fff;}
.lb-pos{font-size:13px;font-weight:700;opacity:.85;} .lb-actions{display:flex;gap:6px;}
.lb-btn{background:rgba(255,255,255,.16);color:#fff;border:0;border-radius:9px;min-width:40px;height:40px;font-size:22px;line-height:1;cursor:pointer;display:inline-flex;align-items:center;justify-content:center;}
.lb-btn svg{width:20px;height:20px;}
.lb-stage{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;overflow:hidden;touch-action:none;}
.lb-stage img{max-width:100%;max-height:100%;user-select:none;-webkit-user-drag:none;will-change:transform;}
.lb-nav{position:absolute;top:50%;transform:translateY(-50%);background:rgba(255,255,255,.12);color:#fff;border:0;width:42px;height:64px;font-size:30px;cursor:pointer;z-index:4;}
.lb-prev{left:0;border-radius:0 12px 12px 0;} .lb-next{right:0;border-radius:12px 0 0 12px;}
.lb-info{position:absolute;left:0;right:0;bottom:0;background:linear-gradient(transparent,rgba(0,0,0,.78));color:#fff;padding:34px 16px 16px;z-index:4;font-size:13px;}
.lb-info .lb-note{font-size:15px;font-weight:700;margin-bottom:3px;} .lb-info .lb-meta{opacity:.85;line-height:1.5;}
.lb-info .lb-edit{color:#9fd0ff;text-decoration:underline;background:none;border:0;cursor:pointer;font-size:13px;padding:0;margin-top:5px;}
/* ---- ressourcenarme Animationen: nur opacity/transform, mit Reduced-Motion-Abschaltung ---- */
@keyframes ciFadeUp{from{opacity:0;transform:translateY(10px);}to{opacity:1;transform:none;}}
@keyframes ciFade{from{opacity:0;}to{opacity:1;}}
@keyframes ciSheet{from{opacity:.3;transform:translateY(18px);}to{opacity:1;transform:none;}}
@keyframes ciPop{0%{opacity:0;transform:scale(.5);}60%{transform:scale(1.08);}100%{opacity:1;transform:none;}}
.card{animation:ciFadeUp .3s cubic-bezier(.22,.61,.36,1) both;}
.overlay:not(.d-none){animation:ciFade .18s ease;}
.modal{animation:ciSheet .24s cubic-bezier(.22,.61,.36,1);}
.check{animation:ciPop .42s cubic-bezier(.34,1.56,.64,1) both;}
.hstat{transition:background .25s ease;}
.btn,.pt,.plate-save,.lnk{transition:transform .08s ease, filter .12s ease;}
.btn:active,.pt:active,.plate-save:active{transform:scale(.97);}
@media (prefers-reduced-motion: reduce){
.card,.overlay,.modal,.check{animation:none!important;}
.btn:active,.pt:active,.plate-save:active{transform:none;}
}
</style></head><body><div class="card">
<div class="hd">
<a class="back" id="ci-back" href="https://seaside.pacim.de/day-list.php?t=604de2bc9d0d51226a70082c">← Liste</a> <div class="k">Check-in</div>
<div class="t">Kokot, Jens</div>
<div class="no">260627-AIDA-7266</div>
<span class="hstat" id="ci-status-badge"></span>
</div>
<div class="bd">
<div class="plate-wrap">
<div class="plate fe" id="ci-plate" spellcheck="false">AA - DA 961</div>
<button type="button" class="plate-save d-none" id="ci-plate-save" title="Speichern" aria-label="Speichern"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M5 13l4 4L19 7"/></svg></button>
</div>
<div class="row"><span class="l">Schiff</span><span class="v">AIDAdiva<br><span class="muted">7 Tage</span></span></div>
<div class="row"><span class="l">Stellplatz</span><span class="v">Außen</span></div>
<div class="row"><span class="l">Zeitraum</span><span class="v">27.06. – 04.07.26</span></div>
<div class="row" id="ci-timerow">
<span class="l" id="ci-timelabel">Boarding</span>
<span class="v" id="ci-timeval">12:00 Uhr</span>
</div>
</div>
<div class="sec"><div class="note ok"><strong>Bezahlt:</strong> 90,00 € · myAIDA</div></div>
<!-- Eine Haupt-Aktion: wechselt Zahlung → Check-in → Auschecken -->
<div class="sec">
<button type="button" class="btn" id="ci-action-btn">Aktion</button>
</div>
<div class="status" id="ci-status"></div>
</div>
<!-- Check-in Erfolg / Countdown -->
<div class="overlay d-none" id="ci-done">
<div class="done-box">
<div class="check" id="ci-done-ic"><svg viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M5 13l4 4L19 7"/></svg></div>
<div class="done-t" id="ci-done-t">Check-in erfasst</div>
<div class="done-x">Zurück zur Liste in <span id="ci-cd">3</span> s …</div>
<button type="button" class="btn-cancel" id="ci-cancel">Abbrechen – hier bleiben</button>
<div class="done-skip">irgendwo tippen, um sofort zur Liste zu wechseln</div>
</div>
</div>
<div class="foot">SeaSide Travel · Parken am Schiff</div>
<script>
var CFG = {"b":115156,"h":"","t":"604de2bc9d0d51226a70082c","embed":false,"paid":true,"arrived":false,"storno":false,"isAida":true,"canAct":true,"coupon":0,"amounts":[90,85,81],"payType":1,"back":"https:\/\/seaside.pacim.de\/day-list.php?t=604de2bc9d0d51226a70082c","boarding":"12:00","ciTime":"","imgApi":"https:\/\/seaside.pacim.de\/booking-images.php","imgView":false,"imgUpload":false,"imgNote":false,"plate":"AA - DA 961","bookingNo":"260627-AIDA-7266"};
(function(){
// Browser-Zoom unterbinden (iOS Safari ignoriert user-scalable=no)
['gesturestart','gesturechange','gestureend'].forEach(function(ev){ document.addEventListener(ev, function(e){ e.preventDefault(); }, {passive:false}); });
document.addEventListener('touchmove', function(e){ if(e.touches && e.touches.length>1) e.preventDefault(); }, {passive:false});
// Vollbild beim ersten Tippen (nur eigenständig; eingebettet übernimmt das die Tagesliste).
if(!CFG.embed){ document.addEventListener('pointerdown', function f(){ document.removeEventListener('pointerdown',f); var e=document.documentElement,r=e.requestFullscreen||e.webkitRequestFullscreen; if(r){ try{ r.call(e); }catch(_){} } }, {passive:true}); }
var API = location.pathname; // gleiche Datei
var $ = function(id){ return document.getElementById(id); };
var coupon = $('ci-coupon'), amountEl = $('ci-amount'), status = $('ci-status');
var selType = CFG.payType || 0; // keine Zahlungsart vorausgewählt
// Eingebettet (Overlay der Tagesliste): Statusänderungen an die Elternseite melden.
function ciState(){ return CFG.storno?'x':(CFG.arrived?'i':(CFG.paid?'p':'o')); }
function parentMsg(o){ if(CFG.embed && window.parent && window.parent!==window){ o.pacimCi=1; o.b=CFG.b; try{ window.parent.postMessage(o,'*'); }catch(e){} } }
// Anreise-/Check-in-Zeit live: angereist -> „Check-in HH:MM · Boarding HH:MM (muted)", sonst „Boarding".
function renderTimeRow(){
var row=$('ci-timerow'), lab=$('ci-timelabel'), val=$('ci-timeval'); if(!row||!lab||!val) return;
if(CFG.arrived && CFG.ciTime){ lab.textContent='Check-in'; val.innerHTML=CFG.ciTime+' Uhr'+(CFG.boarding?' <span class="muted">· Boarding '+CFG.boarding+'</span>':''); row.classList.remove('d-none'); }
else if(CFG.boarding){ lab.textContent='Boarding'; val.textContent=CFG.boarding+' Uhr'; row.classList.remove('d-none'); }
else row.classList.add('d-none');
}
function eur(v){ return v.toFixed(2).replace('.',',') + ' €'; }
function setStatus(t,k){ status.textContent = t||''; status.className = 'status' + (k?(' '+k):''); }
function refreshAmount(){ if(amountEl) amountEl.textContent = eur(CFG.amounts[coupon ? coupon.value : 0]); }
function markType(){ var ts=document.querySelectorAll('#ci-types .pt'); for(var i=0;i<ts.length;i++) ts[i].classList.toggle('on', parseInt(ts[i].dataset.type,10)===selType); }
function statusBadge(){
var sb=$('ci-status-badge'); if(!sb) return;
var cls,txt;
if(CFG.storno){ cls='s-red'; txt='Storniert'; }
else if(CFG.arrived){ cls='s-green'; txt='Angereist'; }
else if(CFG.paid){ cls='s-blue'; txt='Check-in offen'; }
else { cls='s-orange'; txt = CFG.canAct ? (eur(CFG.amounts[CFG.coupon||0])+' offen') : 'Zahlung offen'; }
sb.className='hstat '+cls; sb.textContent=txt;
}
var PAYNAMES={1:'Überweisung',2:'EC-Karte',3:'Bar'};
function renderState(){
statusBadge();
if(CFG.storno) return;
var paidSec=$('ci-paid-sec'), btn=$('ci-action-btn');
if(paidSec){
if(CFG.paid && !CFG.isAida){
paidSec.classList.remove('d-none');
$('ci-paid-info').textContent = eur(CFG.amounts[CFG.coupon||0]) + ' · ' + (PAYNAMES[CFG.payType]||'');
} else paidSec.classList.add('d-none');
}
if(btn){
btn.disabled=false;
if(CFG.arrived){ btn.textContent='Fahrzeug auschecken'; btn.className='btn btn-danger'; btn.dataset.act='uncheckin'; }
else if(CFG.paid){ btn.textContent='Check-in erfassen'; btn.className='btn btn-checkin'; btn.dataset.act='checkin'; }
else { btn.textContent='Zahlung erfassen'; btn.className='btn btn-warn'; btn.dataset.act='pay'; }
}
}
if(coupon){ coupon.value = CFG.coupon || 0; coupon.addEventListener('change', refreshAmount); refreshAmount(); }
var types=document.querySelectorAll('#ci-types .pt');
for(var i=0;i<types.length;i++){ types[i].addEventListener('click', function(){ selType=parseInt(this.dataset.type,10); markType(); payClearErr(); }); }
markType();
function post(data, cb){
var fd=new URLSearchParams(); fd.set('b',CFG.b); fd.set('h',CFG.h); if(CFG.t) fd.set('t',CFG.t);
for(var k in data) fd.set(k,data[k]);
fetch(API,{method:'POST',headers:{'Content-Type':'application/x-www-form-urlencoded;charset=UTF-8'},body:fd.toString()})
.then(function(r){return r.json();}).then(cb).catch(function(){ setStatus('Serverfehler.','err'); });
}
// ---- Zahlungs-Modal
var payModal=$('ci-pay-modal'), payErr=$('ci-pay-err');
function payError(m){ if(payErr){ payErr.textContent=m||'Fehler.'; payErr.classList.remove('d-none'); } else setStatus(m,'err'); }
function payClearErr(){ if(payErr){ payErr.textContent=''; payErr.classList.add('d-none'); } }
function openPay(){ if(!payModal) return; selType=CFG.payType||0; if(coupon){coupon.value=CFG.coupon||0; refreshAmount();} markType(); payClearErr(); payModal.classList.remove('d-none'); }
function closePay(){ if(payModal) payModal.classList.add('d-none'); }
var payClose=$('ci-pay-close'); if(payClose) payClose.addEventListener('click', closePay);
if(payModal) payModal.addEventListener('click', function(e){ if(e.target===payModal) closePay(); });
var payBtn=$('ci-pay-btn');
if(payBtn) payBtn.addEventListener('click', function(){
payClearErr();
if(!selType){ payError('Bitte Zahlungsart wählen.'); return; }
payBtn.disabled=true;
post({action:'pay', type:selType, coupon:(coupon?coupon.value:0)}, function(res){
payBtn.disabled=false;
if(!res||!res.ok){ payError((res&&res.error)||'Fehler.'); return; } // Fehler bleibt im Modal, keine Rechnung erstellt
CFG.paid=true; CFG.coupon=res.coupon; CFG.payType=res.type;
closePay(); renderState(); parentMsg({state:ciState()});
setStatus('✓ Zahlung erfasst ('+res.amount_fmt+' · '+res.type_name+')','ok');
});
});
var editBtn=$('ci-edit-btn');
if(editBtn) editBtn.addEventListener('click', function(){ openPay(); });
var IN_ICON='<svg viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M5 13l4 4L19 7"/></svg>';
var OUT_ICON='<svg viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M14 3h5a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-5"/><path d="M11 16l4-4-4-4"/><path d="M15 12H3"/></svg>';
function startCountdown(mode){
var out=(mode==='out');
var ov=$('ci-done'); if(!ov){ if(CFG.embed) parentMsg({close:1}); else location.href=CFG.back; return; }
ov.classList.toggle('out', out);
var ic=$('ci-done-ic'); if(ic) ic.innerHTML = out?OUT_ICON:IN_ICON;
var tt=$('ci-done-t'); if(tt) tt.textContent = out?'Fahrzeug ausgecheckt':'Check-in erfasst';
ov.classList.remove('d-none');
var n=3, cd=$('ci-cd'), done=false; cd.textContent=n;
var t=setInterval(function(){ n--; cd.textContent=n; if(n<=0) finish(); },1000);
function finish(){ if(done) return; done=true; clearInterval(t); if(CFG.embed){ parentMsg({close:1}); } else { location.href=CFG.back; } }
function stay(){ if(done) return; done=true; clearInterval(t); ov.classList.add('d-none'); }
var cBtn=$('ci-cancel'); if(cBtn) cBtn.onclick=function(e){ e.stopPropagation(); stay(); }; // Abbrechen -> hier bleiben
ov.onclick=function(e){ if(e.target.closest('#ci-cancel')) return; finish(); }; // woanders -> sofort weiter
}
var actBtn=$('ci-action-btn');
if(actBtn) actBtn.addEventListener('click', function(){
var act=actBtn.dataset.act;
if(act==='pay'){ openPay(); return; }
if(act==='uncheckin'){
actBtn.disabled=true; setStatus('Check-in wird zurückgenommen …');
post({action:'uncheckin'}, function(res){
if(!res||!res.ok){ actBtn.disabled=false; setStatus((res&&res.error)||'Fehler.','err'); return; }
CFG.arrived=false; CFG.ciTime=''; renderState(); renderTimeRow(); parentMsg({state:ciState()}); setStatus('Check-in zurückgenommen.','ok');
startCountdown('out');
});
return;
}
if(act==='checkin'){
actBtn.disabled=true; setStatus('Check-in …');
post({action:'checkin'}, function(res){
if(!res||!res.ok){ actBtn.disabled=false; setStatus((res&&res.error)||'Fehler.','err'); return; }
CFG.arrived=true; CFG.ciTime=res.time||CFG.ciTime; renderState(); renderTimeRow(); parentMsg({state:'i'}); startCountdown('in');
});
}
});
// Kennzeichen ändern – direkt im Kennzeichen-Feld (Klick rein aktiviert, Speichern-Button rechts)
var plate=$('ci-plate'), plSave=$('ci-plate-save'), plOrig = plate ? plate.textContent : '';
if(plate && plSave && !plate.getAttribute('data-ro')){
function startEdit(){
if(plate.isContentEditable) return;
plOrig = plate.textContent;
plate.contentEditable='true'; plate.classList.add('editing'); plSave.classList.remove('d-none');
plate.focus();
try{ var rng=document.createRange(); rng.selectNodeContents(plate); rng.collapse(false); var sel=getSelection(); sel.removeAllRanges(); sel.addRange(rng); }catch(e){}
}
function stopEdit(){ plate.contentEditable='false'; plate.classList.remove('editing'); plSave.classList.add('d-none'); }
plate.addEventListener('click', startEdit);
plate.addEventListener('keydown', function(ev){
if(ev.key==='Enter'){ ev.preventDefault(); plSave.click(); }
else if(ev.key==='Escape'){ plate.textContent=plOrig; stopEdit(); }
});
// Klick außerhalb: ohne Änderung Bearbeiten beenden; mit ungespeicherter Änderung nachfragen.
plate.addEventListener('blur', function(){
if(!plate.isContentEditable) return;
var cur=(plate.textContent||'').replace(/\s+/g,' ').trim();
var org=(plOrig||'').replace(/\s+/g,' ').trim();
if(cur===org || cur===''){ plate.textContent=plOrig; stopEdit(); return; }
if(confirm('Kennzeichen „'+cur+'" speichern?\n\nOK = Speichern · Abbrechen = Verwerfen')){ plSave.click(); }
else { plate.textContent=plOrig; stopEdit(); }
});
plSave.addEventListener('mousedown', function(ev){ ev.preventDefault(); }); // Fokus im Feld halten (kein blur beim Speichern)
plSave.addEventListener('click', function(ev){
ev.stopPropagation();
var v=(plate.textContent||'').replace(/\s+/g,' ').trim();
if(!v){ setStatus('Bitte ein Kennzeichen eingeben.','err'); return; }
setStatus('Kennzeichen wird gespeichert …');
post({action:'plate', plate:v}, function(res){
if(!res||!res.ok){ setStatus((res&&res.error)||'Fehler.','err'); plate.textContent=plOrig; return; }
plate.textContent=res.plate; plOrig=res.plate; stopEdit(); parentMsg({rows:1});
setStatus('✓ Kennzeichen aktualisiert','ok');
});
});
}
var backLink=$('ci-back');
if(backLink && CFG.embed) backLink.addEventListener('click', function(e){ e.preventDefault(); parentMsg({close:1}); });
renderState();
renderTimeRow();
})();
/* ============================================================ Fahrzeugfotos */
(function(){
if(!CFG.imgView && !CFG.imgUpload) return;
var $=function(id){return document.getElementById(id);};
var grid=$('ci-ph-grid'), countEl=$('ci-ph-count'), emptyEl=$('ci-ph-empty');
var API=CFG.imgApi, images=[];
function esc(s){return String(s==null?'':s).replace(/[&<>"]/g,function(c){return {'&':'&','<':'<','>':'>','"':'"'}[c];});}
function authParams(fd){ fd.append('b',CFG.b); if(CFG.t) fd.append('t',CFG.t); if(CFG.h) fd.append('h',CFG.h); return fd; }
function listUrl(){ var q='action=list&b='+CFG.b; if(CFG.t)q+='&t='+encodeURIComponent(CFG.t); if(CFG.h)q+='&h='+encodeURIComponent(CFG.h); return API+'?'+q; }
// ---------- Galerie
function loadGallery(){
if(!CFG.imgView){ if(emptyEl) emptyEl.style.display=''; return; }
fetch(listUrl(),{headers:{'X-Requested-With':'XMLHttpRequest'}}).then(function(r){return r.json();}).then(function(res){
if(!res||!res.success){ return; }
images=res.images||[]; renderGrid();
}).catch(function(){});
}
var NOTE_SVG='<svg viewBox="0 0 24 24" fill="none" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>';
function renderGrid(){
if(countEl){ countEl.textContent=images.length; countEl.classList.toggle('zero', images.length===0); }
if(emptyEl) emptyEl.style.display = images.length? 'none':'';
if(!grid) return;
var h='';
for(var i=0;i<images.length;i++){ var im=images[i];
h+='<div class="ph-thumb" data-i="'+i+'"><img src="'+esc(im.thumb_url)+'" loading="lazy" alt="">'+((im.note&&im.note_visible!==false)?'<span class="ph-ndot">'+NOTE_SVG+'</span>':'')+'</div>';
}
grid.innerHTML=h;
}
if(grid) grid.addEventListener('click', function(e){ var t=e.target.closest('.ph-thumb'); if(t) openLb(parseInt(t.dataset.i,10)); });
// ---------- Lightbox
var lb=$('ci-lb'), lbImg=$('ci-lb-img'), lbInfo=$('ci-lb-info'), lbPos=$('ci-lb-pos'),
lbDel=$('ci-lb-del'), lbDl=$('ci-lb-dl'), lbStage=$('ci-lb-stage');
var idx=0, scale=1, tx=0, ty=0;
function applyT(){ lbImg.style.transform='translate('+tx+'px,'+ty+'px) scale('+scale+')'; }
function resetT(){ scale=1; tx=0; ty=0; applyT(); }
function showInfo(im){
var meta=[]; meta.push(im.created_at_formatted); if(im.created_by_name) meta.push('von '+esc(im.created_by_name));
if(CFG.plate) meta.push(esc(CFG.plate)); if(CFG.bookingNo) meta.push(esc(CFG.bookingNo));
if(im.file_size_formatted) meta.push(im.file_size_formatted+(im.width?' · '+im.width+'×'+im.height:''));
var note = (im.note&&im.note_visible!==false)? esc(im.note) : '';
var html='';
if(note) html+='<div class="lb-note">'+note+'</div>'; else html+='<div class="lb-note" style="opacity:.6;font-weight:400;font-style:italic">Keine Notiz</div>';
html+='<div class="lb-meta">'+meta.join(' · ')+'</div>';
if(im.can_edit) html+='<button type="button" class="lb-edit" id="ci-lb-noteedit">Notiz bearbeiten</button>';
lbInfo.innerHTML=html;
var ne=$('ci-lb-noteedit'); if(ne) ne.addEventListener('click', function(){ editNote(im); });
if(lbDel) lbDel.style.display=im.can_delete?'':'none';
if(lbDl) lbDl.style.display=(im.can_download&&im.original_url)?'':'none';
}
function openLb(i){ if(!lb||i<0||i>=images.length) return; idx=i; var im=images[i];
lbImg.src=im.image_url; resetT(); lbPos.textContent=(i+1)+' / '+images.length; showInfo(im);
lb.classList.remove('d-none'); document.documentElement.style.overflow='hidden';
}
function closeLb(){ if(lb){ lb.classList.add('d-none'); lbImg.src=''; document.documentElement.style.overflow=''; } }
function nav(d){ var n=idx+d; if(n<0||n>=images.length) return; openLb(n); }
if($('ci-lb-x')) $('ci-lb-x').addEventListener('click', closeLb);
if($('ci-lb-prev')) $('ci-lb-prev').addEventListener('click', function(){ nav(-1); });
if($('ci-lb-next')) $('ci-lb-next').addEventListener('click', function(){ nav(1); });
if($('ci-lb-zoom')) $('ci-lb-zoom').addEventListener('click', function(){ scale = scale>1?1:2.5; if(scale===1){tx=0;ty=0;} applyT(); });
if(lbDl) lbDl.addEventListener('click', function(){ var im=images[idx]; if(im&&im.original_url) window.open(im.original_url,'_blank'); });
if(lbDel) lbDel.addEventListener('click', function(){ delImage(images[idx]); });
// Touch: Pinch-Zoom + Pan + Wisch-Navigation (wenn nicht gezoomt) + Doppeltipp.
var pts={}, startDist=0, startScale=1, startTx=0, startTy=0, panX=0, panY=0, lastTap=0;
function dist(a,b){ var dx=a.x-b.x, dy=a.y-b.y; return Math.sqrt(dx*dx+dy*dy); }
if(lbStage){
lbStage.addEventListener('pointerdown', function(e){ pts[e.pointerId]={x:e.clientX,y:e.clientY}; var k=Object.keys(pts);
if(k.length===1){ panX=e.clientX; panY=e.clientY; startTx=tx; startTy=ty;
var now=Date.now(); if(now-lastTap<300){ scale=scale>1?1:2.5; if(scale===1){tx=0;ty=0;} applyT(); } lastTap=now;
} else if(k.length===2){ startDist=dist(pts[k[0]],pts[k[1]]); startScale=scale; }
});
lbStage.addEventListener('pointermove', function(e){ if(!pts[e.pointerId]) return; pts[e.pointerId]={x:e.clientX,y:e.clientY}; var k=Object.keys(pts);
if(k.length===2){ var d=dist(pts[k[0]],pts[k[1]]); if(startDist>0){ scale=Math.min(4,Math.max(1,startScale*d/startDist)); if(scale===1){tx=0;ty=0;} applyT(); } }
else if(k.length===1 && scale>1){ tx=startTx+(e.clientX-panX); ty=startTy+(e.clientY-panY); applyT(); }
});
function up(e){ var wasPan=(Object.keys(pts).length===1 && scale<=1);
var sx=pts[e.pointerId]?pts[e.pointerId].x:panX; delete pts[e.pointerId];
if(wasPan){ var dx=sx-panX; if(Math.abs(dx)>50) nav(dx<0?1:-1); }
if(Object.keys(pts).length===0 && scale<=1){ tx=0;ty=0;applyT(); }
}
lbStage.addEventListener('pointerup', up); lbStage.addEventListener('pointercancel', up);
}
function editNote(im){ if(!im.can_edit) return; var v=prompt('Notiz zum Bild:', im.note||''); if(v===null) return;
var fd=authParams(new FormData()); fd.append('id',im.id); fd.append('note',v);
fetch(API+'?action=note',{method:'POST',body:fd}).then(function(r){return r.json();}).then(function(res){
if(res&&res.success){ im.note=res.note; showInfo(im); renderGrid(); } else alert((res&&res.error)||'Fehler.');
}).catch(function(){ alert('Fehler.'); });
}
function delImage(im){ if(!im||!im.can_delete) return; if(!confirm('Dieses Foto löschen?')) return;
var fd=authParams(new FormData()); fd.append('id',im.id);
fetch(API+'?action=delete',{method:'POST',body:fd}).then(function(r){return r.json();}).then(function(res){
if(res&&res.success){ closeLb(); loadGallery(); } else alert((res&&res.error)||'Fehler.');
}).catch(function(){ alert('Fehler.'); });
}
// ---------- Upload
if(CFG.imgUpload){
var addBtn=$('ci-ph-add'), upModal=$('ci-up-modal'), tiles=$('ci-up-tiles'),
goBtn=$('ci-up-go'), upErr=$('ci-up-err'), cam=$('ci-up-cam'), gal=$('ci-up-gal');
var queue=[]; // {file, url, note, el, bar, st, status}
function openUp(){ queue=[]; tiles.innerHTML=''; goBtn.disabled=true; upErr.classList.add('d-none'); upModal.classList.remove('d-none'); }
function closeUp(){ upModal.classList.add('d-none'); queue.forEach(function(q){ if(q.url) URL.revokeObjectURL(q.url); }); queue=[]; tiles.innerHTML=''; }
if(addBtn) addBtn.addEventListener('click', openUp);
if($('ci-up-close')) $('ci-up-close').addEventListener('click', closeUp);
if(upModal) upModal.addEventListener('click', function(e){ if(e.target===upModal) closeUp(); });
function addFiles(fl){
var MAX=10;
for(var i=0;i<fl.length;i++){ if(queue.length>=MAX){ upErr.textContent='Maximal '+MAX+' Bilder auf einmal.'; upErr.classList.remove('d-none'); break; }
var f=fl[i]; if(!/^image\//.test(f.type)) continue;
addTile(f);
}
goBtn.disabled = queue.length===0;
}
function addTile(f){
var url=URL.createObjectURL(f);
var el=document.createElement('div'); el.className='ph-tile';
el.innerHTML='<div class="ph-tibox"><img src="'+url+'" alt=""><button type="button" class="ph-rm">×</button><div class="ph-st d-none"></div><div class="ph-bar"></div></div>'+
(CFG.imgNote?'<input type="text" class="ph-tnote" maxlength="500" placeholder="Notiz (optional)">':'');
tiles.appendChild(el);
var item={file:f,url:url,note:'',el:el,bar:el.querySelector('.ph-bar'),st:el.querySelector('.ph-st'),status:'wait'};
var noteInp=el.querySelector('.ph-tnote'); if(noteInp) noteInp.addEventListener('input',function(){ item.note=this.value; });
el.querySelector('.ph-rm').addEventListener('click',function(){ if(item.status==='up') return; var ix=queue.indexOf(item); if(ix>=0)queue.splice(ix,1); URL.revokeObjectURL(item.url); el.remove(); goBtn.disabled=queue.length===0; });
queue.push(item);
}
if(cam) cam.addEventListener('change',function(){ addFiles(this.files); this.value=''; });
if(gal) gal.addEventListener('change',function(){ addFiles(this.files); this.value=''; });
function setSt(item,txt,show){ item.st.textContent=txt||''; item.st.classList.toggle('d-none', !show); }
function resizeImage(file, cb){
function finish(bw,bh,draw){ var s=Math.min(1,1920/Math.max(bw,bh)); var nw=Math.max(1,Math.round(bw*s)),nh=Math.max(1,Math.round(bh*s));
var cv=document.createElement('canvas'); cv.width=nw; cv.height=nh; var cx=cv.getContext('2d'); cx.fillStyle='#fff'; cx.fillRect(0,0,nw,nh); draw(cx,nw,nh);
cv.toBlob(function(b){ cb(b); }, 'image/jpeg', 0.82); }
if(window.createImageBitmap){ createImageBitmap(file,{imageOrientation:'from-image'}).then(function(bmp){ finish(bmp.width,bmp.height,function(cx,nw,nh){cx.drawImage(bmp,0,0,nw,nh); if(bmp.close)bmp.close();}); }).catch(fb); }
else fb();
function fb(){ var u=URL.createObjectURL(file), im=new Image(); im.onload=function(){ finish(im.naturalWidth,im.naturalHeight,function(cx,nw,nh){cx.drawImage(im,0,0,nw,nh);}); URL.revokeObjectURL(u); }; im.onerror=function(){ URL.revokeObjectURL(u); cb(null); }; im.src=u; }
}
function uploadItem(item, done){
item.status='up'; setSt(item,'Wird hochgeladen…',true); item.bar.style.width='5%';
resizeImage(item.file, function(blob){
if(!blob){ item.status='err'; item.el.classList.add('err'); setSt(item,'Fehler',true); return done(false); }
var fd=authParams(new FormData()); fd.append('image',blob,'photo.jpg'); if(item.note) fd.append('note',item.note);
var xhr=new XMLHttpRequest(); xhr.open('POST',API+'?action=upload');
xhr.upload.onprogress=function(e){ if(e.lengthComputable){ item.bar.style.width=Math.max(5,Math.round(e.loaded/e.total*95))+'%'; } };
xhr.onload=function(){ var res; try{res=JSON.parse(xhr.responseText);}catch(_){res=null;}
if(res&&res.success){ item.status='done'; item.el.classList.add('done'); item.bar.style.width='100%'; setSt(item,'✓ Fertig',true); done(true); }
else { item.status='err'; item.el.classList.add('err'); setSt(item,(res&&res.error)||'Fehler',true); done(false); } };
xhr.onerror=function(){ item.status='err'; item.el.classList.add('err'); setSt(item,'Netzwerkfehler',true); done(false); };
xhr.send(fd);
});
}
if(goBtn) goBtn.addEventListener('click', function(){
var pend=queue.filter(function(q){return q.status==='wait';}); if(!pend.length) return;
goBtn.disabled=true; upErr.classList.add('d-none');
var i=0, okCount=0;
(function next(){ if(i>=pend.length){ // fertig
loadGallery();
if(okCount===pend.length){ closeUp(); }
else { upErr.textContent='Einige Bilder konnten nicht hochgeladen werden.'; upErr.classList.remove('d-none'); goBtn.disabled=false; goBtn.textContent='Erneut versuchen'; }
return; }
uploadItem(pend[i], function(ok){ if(ok)okCount++; i++; next(); });
})();
});
}
loadGallery();
})();
</script>
</body></html>