Files
UbuntuandClaude Opus 4.7 92a84aadb1 Remove dead strftime() call in worker calendar form
The strftime() result was immediately overwritten by a hardcoded
Hungarian month-name array. Drop the dead line so PHP 8.1+ stops
emitting an E_DEPRECATED warning when prod loads the worker calendar.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-11 11:41:47 +00:00

324 lines
16 KiB
PHP
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<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: 14px 0 10px; }
.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: 20px; 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: 1px 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: 13px; margin-bottom: 3px; }
.cal-badge { display: inline-block; padding: 1px 5px; border-radius: 3px; font-size: 11px; 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: 2px solid #fff; outline-offset: -2px; }
/* Legend */
.cal-legend { display: flex; flex-wrap: wrap; gap: 10px; margin: 12px 0; font-size: 12px; }
.cal-legend-item { display: flex; align-items: center; gap: 5px; }
.cal-legend-dot { width: 14px; height: 14px; border-radius: 2px; 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: 3px; font-size: 13px; box-sizing: border-box;
}
.cal-wrap select option, #calModalBox select option {
background: #2a2a2a; color: #fff;
}
#calModalBox textarea { height: 60px; resize: vertical; }
.cal-modal-btns { display: flex; gap: 10px; margin-top: 16px; }
.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');
$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; ?>">&#8592; 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ő &#8594;</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;">&#x1F374; '.$lb['start'].'&ndash;'.$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>