Add visual booking calendar (weekly Teams-style view)

- New weekly calendar at /bookings/calendar with time blocks per booking
- Color-coded by worker, overlapping bookings shown side-by-side
- Click booking to see details, edit or delete
- Worker filter dropdown, week navigation (prev/next/today)
- AJAX week loading for smooth navigation
- Link between list view and calendar view

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Ubuntu
2026-05-07 14:03:41 +00:00
co-authored by Claude Opus 4.6
parent a100acddec
commit 6abb90329d
6 changed files with 584 additions and 0 deletions
+2
View File
@@ -95,6 +95,8 @@ $route['workers/store-calendar-override'] = 'admin/store_calendar_override';
$route['workers/delete-calendar-override'] = 'admin/delete_calendar_override';
$route['bookings'] = 'admin/bookings';
$route['bookings/calendar'] = 'admin/booking_calendar';
$route['bookings/calendar-data'] = 'admin/booking_calendar_data';
$route['bookings/add-booking'] = 'admin/add_booking';
$route['bookings/update-booking/(:any)'] = 'admin/update_booking/$1';
$route['bookings/booking-process'] = 'admin/booking_process';
+90
View File
@@ -695,6 +695,96 @@ class Admin extends CI_Controller {
}
}
public function booking_calendar(){
$this->load->helper('url');
$this->load->model('User_model');
$this->load->model('Service_model');
$this->load->model('Module_model');
if(isset($_SESSION['username'])){
$data['currentUser'] = $this->User_model->getUserByUsername($_SESSION['username']);
$data['pageTitle'] = 'Foglalási naptár';
$data['message'] = '';
$data['message_class'] = '';
if($this->User_model->is_user_admin($_SESSION['username'])){
$data['activeModules'] = $this->Module_model->getAllModule();
} else {
$data['activeModules'] = $this->Module_model->getUserModules($data['currentUser']->user_id);
}
// Compute week bounds
$weekParam = isset($_GET['week']) ? $_GET['week'] : date('Y-m-d');
$monday = new DateTime($weekParam);
$dow = (int)$monday->format('N'); // 1=Mon..7=Sun
if ($dow > 1) $monday->modify('-'.($dow - 1).' days');
$sunday = clone $monday;
$sunday->modify('+6 days');
$data['weekStart'] = $monday->format('Y-m-d');
$data['weekEnd'] = $sunday->format('Y-m-d');
$data['workers'] = $this->Service_model->getActiveWorkers();
$workerId = isset($_GET['worker_id']) ? $_GET['worker_id'] : null;
$data['bookings'] = $this->Service_model->getBookingsByDateRange($data['weekStart'], $data['weekEnd'], $workerId);
$this->load->view('admin/booking-calendar', $data);
} else {
header("Location:".SITEURL."login");
}
}
public function booking_calendar_data(){
$this->load->helper('url');
$this->load->model('User_model');
$this->load->model('Service_model');
if(!isset($_SESSION['username'])){
header('Content-Type: application/json');
echo json_encode(array('error' => 'unauthorized'));
return;
}
$weekParam = isset($_GET['week']) ? $_GET['week'] : date('Y-m-d');
$monday = new DateTime($weekParam);
$dow = (int)$monday->format('N');
if ($dow > 1) $monday->modify('-'.($dow - 1).' days');
$sunday = clone $monday;
$sunday->modify('+6 days');
$workerId = isset($_GET['worker_id']) && $_GET['worker_id'] !== '' ? $_GET['worker_id'] : null;
$bookings = $this->Service_model->getBookingsByDateRange($monday->format('Y-m-d'), $sunday->format('Y-m-d'), $workerId);
$result = array();
foreach ($bookings as $b) {
$services = array();
if (is_array($b->services)) {
foreach ($b->services as $s) {
$services[] = array(
'service_name' => $s->service_name,
'service_price' => $s->service_price,
'service_time' => $s->service_time
);
}
}
$result[] = array(
'booking_id' => $b->booking_id,
'guest_name' => $b->guest_name,
'guest_email' => $b->guest_email,
'guest_phone' => $b->guest_phone,
'worker_id' => $b->worker_id,
'worker_name' => $b->worker_name,
'booking_date' => $b->booking_date,
'booking_start_time' => $b->booking_start_time,
'booking_finish_time' => $b->booking_finish_time,
'services' => $services,
'service_names_joined' => $b->service_names_joined
);
}
header('Content-Type: application/json');
echo json_encode($result);
}
public function add_booking(){
$this->load->helper('url');
$this->load->model('User_model');
+50
View File
@@ -795,6 +795,56 @@ class Service_model extends CI_Model {
return $query->num_rows() > 0;
}
public function getBookingsByDateRange($startDate, $endDate, $workerId = null) {
$this->load->database();
$sql = 'SELECT b.*, w.worker_name, w.worker_profile_img
FROM bookings b
JOIN workers w ON b.worker_id = w.worker_id
WHERE b.booking_date BETWEEN ? AND ?';
$params = array($startDate, $endDate);
if ($workerId) {
$sql .= ' AND b.worker_id = ?';
$params[] = $workerId;
}
$sql .= ' ORDER BY b.booking_date, b.booking_start_time';
$query = $this->db->query($sql, $params);
if ($query->num_rows() == 0) return array();
$resultsArray = array();
foreach ($query->result() as $row) {
$resultTmp = (array)$row;
$resultTmp['services'] = array();
$resultTmp['service_names_joined'] = '';
if (!empty($resultTmp['service_ids'])) {
$servicesArr = unserialize($resultTmp['service_ids']);
if (is_array($servicesArr)) {
$names = array();
foreach ($servicesArr as $sid) {
$svc = $this->getServiceById($sid);
if (is_object($svc)) {
$resultTmp['services'][] = (object)array(
'service_name' => $svc->service_name_hu,
'service_price' => $svc->service_price,
'service_time' => $svc->service_time
);
$names[] = $svc->service_name_hu;
}
}
$resultTmp['service_names_joined'] = implode(', ', $names);
}
}
$resultsArray[] = (object)$resultTmp;
}
return $resultsArray;
}
@@ -0,0 +1,5 @@
<?php
include(getcwd().'/application/views/includes/skeleton-top.php');
include(getcwd().'/application/views/admin/includes/booking-calendar-form.php');
include(getcwd().'/application/views/includes/skeleton-bottom.php');
?>
@@ -0,0 +1,436 @@
<?php
$colorPalette = ['#3498db','#e74c3c','#2ecc71','#f39c12','#9b59b6','#1abc9c','#e67e22','#e91e63','#00bcd4','#8bc34a'];
$workerColorMap = array();
$i = 0;
foreach ($workers as $w) {
$workerColorMap[(string)$w->worker_id] = $colorPalette[$i % count($colorPalette)];
$i++;
}
// Build initial bookings JSON
$bookingsJson = array();
foreach ($bookings as $b) {
$services = array();
if (is_array($b->services)) {
foreach ($b->services as $s) {
$services[] = array(
'service_name' => $s->service_name,
'service_price' => $s->service_price,
'service_time' => $s->service_time
);
}
}
$bookingsJson[] = array(
'booking_id' => $b->booking_id,
'guest_name' => $b->guest_name,
'guest_email' => $b->guest_email,
'guest_phone' => $b->guest_phone,
'worker_id' => $b->worker_id,
'worker_name' => $b->worker_name,
'booking_date' => $b->booking_date,
'booking_start_time' => $b->booking_start_time,
'booking_finish_time' => $b->booking_finish_time,
'services' => $services,
'service_names_joined' => $b->service_names_joined
);
}
?>
<style>
.bcal-wrap { color: #fff; max-width: 1200px; margin: 0 auto; padding: 10px; }
.bcal-header { display: flex; align-items: center; justify-content: space-between; margin: 10px 0; }
.bcal-header a { color: #ccc; text-decoration: none; font-size: 14px; padding: 4px 10px; border: 1px solid #555; border-radius: 3px; cursor: pointer; }
.bcal-header a:hover { background: #333; }
.bcal-title { font-size: 18px; font-weight: bold; }
.bcal-toolbar { display: flex; align-items: center; gap: 12px; margin: 14px 0 6px; flex-wrap: wrap; }
.bcal-toolbar select { background: #2a2a2a; color: #fff; border: 1px solid #555; padding: 5px 8px; border-radius: 3px; font-size: 13px; }
.bcal-toolbar select option { background: #2a2a2a; color: #fff; }
.bcal-toolbar a { color: #ccc; text-decoration: none; font-size: 13px; padding: 4px 10px; border: 1px solid #555; border-radius: 3px; }
.bcal-toolbar a:hover, .bcal-toolbar a.active { background: #444; color: #fff; }
.bcal-legend { display: flex; flex-wrap: wrap; gap: 10px; margin: 8px 0; font-size: 12px; }
.bcal-legend-item { display: flex; align-items: center; gap: 5px; }
.bcal-legend-dot { width: 12px; height: 12px; border-radius: 2px; display: inline-block; }
/* Grid */
.bcal-grid { display: grid; grid-template-columns: 55px repeat(7, 1fr); border: 1px solid #444; border-radius: 4px; overflow: hidden; }
.bcal-day-header { background: #222; text-align: center; padding: 8px 2px; font-size: 12px; font-weight: bold; border-left: 1px solid #444; border-bottom: 1px solid #444; }
.bcal-day-header.today { background: #333; color: #5cb85c; }
.bcal-time-header { background: #222; border-bottom: 1px solid #444; padding: 8px 2px; font-size: 12px; text-align: center; }
.bcal-time-col { background: #1a1a1a; }
.bcal-time-label { height: 60px; padding: 0 4px; font-size: 11px; color: #888; text-align: right; border-bottom: 1px solid #2a2a2a; display: flex; align-items: flex-start; justify-content: flex-end; padding-top: 2px; }
.bcal-day-col { position: relative; border-left: 1px solid #333; min-height: 0; }
.bcal-hour-line { position: absolute; left: 0; right: 0; border-top: 1px solid #333; pointer-events: none; z-index: 0; }
.bcal-half-line { position: absolute; left: 0; right: 0; border-top: 1px dashed #252525; pointer-events: none; z-index: 0; }
/* Booking blocks */
.bcal-booking { position: absolute; left: 1px; right: 1px; border-radius: 3px; padding: 2px 4px; font-size: 10px; line-height: 1.3; overflow: hidden; cursor: pointer; z-index: 2; color: #fff; box-sizing: border-box; border: 1px solid rgba(255,255,255,0.15); transition: filter 0.15s; }
.bcal-booking:hover { filter: brightness(1.2); z-index: 3; }
.bcal-booking .bcal-b-name { font-weight: bold; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.bcal-booking .bcal-b-svc { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; opacity: 0.85; }
.bcal-booking .bcal-b-worker { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; opacity: 0.7; font-size: 9px; }
.bcal-booking .bcal-b-time { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; opacity: 0.7; font-size: 9px; }
/* Modal */
#bcalModal { display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.65); z-index: 9999; }
#bcalModalBox { background: #1e1e1e; border: 1px solid #555; border-radius: 6px; max-width: 440px; margin: 80px auto; padding: 24px; color: #fff; position: relative; }
#bcalModalBox h3 { margin: 0 0 14px; font-size: 17px; }
.bcal-detail-row { margin: 6px 0; font-size: 13px; }
.bcal-detail-row label { color: #999; display: inline-block; width: 100px; }
.bcal-detail-row span { color: #fff; }
.bcal-modal-btns { display: flex; gap: 10px; margin-top: 18px; }
.bcal-modal-btns a, .bcal-modal-btns button { padding: 8px 18px; border-radius: 3px; cursor: pointer; font-size: 14px; text-decoration: none; border: none; color: #fff; text-align: center; }
.bcal-btn-edit { background: #5cb85c; }
.bcal-btn-delete { background: #d9534f; }
.bcal-btn-close { background: #555; color: #fff !important; }
/* Now indicator */
.bcal-now-line { position: absolute; left: 0; right: 0; border-top: 2px solid #d9534f; z-index: 4; pointer-events: none; }
.bcal-now-dot { position: absolute; left: -4px; top: -4px; width: 8px; height: 8px; background: #d9534f; border-radius: 50%; }
</style>
<div class="bcal-wrap">
<div class="pageTitle"><?php echo htmlspecialchars($pageTitle, ENT_QUOTES, 'UTF-8'); ?></div>
<div class="bcal-toolbar">
<label style="color:#ccc;font-size:13px;">Dolgozó:</label>
<select id="bcal-worker-filter">
<option value="">Mindenki</option>
<?php foreach ($workers as $w): ?>
<option value="<?php echo $w->worker_id; ?>"><?php echo htmlspecialchars($w->worker_name, ENT_QUOTES, 'UTF-8'); ?></option>
<?php endforeach; ?>
</select>
<a href="<?php echo SITEURL; ?>bookings">Listanézet</a>
<a href="<?php echo SITEURL; ?>bookings/calendar" class="active">Naptárnézet</a>
</div>
<div class="bcal-header">
<a id="bcal-prev">&#8592; Előző hét</a>
<a id="bcal-today">Ma</a>
<span class="bcal-title" id="bcal-week-label"></span>
<a id="bcal-next">Következő hét &#8594;</a>
</div>
<div class="bcal-legend" id="bcal-legend"></div>
<div class="bcal-grid" id="bcal-grid"></div>
</div>
<!-- Detail modal -->
<div id="bcalModal" onclick="if(event.target===this)closeBcalModal()">
<div id="bcalModalBox">
<h3 id="bcalModalTitle">Foglalás részletei</h3>
<div id="bcalModalBody"></div>
<div class="bcal-modal-btns">
<a id="bcalEditBtn" class="bcal-btn-edit" href="#">Szerkesztés</a>
<a id="bcalDeleteBtn" class="bcal-btn-delete" href="#">Törlés</a>
<a class="bcal-btn-close" onclick="closeBcalModal()" style="cursor:pointer;">Bezárás</a>
</div>
</div>
</div>
<script>
(function(){
var SITEURL = '<?php echo SITEURL; ?>';
var workerColors = <?php echo json_encode($workerColorMap); ?>;
var workersArr = <?php echo json_encode(array_map(function($w){ return array('worker_id'=>$w->worker_id,'worker_name'=>$w->worker_name); }, $workers)); ?>;
var currentMonday = '<?php echo $weekStart; ?>';
var allBookings = <?php echo json_encode($bookingsJson); ?>;
var DAY_START = 8; // 08:00
var DAY_END = 19; // 19:00
var PX_PER_HOUR = 60;
var TOTAL_HOURS = DAY_END - DAY_START;
var dayNames = ['Hétfő','Kedd','Szerda','Csütörtök','Péntek','Szombat','Vasárnap'];
function dateAdd(dateStr, days) {
var parts = dateStr.split('-');
var d = new Date(parseInt(parts[0]), parseInt(parts[1]) - 1, parseInt(parts[2]));
d.setDate(d.getDate() + days);
var y = d.getFullYear();
var m = String(d.getMonth() + 1).padStart(2, '0');
var dd = String(d.getDate()).padStart(2, '0');
return y + '-' + m + '-' + dd;
}
function formatDate(dateStr) {
var parts = dateStr.split('-');
return parts[1] + '.' + parts[2] + '.';
}
function formatDateFull(dateStr) {
var parts = dateStr.split('-');
return parts[0] + '. ' + monthNames[parseInt(parts[1])-1] + ' ' + parseInt(parts[2]) + '.';
}
var monthNames = ['január','február','március','április','május','június','július','augusztus','szeptember','október','november','december'];
function getToday() {
var d = new Date();
return d.getFullYear() + '-' + String(d.getMonth()+1).padStart(2,'0') + '-' + String(d.getDate()).padStart(2,'0');
}
function getMonday(dateStr) {
var parts = dateStr.split('-');
var d = new Date(parseInt(parts[0]), parseInt(parts[1]) - 1, parseInt(parts[2]));
var dow = d.getDay(); // 0=Sun
var diff = dow === 0 ? -6 : 1 - dow;
d.setDate(d.getDate() + diff);
var y = d.getFullYear();
var m = String(d.getMonth() + 1).padStart(2, '0');
var dd = String(d.getDate()).padStart(2, '0');
return y + '-' + m + '-' + dd;
}
function timeToMinutes(t) {
var p = t.split(':');
return parseInt(p[0]) * 60 + parseInt(p[1]);
}
function esc(s) {
var d = document.createElement('div');
d.textContent = s;
return d.innerHTML;
}
function renderLegend() {
var html = '';
for (var i = 0; i < workersArr.length; i++) {
var wid = String(workersArr[i].worker_id);
var color = workerColors[wid] || '#666';
html += '<div class="bcal-legend-item"><span class="bcal-legend-dot" style="background:'+color+';"></span> '+esc(workersArr[i].worker_name)+'</div>';
}
document.getElementById('bcal-legend').innerHTML = html;
}
function updateWeekLabel() {
var sundayStr = dateAdd(currentMonday, 6);
var mParts = currentMonday.split('-');
var sParts = sundayStr.split('-');
var label = mParts[0] + '. ' + monthNames[parseInt(mParts[1])-1] + ' ' + parseInt(mParts[2]) + '. ' +
(mParts[0] !== sParts[0] ? sParts[0] + '. ' : '') +
(mParts[1] !== sParts[1] ? monthNames[parseInt(sParts[1])-1] + ' ' : '') +
parseInt(sParts[2]) + '.';
document.getElementById('bcal-week-label').textContent = label;
}
function computeOverlapColumns(dayBookings) {
// Sort by start time
dayBookings.sort(function(a,b) {
return timeToMinutes(a.booking_start_time) - timeToMinutes(b.booking_start_time);
});
var columns = []; // array of arrays; each column has bookings
for (var i = 0; i < dayBookings.length; i++) {
var bk = dayBookings[i];
var bkStart = timeToMinutes(bk.booking_start_time);
var bkEnd = timeToMinutes(bk.booking_finish_time);
var placed = false;
for (var c = 0; c < columns.length; c++) {
var lastInCol = columns[c][columns[c].length - 1];
var lastEnd = timeToMinutes(lastInCol.booking_finish_time);
if (bkStart >= lastEnd) {
columns[c].push(bk);
bk._col = c;
placed = true;
break;
}
}
if (!placed) {
bk._col = columns.length;
columns.push([bk]);
}
}
// Determine max overlapping columns for each booking
for (var i = 0; i < dayBookings.length; i++) {
var bk = dayBookings[i];
var bkStart = timeToMinutes(bk.booking_start_time);
var bkEnd = timeToMinutes(bk.booking_finish_time);
var maxCols = 1;
for (var j = 0; j < dayBookings.length; j++) {
if (i === j) continue;
var oStart = timeToMinutes(dayBookings[j].booking_start_time);
var oEnd = timeToMinutes(dayBookings[j].booking_finish_time);
if (oStart < bkEnd && oEnd > bkStart) {
maxCols++;
}
}
bk._totalCols = Math.max(maxCols, columns.length);
}
// Normalize: use actual column count for overlapping group
var totalCols = columns.length;
for (var i = 0; i < dayBookings.length; i++) {
dayBookings[i]._totalCols = totalCols;
}
return dayBookings;
}
function renderGrid() {
var today = getToday();
var grid = document.getElementById('bcal-grid');
var html = '';
// Header row: empty corner + 7 day headers
html += '<div class="bcal-time-header"></div>';
for (var d = 0; d < 7; d++) {
var dayDate = dateAdd(currentMonday, d);
var isToday = (dayDate === today);
html += '<div class="bcal-day-header' + (isToday ? ' today' : '') + '">' + dayNames[d] + '<br>' + formatDate(dayDate) + '</div>';
}
// Time column + day columns
// Time column
html += '<div class="bcal-time-col">';
for (var h = DAY_START; h < DAY_END; h++) {
html += '<div class="bcal-time-label">' + String(h).padStart(2,'0') + ':00</div>';
}
html += '</div>';
// Group bookings by date
var bookingsByDate = {};
var filterWorker = document.getElementById('bcal-worker-filter').value;
for (var i = 0; i < allBookings.length; i++) {
var bk = allBookings[i];
if (filterWorker && String(bk.worker_id) !== filterWorker) continue;
if (!bookingsByDate[bk.booking_date]) bookingsByDate[bk.booking_date] = [];
bookingsByDate[bk.booking_date].push(bk);
}
// 7 day columns
for (var d = 0; d < 7; d++) {
var dayDate = dateAdd(currentMonday, d);
var isToday = (dayDate === today);
html += '<div class="bcal-day-col" style="height:'+(TOTAL_HOURS * PX_PER_HOUR)+'px;">';
// Hour lines
for (var h = 0; h < TOTAL_HOURS; h++) {
html += '<div class="bcal-hour-line" style="top:'+(h * PX_PER_HOUR)+'px;"></div>';
html += '<div class="bcal-half-line" style="top:'+(h * PX_PER_HOUR + 30)+'px;"></div>';
}
// Now line
if (isToday) {
var now = new Date();
var nowMinutes = now.getHours() * 60 + now.getMinutes();
var nowOffset = nowMinutes - DAY_START * 60;
if (nowOffset >= 0 && nowOffset <= TOTAL_HOURS * 60) {
html += '<div class="bcal-now-line" style="top:'+nowOffset+'px;"><div class="bcal-now-dot"></div></div>';
}
}
// Bookings
var dayBks = bookingsByDate[dayDate] || [];
if (dayBks.length > 0) {
dayBks = computeOverlapColumns(dayBks);
var totalCols = dayBks[0]._totalCols || 1;
for (var b = 0; b < dayBks.length; b++) {
var bk = dayBks[b];
var startMin = timeToMinutes(bk.booking_start_time);
var endMin = timeToMinutes(bk.booking_finish_time);
var top = (startMin - DAY_START * 60);
var height = Math.max(endMin - startMin, 15);
var color = workerColors[String(bk.worker_id)] || '#666';
var col = bk._col || 0;
var widthPct = (100 / totalCols);
var leftPct = col * widthPct;
var timeLabel = bk.booking_start_time.substring(0,5) + '' + bk.booking_finish_time.substring(0,5);
html += '<div class="bcal-booking" onclick="openBcalModal('+b+',\''+dayDate+'\')" style="top:'+top+'px;height:'+height+'px;background:'+color+';width:calc('+widthPct+'% - 2px);left:calc('+leftPct+'% + 1px);">';
html += '<div class="bcal-b-time">'+esc(timeLabel)+'</div>';
html += '<div class="bcal-b-name">'+esc(bk.guest_name)+'</div>';
if (height > 30) html += '<div class="bcal-b-svc">'+esc(bk.service_names_joined)+'</div>';
if (height > 45) html += '<div class="bcal-b-worker">'+esc(bk.worker_name)+'</div>';
html += '</div>';
}
}
html += '</div>';
}
grid.innerHTML = html;
// Store day bookings globally for modal access
window._bcalByDate = bookingsByDate;
}
window.openBcalModal = function(idx, dateStr) {
var dayBks = window._bcalByDate[dateStr] || [];
var bk = dayBks[idx];
if (!bk) return;
var body = '';
body += '<div class="bcal-detail-row"><label>Vendég:</label> <span>'+esc(bk.guest_name)+'</span></div>';
body += '<div class="bcal-detail-row"><label>Email:</label> <span>'+esc(bk.guest_email)+'</span></div>';
body += '<div class="bcal-detail-row"><label>Telefon:</label> <span>'+esc(bk.guest_phone)+'</span></div>';
body += '<div class="bcal-detail-row"><label>Dolgozó:</label> <span>'+esc(bk.worker_name)+'</span></div>';
body += '<div class="bcal-detail-row"><label>Dátum:</label> <span>'+esc(bk.booking_date)+'</span></div>';
body += '<div class="bcal-detail-row"><label>Időpont:</label> <span>'+bk.booking_start_time.substring(0,5)+' '+bk.booking_finish_time.substring(0,5)+'</span></div>';
if (bk.services && bk.services.length > 0) {
body += '<div class="bcal-detail-row"><label>Szolgáltatás:</label></div>';
var totalPrice = 0;
for (var s = 0; s < bk.services.length; s++) {
body += '<div style="margin-left:105px;font-size:13px;color:#ccc;">'+esc(bk.services[s].service_name)+' — '+bk.services[s].service_price+' kr</div>';
totalPrice += parseInt(bk.services[s].service_price) || 0;
}
body += '<div class="bcal-detail-row"><label>Összesen:</label> <span>'+totalPrice+' kr</span></div>';
}
document.getElementById('bcalModalBody').innerHTML = body;
document.getElementById('bcalModalTitle').textContent = 'Foglalás #' + bk.booking_id;
document.getElementById('bcalEditBtn').href = SITEURL + 'bookings/update-booking/' + bk.booking_id;
document.getElementById('bcalDeleteBtn').href = '#';
document.getElementById('bcalDeleteBtn').onclick = function(e) {
e.preventDefault();
if (confirm('Biztosan törölni szeretnéd ezt a foglalást?')) {
window.location.href = SITEURL + 'bookings/booking-process?delete-booking=' + bk.booking_id;
}
};
document.getElementById('bcalModal').style.display = 'block';
};
window.closeBcalModal = function() {
document.getElementById('bcalModal').style.display = 'none';
};
function loadWeek(mondayStr) {
currentMonday = mondayStr;
updateWeekLabel();
var filterWorker = document.getElementById('bcal-worker-filter').value;
var url = SITEURL + 'bookings/calendar-data?week=' + mondayStr;
if (filterWorker) url += '&worker_id=' + filterWorker;
$.ajax({
url: url,
type: 'GET',
dataType: 'json',
success: function(data) {
allBookings = data;
renderGrid();
}
});
}
// Navigation
document.getElementById('bcal-prev').onclick = function() {
loadWeek(dateAdd(currentMonday, -7));
};
document.getElementById('bcal-next').onclick = function() {
loadWeek(dateAdd(currentMonday, 7));
};
document.getElementById('bcal-today').onclick = function() {
loadWeek(getMonday(getToday()));
};
document.getElementById('bcal-worker-filter').onchange = function() {
renderGrid();
};
// Initial render
renderLegend();
updateWeekLabel();
renderGrid();
})();
</script>
@@ -2,6 +2,7 @@
<div class="pageTitle"><?php echo $pageTitle;?></div>
<div class="form-row">
<a href="<?php echo SITEURL;?>bookings/add-booking" class="submitBtn">Új foglalás</a>
<a href="<?php echo SITEURL;?>bookings/calendar" class="submitBtn">Naptárnézet</a>
</div>
<div class="form-row">
<select id="booking-filter" class="formDropdownBox" style="padding:0">