// Hotel-level mock data (Hotel Triglav Bled — used by all hotel-side roles) const HOTEL = { name: 'Hotel Triglav Bled', city: 'Bled', rooms: 78, stars: 4, occupancyToday: 82, arrivalsToday: 14, departuresToday: 11, inHouse: 64, }; // Sobe — 78 sob, razdeljenih po nadstropjih in tipih const ROOM_TYPES = [ { code:'STD', name:'Standard', bed:'1×Queen', pax:2, rate:120, count:32 }, { code:'DLX', name:'Deluxe', bed:'1×King', pax:2, rate:160, count:22 }, { code:'JSU', name:'Junior Suite', bed:'1×King + sofa', pax:3, rate:230, count:14 }, { code:'SUI', name:'Suite Triglav', bed:'1×King', pax:4, rate:340, count:8 }, { code:'FAM', name:'Family', bed:'2×Queen', pax:4, rate:210, count:2 }, ]; // Statusi sob const ROOM_STATUS = ['clean','dirty','inspected','out_of_order','occupied','arriving','departing']; // Generiraj 78 sob (4 nadstropja × ~20 sob) const ROOMS = (() => { const out = []; const types = ['STD','STD','STD','DLX','DLX','JSU','SUI','FAM']; let n = 0; for (let f=1; f<=4; f++){ const perFloor = f===4 ? 18 : 20; for (let r=1; r<=perFloor; r++){ const num = `${f}${String(r).padStart(2,'0')}`; const type = (f===4 && r<=4) ? 'SUI' : types[(n*7)%types.length]; const status = ['clean','dirty','occupied','occupied','occupied','clean','inspected','occupied','dirty','clean','occupied','occupied','arriving','departing','clean','out_of_order','occupied','dirty','clean','occupied'][n%20]; const guest = (status==='occupied'||status==='departing') ? ['Ana Novak','Marko Hribar','J. Schmidt','Sara Lah','M. Rossi','P. Müller','Eva Kos','J. Dvořák','S. Kowalski','M. Nowak','I. Tomić','L. Bertoni'][n%12] : null; out.push({ num, floor:f, type, status, guest, nights: guest? (n%5)+1 : 0 }); n++; } } return out; })(); // Rezervacije — 24 prihajajočih + nekaj v hišo const RESERVATIONS = [ { id:'R-25041', guest:'Ana Novak', email:'ana.n@gmail.com', checkin:'28.04.', checkout:'02.05.', nights:4, room:'213', type:'DLX', pax:2, channel:'Booking.com', status:'confirmed', total:640, paid:0, vip:false, note:'Pozno prihod (~22:00)' }, { id:'R-25042', guest:'Marko Hribar', email:'m.hribar@siol.net', checkin:'28.04.', checkout:'30.04.', nights:2, room:'108', type:'STD', pax:1, channel:'Direct', status:'confirmed', total:240, paid:240, vip:false, note:'' }, { id:'R-25043', guest:'James Schmidt', email:'jschmidt@gmail.com', checkin:'28.04.', checkout:'04.05.', nights:6, room:'305', type:'JSU', pax:2, channel:'Booking.com', status:'confirmed', total:1380, paid:1380, vip:true, note:'Repeat guest, želi cvetje' }, { id:'R-25044', guest:'Sara Lah', email:'sara@gmail.com', checkin:'28.04.', checkout:'01.05.', nights:3, room:'412', type:'SUI', pax:2, channel:'Expedia', status:'confirmed', total:1020, paid:255, vip:false, note:'Honeymoon' }, { id:'R-25045', guest:'Marco Rossi', email:'rossi@libero.it', checkin:'28.04.', checkout:'29.04.', nights:1, room:'117', type:'STD', pax:2, channel:'Airbnb', status:'confirmed', total:120, paid:120, vip:false, note:'' }, { id:'R-25046', guest:'Petra Müller', email:'p.mueller@gmx.de', checkin:'28.04.', checkout:'05.05.', nights:7, room:'201', type:'STD', pax:2, channel:'Direct', status:'confirmed', total:840, paid:0, vip:false, note:'' }, { id:'R-25047', guest:'Eva Kos', email:'eva.kos@telemach.net', checkin:'28.04.', checkout:'30.04.', nights:2, room:'304', type:'JSU', pax:3, channel:'Direct', status:'arriving', total:460, paid:460, vip:false, note:'Otrok 6 let, prosi za posteljico' }, { id:'R-25048', guest:'Jan Dvořák', email:'jdvorak@seznam.cz', checkin:'28.04.', checkout:'01.05.', nights:3, room:'105', type:'STD', pax:2, channel:'Booking.com', status:'arriving', total:360, paid:360, vip:false, note:'' }, { id:'R-25049', guest:'Stanisław Kowalski',email:'kowalski@onet.pl', checkin:'29.04.', checkout:'02.05.', nights:3, room:'—', type:'DLX', pax:2, channel:'Booking.com', status:'confirmed', total:480, paid:480, vip:false, note:'' }, { id:'R-25050', guest:'Magdalena Nowak', email:'mnowak@wp.pl', checkin:'29.04.', checkout:'30.04.', nights:1, room:'—', type:'STD', pax:1, channel:'Direct', status:'confirmed', total:120, paid:0, vip:false, note:'' }, { id:'R-25051', guest:'Ivan Tomić', email:'tomic@gmail.com', checkin:'29.04.', checkout:'04.05.', nights:5, room:'—', type:'JSU', pax:4, channel:'Expedia', status:'confirmed', total:1150, paid:230, vip:false, note:'' }, { id:'R-25052', guest:'Luca Bertoni', email:'lbertoni@tin.it', checkin:'30.04.', checkout:'03.05.', nights:3, room:'—', type:'DLX', pax:2, channel:'Booking.com', status:'confirmed', total:480, paid:480, vip:false, note:'' }, { id:'R-25053', guest:'Hans Schneider', email:'hans@web.de', checkin:'30.04.', checkout:'05.05.', nights:5, room:'—', type:'SUI', pax:2, channel:'Direct', status:'confirmed', total:1700, paid:425, vip:true, note:'Anniversary, prosil za šampanjec' }, { id:'R-25054', guest:'Catherine Walsh', email:'cwalsh@yahoo.com', checkin:'01.05.', checkout:'04.05.', nights:3, room:'—', type:'DLX', pax:2, channel:'Booking.com', status:'confirmed', total:480, paid:480, vip:false, note:'' }, ]; // 14-dnevni horizont za koledar — { date, occupied, total, arrivals, departures } const CALENDAR_14D = (() => { const arr = []; const seedOcc = [82,78,84,89,92,86,71,68,74,80,85,88,76,70]; const seedArr = [14,8,12,18,22,16,5,7,11,14,17,19,9,6]; const seedDep = [11,12,7,15,18,21,9,4,8,13,15,18,11,8]; for (let i=0; i<14; i++){ const d = new Date(2026,3,28+i); arr.push({ date:d, day:d.getDate(), month:d.getMonth()+1, weekday:['Ne','Po','To','Sr','Če','Pe','So'][d.getDay()], occupied: Math.round(78*seedOcc[i]/100), total:78, occupancy:seedOcc[i], arrivals:seedArr[i], departures:seedDep[i], revenue: Math.round(78*seedOcc[i]/100 * 142), }); } return arr; })(); // Channel manager statuses const CHANNELS = [ { name:'Booking.com', status:'syncing', sync:'pred 3 min', live:42, share:38, revenue:24890 }, { name:'Expedia', status:'ok', sync:'pred 1 min', live:18, share:16, revenue:11420 }, { name:'Airbnb', status:'ok', sync:'pred 2 min', live:9, share:8, revenue:5680 }, { name:'Direct (web)', status:'ok', sync:'live', live:23, share:21, revenue:14260 }, { name:'Walk-in', status:'ok', sync:'—', live:8, share:7, revenue:4860 }, { name:'Hotelbeds', status:'ok', sync:'pred 5 min', live:6, share:5, revenue:3920 }, { name:'Google Hotel', status:'down', sync:'pred 2 ur', live:0, share:5, revenue:0 }, ]; // Cleaning / housekeeping tasks const HK_TASKS = [ { room:'108', floor:1, type:'STD', task:'departure', due:'12:00', priority:'high', est:'25 min', assigned:'Anita K.', status:'pending', notes:'' }, { room:'117', floor:1, type:'STD', task:'departure', due:'12:00', priority:'high', est:'25 min', assigned:'Anita K.', status:'in_progress', notes:'' }, { room:'201', floor:2, type:'STD', task:'stayover', due:'14:00', priority:'med', est:'15 min', assigned:'Marija P.', status:'pending', notes:'Ne motiti do 14h' }, { room:'213', floor:2, type:'DLX', task:'arrival', due:'15:00', priority:'urgent', est:'30 min', assigned:'Marija P.', status:'done', notes:'VIP — cvetje' }, { room:'304', floor:3, type:'JSU', task:'arrival', due:'15:00', priority:'urgent', est:'40 min', assigned:'Branka L.', status:'pending', notes:'Posteljica za otroka' }, { room:'305', floor:3, type:'JSU', task:'stayover', due:'13:00', priority:'med', est:'20 min', assigned:'Branka L.', status:'done', notes:'' }, { room:'412', floor:4, type:'SUI', task:'arrival', due:'15:00', priority:'urgent', est:'45 min', assigned:'Marija P.', status:'in_progress', notes:'Honeymoon — šampanjec' }, { room:'105', floor:1, type:'STD', task:'arrival', due:'15:00', priority:'high', est:'25 min', assigned:'Anita K.', status:'pending', notes:'' }, { room:'418', floor:4, type:'SUI', task:'maintenance', due:'asap', priority:'urgent', est:'—', assigned:'Tomaž V.', status:'in_progress', notes:'TV ne dela' }, { room:'207', floor:2, type:'DLX', task:'inspection', due:'16:00', priority:'low', est:'10 min', assigned:'Branka L.', status:'pending', notes:'' }, ]; // Devices (kiosks, locks, printers, POS, network) const DEVICES = [ { id:'KIOSK-01', name:'Kiosk · Lobby', type:'kiosk', location:'Pritličje, lobby', status:'online', lastSeen:'sedaj', ver:'4.2.1', battery:null, ip:'10.0.12.41' }, { id:'KIOSK-02', name:'Kiosk · Konferenčna', type:'kiosk', location:'1. nadstropje, foyer', status:'online', lastSeen:'pred 1 min', ver:'4.2.1', battery:null, ip:'10.0.12.42' }, { id:'POS-01', name:'Recepcija POS', type:'pos', location:'Pritličje, recepcija', status:'online', lastSeen:'sedaj', ver:'4.2.1', battery:null, ip:'10.0.12.21' }, { id:'POS-02', name:'Bar POS', type:'pos', location:'Pritličje, bar', status:'online', lastSeen:'pred 4 min', ver:'4.2.1', battery:null, ip:'10.0.12.22' }, { id:'POS-03', name:'Restavracija POS', type:'pos', location:'Pritličje, restavracija', status:'offline', lastSeen:'pred 14 min', ver:'4.2.0', battery:null, ip:'10.0.12.23' }, { id:'PRT-01', name:'Tiskalnik računov · recepcija', type:'printer', location:'Recepcija', status:'online', lastSeen:'sedaj', ver:'—', battery:null, ip:'10.0.12.51' }, { id:'PRT-02', name:'Tiskalnik ključev · recepcija', type:'printer', location:'Recepcija', status:'warning', lastSeen:'sedaj', ver:'—', battery:null, ip:'10.0.12.52', warn:'Malo papirja' }, { id:'LCK-313', name:'Ključavnica 313', type:'lock', location:'3. nadstr., soba 313', status:'online', lastSeen:'pred 18 min', ver:'2.1.4', battery:67, ip:'mesh' }, { id:'LCK-418', name:'Ključavnica 418', type:'lock', location:'4. nadstr., soba 418', status:'warning', lastSeen:'pred 2 ur', ver:'2.1.4', battery:14, ip:'mesh', warn:'Šibka baterija' }, { id:'TAB-HK1', name:'Tablet · sobarica 1', type:'tablet', location:'Housekeeping voziček 1', status:'online', lastSeen:'pred 2 min', ver:'4.2.1', battery:78, ip:'wifi' }, { id:'TAB-HK2', name:'Tablet · sobarica 2', type:'tablet', location:'Housekeeping voziček 2', status:'online', lastSeen:'pred 6 min', ver:'4.2.1', battery:42, ip:'wifi' }, { id:'AP-01', name:'WiFi AP · Pritličje', type:'network', location:'Pritličje', status:'online', lastSeen:'sedaj', ver:'—', battery:null, ip:'10.0.10.1' }, { id:'AP-02', name:'WiFi AP · 2. nadstropje', type:'network', location:'2. nadstropje', status:'online', lastSeen:'sedaj', ver:'—', battery:null, ip:'10.0.10.2' }, { id:'AP-03', name:'WiFi AP · 4. nadstropje', type:'network', location:'4. nadstropje', status:'warning', lastSeen:'pred 1 min', ver:'—', battery:null, ip:'10.0.10.4', warn:'Visoka latenca 220 ms' }, ]; // Today's shift / staff on duty const STAFF_ON_DUTY = [ { name:'Maja Kranjc', role:'Recepcija', shift:'07–15', status:'na delu', tasks:8 }, { name:'Janez Logar', role:'Recepcija', shift:'15–23', status:'prihaja', tasks:0 }, { name:'Anita Koren', role:'Housekeeping', shift:'08–16', status:'na delu', tasks:5 }, { name:'Marija Petek', role:'Housekeeping', shift:'08–16', status:'na delu', tasks:4 }, { name:'Branka Lah', role:'Housekeeping', shift:'08–16', status:'na delu', tasks:3 }, { name:'Tomaž Vidic', role:'Vzdrževanje', shift:'09–17', status:'na delu', tasks:2 }, { name:'Klemen Bizjak', role:'F&B', shift:'12–22', status:'prihaja', tasks:0 }, ]; // Guest messages / requests const GUEST_REQUESTS = [ { id:'GR-1', room:'305', guest:'James Schmidt', request:'Dodatne brisače', time:'pred 4 min', priority:'low', status:'open' }, { id:'GR-2', room:'412', guest:'Sara Lah', request:'Steklenica šampanjca v sobo', time:'pred 18 min', priority:'med', status:'in_progress' }, { id:'GR-3', room:'213', guest:'Ana Novak', request:'Pozni check-out (do 14h)', time:'pred 1 ur', priority:'low', status:'approved' }, { id:'GR-4', room:'418', guest:'Hans Schneider',request:'TV v sobi ne dela', time:'pred 25 min', priority:'high', status:'in_progress' }, { id:'GR-5', room:'108', guest:'Marko Hribar', request:'Taksi ob 6:30 zjutraj', time:'pred 2 ur', priority:'med', status:'approved' }, ]; // 30-day occupancy history const OCCUPANCY_30D = [62,58,64,71,68,72,75,79,82,84,80,76,72,68,71,75,78,82,85,88,84,80,76,73,77,81,84,86,82,82]; const ADR_30D = [128,131,129,135,138,142,145,148,144,141,138,140,142,145,148,150,148,145,142,144,146,149,152,150,148,146,148,150,142,142]; Object.assign(window, { HOTEL, ROOM_TYPES, ROOM_STATUS, ROOMS, RESERVATIONS, CALENDAR_14D, CHANNELS, HK_TASKS, DEVICES, STAFF_ON_DUTY, GUEST_REQUESTS, OCCUPANCY_30D, ADR_30D, });