@@ -0,0 +1,322 @@
< style >
. cal - wrap { color : #fff; max-width: 820px; margin: 0 auto; padding: 10px; }
. cal - header { display : flex ; align - items : center ; justify - content : space - between ; margin : 14 px 0 10 px ; }
. cal - header a { color : #ccc; text-decoration: none; font-size: 18px; padding: 4px 10px; border: 1px solid #555; border-radius: 3px; }
. cal - header a : hover { background : #333; }
. cal - title { font - size : 20 px ; font - weight : bold ; }
. cal - table { width : 100 % ; border - collapse : collapse ; table - layout : fixed ; }
. cal - table th { background : #222; text-align: center; padding: 6px 2px; font-size: 13px; border: 1px solid #444; }
. cal - table td { border : 1 px solid #333; vertical-align: top; height: 72px; padding: 4px; cursor: pointer; position: relative; font-size: 12px; }
. cal - table td : hover { background : #1a1a1a; }
. cal - table td . empty { cursor : default ; background : #111; }
. cal - day - num { font - weight : bold ; font - size : 13 px ; margin - bottom : 3 px ; }
. cal - badge { display : inline - block ; padding : 1 px 5 px ; border - radius : 3 px ; font - size : 11 px ; color : #fff; margin-top: 2px; }
. badge - vacation { background : #d9534f; }
. badge - sick { background : #f0ad4e; color: #222; }
. badge - custom { background : #5bc0de; color: #222; }
. badge - other { background : #9b59b6; }
. badge - dayoff { background : #555; }
. badge - working { background : #5cb85c; }
. badge - noshift { background : #333; color: #888; }
. cal - today { outline : 2 px solid #fff; outline-offset: -2px; }
/* Legend */
. cal - legend { display : flex ; flex - wrap : wrap ; gap : 10 px ; margin : 12 px 0 ; font - size : 12 px ; }
. cal - legend - item { display : flex ; align - items : center ; gap : 5 px ; }
. cal - legend - dot { width : 14 px ; height : 14 px ; border - radius : 2 px ; display : inline - block ; }
/* Modal */
#calModal { display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.65); z-index: 9999; }
#calModalBox { background: #1e1e1e; border: 1px solid #555; border-radius: 6px; max-width: 400px; margin: 80px auto; padding: 24px; color: #fff; position: relative; }
#calModalBox h3 { margin: 0 0 14px; font-size: 17px; }
#calModalBox label { display: block; margin: 10px 0 3px; font-size: 13px; color: #ccc; }
#calModalBox select, #calModalBox input[type="text"], #calModalBox input[type="date"], #calModalBox textarea {
width : 100 % ; background : #2a2a2a; color: #fff; border: 1px solid #555; padding: 6px 8px;
border - radius : 3 px ; font - size : 13 px ; box - sizing : border - box ;
}
#calModalBox textarea { height: 60px; resize: vertical; }
. cal - modal - btns { display : flex ; gap : 10 px ; margin - top : 16 px ; }
. cal - btn - save { background : #5cb85c; color: #fff; border: none; padding: 8px 18px; border-radius: 3px; cursor: pointer; font-size: 14px; }
. cal - btn - cancel { background : #555; color: #fff; border: none; padding: 8px 18px; border-radius: 3px; cursor: pointer; font-size: 14px; }
</ style >
< div class = " cal-wrap " >
< div class = " pageTitle " >< ? php echo $pageTitle ; ?> </div>
<!-- Worker selector -->
<?php $monthParam = $year.'-'.str_pad($month, 2, '0', STR_PAD_LEFT); ?>
<div style="margin: 14px 0;">
<label style="color:#ccc; font-size:13px;">Dolgozó:</label>
<select onchange="if(this.value) window.location='<?php echo site_url('workers/worker-calendar'); ?>/' + this.value + '?month=<?php echo $monthParam; ?>'" style="background:#2a2a2a;color:#fff;border:1px solid #555;padding:5px 8px;border-radius:3px;font-size:13px;">
<option value="">-- Válassz dolgozót --</option>
<?php foreach ($workers as $w): ?>
<option value="<?php echo $w->worker_id; ?>"
<?php echo ($selectedWorker && $selectedWorker->worker_id == $w->worker_id) ? 'selected' : ''; ?>>
<?php echo htmlspecialchars($w->worker_name); ?>
</option>
<?php endforeach; ?>
</select>
</div>
<?php if ($selectedWorker):
// Build schedule map: weekday (0=Sun..6=Sat) => row
$scheduleMap = [];
foreach ($scheduleRows as $row) {
$scheduleMap[$row->weekday] = $row;
}
// Calendar math
$firstDay = mktime(0, 0, 0, $month, 1, $year);
$daysInMonth = (int)date('t', $firstDay);
// day-of-week of 1st (0=Sun, so Mon=1)
$startDow = (int)date('w', $firstDay); // 0=Sun..6=Sat
// Convert to Mon-based: Mon=0 .. Sun=6
$startOffset = ($startDow + 6) % 7;
$today = date('Y-m-d');
$monthLabel = strftime('%Y %B', $firstDay); // Hungarian month names via locale
// Fallback: PHP intl not guaranteed; build own table
$monthNames = ['január','február','március','április','május','június','július','augusztus','szeptember','október','november','december'];
$monthLabel = $year . ' ' . $monthNames[$month - 1];
$prevMonth = $month == 1 ? 12 : $month - 1;
$prevYear = $month == 1 ? $year - 1 : $year;
$nextMonth = $month == 12 ? 1 : $month + 1;
$nextYear = $month == 12 ? $year + 1 : $year;
$prevParam = $prevYear . '-' . str_pad($prevMonth, 2, '0', STR_PAD_LEFT);
$nextParam = $nextYear . '-' . str_pad($nextMonth, 2, '0', STR_PAD_LEFT);
$workerId = $selectedWorker->worker_id;
?>
<!-- Month navigation -->
<div class="cal-header">
<a href="<?php echo site_url('workers/worker-calendar/'.$workerId).'?month='.$prevParam; ?>">← Előző</a>
<span class="cal-title"><?php echo htmlspecialchars($monthLabel); ?></span>
<a href="<?php echo site_url('workers/worker-calendar/'.$workerId).'?month='.$nextParam; ?>">Következő →</a>
</div>
<!-- Legend -->
<div class="cal-legend">
<div class="cal-legend-item"><span class="cal-legend-dot" style="background:#5cb85c;"></span> Munkanap</div>
<div class="cal-legend-item"><span class="cal-legend-dot" style="background:#333;border:1px solid #555;"></span> Szabad nap</div>
<div class="cal-legend-item"><span class="cal-legend-dot" style="background:#555;"></span> Napiszabadság</div>
<div class="cal-legend-item"><span class="cal-legend-dot" style="background:#d9534f;"></span> Szabadság</div>
<div class="cal-legend-item"><span class="cal-legend-dot" style="background:#f0ad4e;"></span> Betegszabadság</div>
<div class="cal-legend-item"><span class="cal-legend-dot" style="background:#5bc0de;"></span> Egyedi munkaidő</div>
<div class="cal-legend-item"><span class="cal-legend-dot" style="background:#9b59b6;"></span> Egyéb</div>
<div class="cal-legend-item"><span class="cal-legend-dot" style="background:#888;"></span> Ebédszünet (auto)</div>
</div>
<!-- Calendar grid -->
<table class="cal-table">
<tr>
<th>H</th><th>K</th><th>Sz</th><th>Cs</th><th>P</th><th>Sz</th><th>V</th>
</tr>
<?php
$cell = 0;
$day = 1;
$phpDow = [1,2,3,4,5,6,0]; // Mon=0 -> PHP weekday=1, ... Sun=6 -> PHP=0
echo '<tr>';
// Empty cells before first day
for ($i = 0; $i < $startOffset; $i++) {
echo '<td class="empty"></td>';
$cell++;
}
while ($day <= $daysInMonth) {
if ($cell % 7 === 0 && $cell > 0) {
echo '</tr><tr>';
}
$colIndex = $cell % 7; // 0=Mon .. 6=Sun
$phpWeekday = $phpDow[$colIndex]; // PHP weekday number
$dateStr = $year . '-' . str_pad($month, 2, '0', STR_PAD_LEFT) . '-' . str_pad($day, 2, '0', STR_PAD_LEFT);
$isToday = ($dateStr === $today);
// Determine status
$override = isset($overridesByDate[$dateStr]) ? $overridesByDate[$dateStr] : null;
$hasSchedule = isset($scheduleMap[$phpWeekday]);
$badgeHtml = '';
$cellTitle = '';
$overrideJson = 'null';
if ($override) {
$absType = $override->absence_type ?? null;
if ($absType === 'vacation') {
$badgeHtml = '<span class="cal-badge badge-vacation">Szabadság</span>';
$cellTitle = 'Szabadság';
} elseif ($absType === 'sick') {
$badgeHtml = '<span class="cal-badge badge-sick">Beteg</span>';
$cellTitle = 'Betegszabadság';
} elseif ($absType === 'custom') {
$st = substr($override->start_time, 0, 5);
$et = substr($override->end_time, 0, 5);
$badgeHtml = '<span class="cal-badge badge-custom">'.$st.'– '.$et.'</span>';
$cellTitle = 'Egyedi: '.$st.'– '.$et;
} elseif ($absType === 'other') {
$badgeHtml = '<span class="cal-badge badge-other">Egyéb</span>';
$cellTitle = 'Egyéb';
} else {
// is_day_off=1, no absence_type = plain day off
$badgeHtml = '<span class="cal-badge badge-dayoff">Szabad</span>';
$cellTitle = 'Napi szabadság';
}
$overrideJson = json_encode([
'is_day_off' => (int)$override->is_day_off,
'absence_type' => $override->absence_type,
'start_time' => $override->start_time ? substr($override->start_time, 0, 5) : '',
'end_time' => $override->end_time ? substr($override->end_time, 0, 5) : '',
'note' => $override->note ?? '',
]);
} elseif ($hasSchedule) {
$sch = $scheduleMap[$phpWeekday];
$st = substr($sch->start_time, 0, 5);
$et = substr($sch->end_time, 0, 5);
$badgeHtml = '<span class="cal-badge badge-working">'.$st.'– '.$et.'</span>';
$cellTitle = 'Munkanap: '.$st.'– '.$et;
} else {
$badgeHtml = '<span class="cal-badge badge-noshift">Szabad</span>';
$cellTitle = 'Nem dolgozik';
}
$todayClass = $isToday ? ' cal-today' : '';
$encodedDate = htmlspecialchars(json_encode($dateStr), ENT_QUOTES);
$encodedWid = htmlspecialchars(json_encode($workerId), ENT_QUOTES);
$encodedOver = htmlspecialchars($overrideJson, ENT_QUOTES);
echo '<td class="'.$todayClass.'" title="'.htmlspecialchars($cellTitle).'" onclick="openModal('.$encodedDate.', '.$encodedWid.', '.$encodedOver.')">';
echo '<div class="cal-day-num">'.$day.'</div>';
echo $badgeHtml;
if (isset($lunchByDate[$dateStr])) {
$lb = $lunchByDate[$dateStr];
echo '<span class="cal-badge" style="background:#888;display:block;margin-top:2px;">🍴 '.$lb['start'].'–'.$lb['end'].'</span>';
}
echo '</td>';
$day++;
$cell++;
}
// Pad remaining cells
while ($cell % 7 !== 0) {
echo '<td class="empty"></td>';
$cell++;
}
echo '</tr>';
?>
</table>
<?php endif; ?>
</div>
<!-- Modal -->
<div id="calModal" onclick="closeModalBackdrop(event)">
<div id="calModalBox">
<h3 id="calModalTitle">Nap szerkesztése</h3>
<form method="POST" action="<?php echo site_url('workers/store-calendar-override'); ?>" id="calModalForm">
<input type="hidden" name="worker_id" id="modalWorkerId" value="">
<input type="hidden" name="start_date" id="modalStartDate" value="">
<label>Típus:</label>
<select name="override_type" id="modalType" onchange="onTypeChange()">
<option value="remove">Felülírás törlése (alap munkaidő visszaállítása)</option>
<option value="day_off">Szabadnap</option>
<option value="vacation">Szabadság</option>
<option value="sick">Betegszabadság</option>
<option value="custom">Egyedi munkaidő</option>
<option value="other">Egyéb</option>
</select>
<div id="customTimeRow" style="display:none;">
<label>Kezdés:</label>
<input type="text" name="start_time" id="modalStartTime" placeholder="HH:MM" pattern="[0-2][0-9]:[0-5][0-9]" inputmode="numeric">
<label>Vége:</label>
<input type="text" name="end_time" id="modalEndTime" placeholder="HH:MM" pattern="[0-2][0-9]:[0-5][0-9]" inputmode="numeric">
</div>
<div id="noteRow" style="display:none;">
<label>Megjegyzés:</label>
<textarea name="note" id="modalNote"></textarea>
</div>
<div style="margin-top:12px;">
<label>
<input type="checkbox" id="rangeCheck" onchange="toggleRange()" style="margin-right:5px;">
Dátumtartományra alkalmazás
</label>
</div>
<div id="rangeRow" style="display:none;">
<label>Záró dátum:</label>
<input type="date" name="end_date" id="modalEndDate">
</div>
<div class="cal-modal-btns">
<button type="submit" class="cal-btn-save">Mentés</button>
<button type="button" class="cal-btn-cancel" onclick="closeModal()">Mégse</button>
</div>
</form>
</div>
</div>
<script>
function openModal(date, workerId, existing) {
document.getElementById('modalWorkerId').value = workerId;
document.getElementById('modalStartDate').value = date;
document.getElementById('calModalTitle').textContent = 'Nap: ' + date;
document.getElementById('rangeCheck').checked = false;
document.getElementById('rangeRow').style.display = 'none';
document.getElementById('modalEndDate').value = '';
var sel = document.getElementById('modalType');
var noteEl = document.getElementById('modalNote');
noteEl.value = '';
if (existing) {
var absType = existing.absence_type;
if (absType === 'vacation') {
sel.value = 'vacation';
} else if (absType === 'sick') {
sel.value = 'sick';
} else if (absType === 'custom') {
sel.value = 'custom';
} else if (absType === 'other') {
sel.value = 'other';
} else if (existing.is_day_off == 1) {
sel.value = 'day_off';
} else {
sel.value = 'remove';
}
document.getElementById('modalStartTime').value = existing.start_time || '';
document.getElementById('modalEndTime').value = existing.end_time || '';
noteEl.value = existing.note || '';
} else {
sel.value = 'remove';
document.getElementById('modalStartTime').value = '';
document.getElementById('modalEndTime').value = '';
}
onTypeChange();
document.getElementById('calModal').style.display = 'block';
}
function closeModal() {
document.getElementById('calModal').style.display = 'none';
}
function closeModalBackdrop(e) {
if (e.target === document.getElementById('calModal')) {
closeModal();
}
}
function onTypeChange() {
var type = document.getElementById('modalType').value;
document.getElementById('customTimeRow').style.display = (type === 'custom') ? 'block' : 'none';
var showNote = (type === 'vacation' || type === 'sick' || type === 'other' || type === 'custom');
document.getElementById('noteRow').style.display = showNote ? 'block' : 'none';
}
function toggleRange() {
var show = document.getElementById('rangeCheck').checked;
document.getElementById('rangeRow').style.display = show ? 'block' : 'none';
if (!show) document.getElementById('modalEndDate').value = '';
}
</script>