356 lines
17 KiB
PHP
356 lines
17 KiB
PHP
<?php
|
|
/**
|
|
* Calendar Planning View
|
|
* Main interface for drag-and-drop TV scheduling
|
|
*/
|
|
|
|
ini_set('display_errors', 1);
|
|
ini_set('display_startup_errors', 1);
|
|
error_reporting(E_ALL);
|
|
|
|
require_once __DIR__ . '/vendor/autoload.php';
|
|
require_once __DIR__ . '/helpers.php';
|
|
|
|
use Dotenv\Dotenv;
|
|
$dotenv = Dotenv::createImmutable(__DIR__);
|
|
$dotenv->load();
|
|
|
|
$db = getDbConnection();
|
|
|
|
// Get all infomercials with colors for sidebar
|
|
$infomercials = $db->query("
|
|
SELECT id, title, duration, color_code, series_code, upload_status
|
|
FROM infomercials
|
|
WHERE upload_status = 'uploaded'
|
|
ORDER BY title ASC
|
|
")->fetchAll();
|
|
|
|
// Auto-assign colors to infomercials without colors
|
|
foreach ($infomercials as $infomercial) {
|
|
if (empty($infomercial['color_code'])) {
|
|
$stmt = $db->query("SELECT color_code FROM infomercials WHERE color_code IS NOT NULL");
|
|
$existingColors = $stmt->fetchAll(PDO::FETCH_COLUMN);
|
|
$newColor = generateDistinctColor($existingColors);
|
|
|
|
$stmt = $db->prepare("UPDATE infomercials SET color_code = ? WHERE id = ?");
|
|
$stmt->execute([$newColor, $infomercial['id']]);
|
|
}
|
|
}
|
|
|
|
// Refresh infomercials after color assignment
|
|
$infomercials = $db->query("
|
|
SELECT id, title, duration, color_code, series_code, upload_status
|
|
FROM infomercials
|
|
WHERE upload_status = 'uploaded'
|
|
ORDER BY title ASC
|
|
")->fetchAll();
|
|
?>
|
|
|
|
<!DOCTYPE html>
|
|
<html lang="nl">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Kalender Planning - Telvero Talpa</title>
|
|
|
|
<!-- Bootstrap -->
|
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css">
|
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.0/font/bootstrap-icons.css">
|
|
|
|
<!-- FullCalendar -->
|
|
<link href='https://cdn.jsdelivr.net/npm/fullcalendar-scheduler@6.1.10/index.global.min.css' rel='stylesheet' />
|
|
|
|
<!-- Custom CSS -->
|
|
<link rel="stylesheet" href="assets/css/custom.css">
|
|
</head>
|
|
<body class="bg-light">
|
|
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
|
|
<div class="container-fluid">
|
|
<a class="navbar-brand" href="index.php">
|
|
<i class="bi bi-tv"></i> Telvero Talpa Planner
|
|
</a>
|
|
<div class="navbar-nav">
|
|
<a class="nav-link" href="index.php">Dashboard</a>
|
|
<a class="nav-link" href="planner.php">Excel Planner</a>
|
|
<a class="nav-link active" href="calendar.php">Kalender</a>
|
|
<a class="nav-link" href="blocks.php">Blokken</a>
|
|
<a class="nav-link" href="infomercials.php">Infomercials</a>
|
|
</div>
|
|
</div>
|
|
</nav>
|
|
|
|
<div class="container-fluid mt-4">
|
|
<!-- Alert Container -->
|
|
<div id="alertContainer"></div>
|
|
|
|
<!-- Block Info Display & Zoom Controls -->
|
|
<div class="row mb-3">
|
|
<div class="col-md-9">
|
|
<div class="card shadow-sm">
|
|
<div class="card-header bg-info text-white py-2 d-flex justify-content-between align-items-center">
|
|
<h6 class="mb-0">
|
|
<i class="bi bi-calendar3"></i> Actieve Blokken voor Vandaag
|
|
</h6>
|
|
<button type="button" class="btn-icon btn-icon-sm btn-icon-success" onclick="showSyncBlockModal()">
|
|
<i class="bi bi-cloud-upload"></i>
|
|
</button>
|
|
</div>
|
|
<div class="card-body p-2" id="blockInfoContainer">
|
|
<p class="text-muted small mb-0">Laden...</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="card shadow-sm">
|
|
<div class="card-header bg-secondary text-white py-2">
|
|
<h6 class="mb-0">
|
|
<i class="bi bi-zoom-in"></i> Zoom
|
|
</h6>
|
|
</div>
|
|
<div class="card-body p-2">
|
|
<div class="action-buttons w-100 justify-content-center">
|
|
<button type="button" class="btn-icon btn-icon-sm btn-icon-secondary" onclick="adjustZoom(0.8)">
|
|
<i class="bi bi-dash-circle"></i>
|
|
</button>
|
|
<button type="button" class="btn-icon btn-icon-sm btn-icon-secondary" onclick="adjustZoom(1.0)">
|
|
<i class="bi bi-arrow-clockwise"></i>
|
|
</button>
|
|
<button type="button" class="btn-icon btn-icon-sm btn-icon-secondary" onclick="adjustZoom(1.2)">
|
|
<i class="bi bi-plus-circle"></i>
|
|
</button>
|
|
</div>
|
|
<div class="mt-2 text-center">
|
|
<small class="text-muted">Huidige: <span id="zoomLevel">100%</span></small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<!-- Sidebar with draggable infomercials -->
|
|
<div class="col-md-3">
|
|
<div class="card shadow-sm">
|
|
<div class="card-header bg-primary text-white">
|
|
<h5 class="mb-0">
|
|
<i class="bi bi-collection-play"></i> Beschikbare Infomercials
|
|
</h5>
|
|
</div>
|
|
<div class="card-body p-2">
|
|
<!-- Search -->
|
|
<div class="mb-3">
|
|
<input type="text"
|
|
class="form-control form-control-sm"
|
|
placeholder="Zoeken..."
|
|
onkeyup="filterCommercials(this.value)">
|
|
</div>
|
|
|
|
<!-- Infomercial List -->
|
|
<div class="infomercial-sidebar">
|
|
<?php if (empty($infomercials)): ?>
|
|
<div class="text-center text-muted p-3">
|
|
<i class="bi bi-inbox" style="font-size: 2rem;"></i>
|
|
<p class="mt-2 small">Geen infomercials beschikbaar</p>
|
|
<a href="infomercials.php" class="btn btn-sm btn-primary">
|
|
Voeg Infomercial Toe
|
|
</a>
|
|
</div>
|
|
<?php else: ?>
|
|
<?php foreach ($infomercials as $infomercial): ?>
|
|
<div class="infomercial-item"
|
|
style="border-left-color: <?= htmlspecialchars($infomercial['color_code']) ?>;"
|
|
data-infomercial-id="<?= $infomercial['id'] ?>"
|
|
data-title="<?= htmlspecialchars($infomercial['title']) ?>"
|
|
data-duration="<?= $infomercial['duration'] ?>"
|
|
data-color="<?= htmlspecialchars($infomercial['color_code']) ?>"
|
|
data-series-code="<?= htmlspecialchars($infomercial['series_code'] ?? '') ?>">
|
|
|
|
<div class="d-flex align-items-center">
|
|
<div class="color-preview me-2"
|
|
style="background-color: <?= htmlspecialchars($infomercial['color_code']) ?>; width: 20px; height: 20px; border-radius: 3px;">
|
|
</div>
|
|
<div class="flex-grow-1">
|
|
<div class="infomercial-title">
|
|
<?= htmlspecialchars($infomercial['title']) ?>
|
|
</div>
|
|
<div class="infomercial-duration">
|
|
<i class="bi bi-clock"></i> <?= $infomercial['duration'] ?>
|
|
</div>
|
|
<?php if ($infomercial['series_code']): ?>
|
|
<div class="infomercial-series">
|
|
<i class="bi bi-tag"></i> <?= htmlspecialchars($infomercial['series_code']) ?>
|
|
</div>
|
|
<?php endif; ?>
|
|
</div>
|
|
<div>
|
|
<i class="bi bi-grip-vertical text-muted"></i>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<?php endforeach; ?>
|
|
<?php endif; ?>
|
|
</div>
|
|
|
|
<div class="mt-3 p-2 bg-light rounded">
|
|
<small class="text-muted">
|
|
<i class="bi bi-info-circle"></i>
|
|
Sleep infomercials naar de kalender om te plannen
|
|
</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Legend -->
|
|
<div class="card shadow-sm mt-3">
|
|
<div class="card-header bg-secondary text-white">
|
|
<h6 class="mb-0"><i class="bi bi-palette"></i> Legenda</h6>
|
|
</div>
|
|
<div class="card-body p-2">
|
|
<div class="small">
|
|
<?php
|
|
$uniqueColors = [];
|
|
foreach ($infomercials as $infomercial) {
|
|
if ($infomercial['series_code'] && !isset($uniqueColors[$infomercial['series_code']])) {
|
|
$uniqueColors[$infomercial['series_code']] = $infomercial['color_code'];
|
|
}
|
|
}
|
|
?>
|
|
<?php foreach ($uniqueColors as $code => $color): ?>
|
|
<div class="d-flex align-items-center mb-2">
|
|
<div style="width: 20px; height: 20px; background-color: <?= $color ?>; border-radius: 3px; margin-right: 8px;"></div>
|
|
<span><?= htmlspecialchars($code) ?></span>
|
|
</div>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Calendar -->
|
|
<div class="col-md-9">
|
|
<div class="card shadow-sm">
|
|
<div class="card-body">
|
|
<div id="calendar"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Event Details Modal -->
|
|
<div class="modal fade" id="eventModal" tabindex="-1">
|
|
<div class="modal-dialog">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title" id="eventTitle">Uitzending Details</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
</div>
|
|
<div class="modal-body" id="eventDetails">
|
|
<!-- Details will be populated by JavaScript -->
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-danger" id="deleteEventBtn">
|
|
<i class="bi bi-trash"></i> Verwijderen
|
|
</button>
|
|
<button type="button" class="btn btn-success" id="syncEventBtn">
|
|
<i class="bi bi-cloud-upload"></i> Sync
|
|
</button>
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Sluiten</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Block Time Editor Modal -->
|
|
<div class="modal fade" id="blockTimeModal" tabindex="-1">
|
|
<div class="modal-dialog">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title">Blok Starttijd Aanpassen</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<input type="hidden" id="blockDate">
|
|
<input type="hidden" id="blockChannel">
|
|
|
|
<div class="mb-3">
|
|
<label class="form-label">Nieuwe Starttijd</label>
|
|
<input type="time" class="form-control" id="blockStartTime">
|
|
</div>
|
|
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" id="recalculateTransmissions" checked>
|
|
<label class="form-check-label" for="recalculateTransmissions">
|
|
Herbereken alle uitzendingen in dit blok
|
|
</label>
|
|
</div>
|
|
|
|
<div class="alert alert-info mt-3">
|
|
<i class="bi bi-info-circle"></i>
|
|
Als je "herbereken" aanvinkt, worden alle uitzendingen in dit blok opnieuw getimed vanaf de nieuwe starttijd.
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Annuleren</button>
|
|
<button type="button" class="btn btn-primary" onclick="saveBlockTime()">
|
|
<i class="bi bi-check-circle"></i> Opslaan
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Sync Block Modal -->
|
|
<div class="modal fade" id="syncBlockModal" tabindex="-1">
|
|
<div class="modal-dialog">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title">Blok Synchroniseren naar Talpa</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<div class="mb-3">
|
|
<label class="form-label">Datum</label>
|
|
<input type="date" class="form-control" id="syncBlockDate" value="<?= date('Y-m-d') ?>">
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<label class="form-label">Zender</label>
|
|
<select class="form-select" id="syncBlockChannel">
|
|
<option value="SBS9">SBS9</option>
|
|
<option value="NET5">NET5</option>
|
|
<option value="SBS6">SBS6</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="alert alert-info">
|
|
<i class="bi bi-info-circle"></i>
|
|
Dit synchroniseert alle uitzendingen in het geselecteerde blok naar Talpa.
|
|
Alleen uitzendingen die nog niet gesynchroniseerd zijn worden verzonden.
|
|
</div>
|
|
|
|
<div id="syncBlockProgress" class="d-none">
|
|
<div class="progress">
|
|
<div class="progress-bar progress-bar-striped progress-bar-animated"
|
|
role="progressbar" style="width: 100%"></div>
|
|
</div>
|
|
<p class="text-center mt-2 mb-0">Synchroniseren...</p>
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Annuleren</button>
|
|
<button type="button" class="btn btn-primary" onclick="syncBlock()">
|
|
<i class="bi bi-cloud-upload"></i> Synchroniseren
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Scripts -->
|
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
|
<script src='https://cdn.jsdelivr.net/npm/fullcalendar-scheduler@6.1.10/index.global.min.js'></script>
|
|
<script src="assets/js/calendar-init.js"></script>
|
|
</body>
|
|
</html>
|