269 lines
11 KiB
PHP
269 lines
11 KiB
PHP
<?php
|
|
require_once __DIR__ . '/auth.php';
|
|
require_once __DIR__ . '/db/config.php';
|
|
|
|
$pdo = db();
|
|
$stmt = $pdo->prepare("SELECT id, name FROM leads WHERE status != 'Closed'");
|
|
$stmt->execute();
|
|
$leads = $stmt->fetchAll();
|
|
|
|
?>
|
|
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Calendar</title>
|
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/js-calendar-pro/dist/js-calendar.min.css">
|
|
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
|
|
</head>
|
|
<body>
|
|
|
|
<div class="main-container">
|
|
<aside class="sidebar">
|
|
<div class="logo">SaaSApp</div>
|
|
<nav class="nav flex-column">
|
|
<a class="nav-link" href="index.php">Dashboard</a>
|
|
<a class="nav-link" href="leads.php">Leads</a>
|
|
<a class="nav-link active" href="calendar.php">Calendar</a>
|
|
<?php if (is_admin()): ?>
|
|
<a class="nav-link" href="users.php">Users</a>
|
|
<a class="nav-link" href="settings.php">Settings</a>
|
|
<?php endif; ?>
|
|
<a class="nav-link" href="logout.php">Logout</a>
|
|
</nav>
|
|
</aside>
|
|
|
|
<main class="main-content">
|
|
<header class="header">
|
|
<h1>Calendar</h1>
|
|
</header>
|
|
|
|
<div class="card">
|
|
<div class="card-body">
|
|
<div id="calendar"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card mt-4" id="eventsCard" style="display: none;">
|
|
<div class="card-body">
|
|
<div class="d-flex justify-content-between align-items-center">
|
|
<h5 class="card-title" id="eventsDate">Events for...</h5>
|
|
<button class="btn btn-primary btn-sm" id="addEventBtn">Add Event</button>
|
|
</div>
|
|
<ul class="list-group mt-3" id="eventsList"></ul>
|
|
</div>
|
|
</div>
|
|
</main>
|
|
</div>
|
|
|
|
<!-- Event Modal -->
|
|
<div class="modal fade" id="eventModal" tabindex="-1" aria-labelledby="eventModalLabel" aria-hidden="true">
|
|
<div class="modal-dialog">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title" id="eventModalLabel">New Event</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<form id="eventForm">
|
|
<input type="hidden" id="eventDate" name="eventDate">
|
|
<input type="hidden" id="eventId" name="eventId">
|
|
<div class="mb-3">
|
|
<label for="eventTitle" class="form-label">Title</label>
|
|
<input type="text" class="form-control" id="eventTitle" name="eventTitle" required>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label for="leadId" class="form-label">Lead (optional)</label>
|
|
<select class="form-select" id="leadId" name="leadId">
|
|
<option value="">Select a lead</option>
|
|
<?php foreach ($leads as $lead): ?>
|
|
<option value="<?php echo $lead['id']; ?>"><?php echo htmlspecialchars($lead['name']); ?></option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
</div>
|
|
<div class="row">
|
|
<div class="col-md-6 mb-3">
|
|
<label for="startTime" class="form-label">Start Time</label>
|
|
<input type="time" class="form-control" id="startTime" name="startTime" required>
|
|
</div>
|
|
<div class="col-md-6 mb-3">
|
|
<label for="endTime" class="form-label">End Time</label>
|
|
<input type="time" class="form-control" id="endTime" name="endTime" required>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
|
<button type="button" class="btn btn-primary" id="saveEvent">Save Event</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script src="https://cdn.jsdelivr.net/npm/js-calendar-pro/dist/js-calendar.min.js"></script>
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
const calendarEl = document.getElementById('calendar');
|
|
const calendar = new JsCalendar(calendarEl);
|
|
const eventModal = new bootstrap.Modal(document.getElementById('eventModal'));
|
|
const eventDateInput = document.getElementById('eventDate');
|
|
const addEventBtn = document.getElementById('addEventBtn');
|
|
let selectedDate = null;
|
|
|
|
function fetchAndRenderEvents() {
|
|
fetch('api/get_events.php')
|
|
.then(response => response.json())
|
|
.then(events => {
|
|
// Clear existing markers
|
|
calendarEl.querySelectorAll('.event-marker').forEach(marker => marker.remove());
|
|
|
|
events.forEach(event => {
|
|
const eventDate = new Date(event.start_time);
|
|
const dateString = eventDate.toISOString().slice(0, 10);
|
|
const dateCell = calendarEl.querySelector(`.jsCalendar-cell[data-date='${dateString}']`);
|
|
if (dateCell && !dateCell.querySelector('.event-marker')) {
|
|
const marker = document.createElement('div');
|
|
marker.classList.add('event-marker');
|
|
dateCell.appendChild(marker);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
calendar.onDateClick((event, date) => {
|
|
selectedDate = date;
|
|
const dateString = date.toISOString().slice(0, 10);
|
|
|
|
const eventsCard = document.getElementById('eventsCard');
|
|
const eventsDate = document.getElementById('eventsDate');
|
|
const eventsList = document.getElementById('eventsList');
|
|
|
|
eventsDate.textContent = `Events for ${date.toLocaleDateString()}`;
|
|
eventsList.innerHTML = ''; // Clear previous events
|
|
|
|
fetch(`api/get_events_for_day.php?date=${dateString}`)
|
|
.then(response => response.json())
|
|
.then(events => {
|
|
if (events.length > 0) {
|
|
events.forEach(event => {
|
|
const li = document.createElement('li');
|
|
li.classList.add('list-group-item');
|
|
const startTime = new Date(event.start_time).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
|
|
const endTime = new Date(event.end_time).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
|
|
li.innerHTML = `
|
|
<div>
|
|
<strong>${event.title}</strong><br>
|
|
${startTime} - ${endTime}
|
|
${event.lead_name ? `<br><small>Lead: ${event.lead_name}</small>` : ''}
|
|
</div>
|
|
<div>
|
|
<button class="btn btn-sm btn-outline-primary edit-event" data-id="${event.id}">Edit</button>
|
|
<button class="btn btn-sm btn-outline-danger delete-event" data-id="${event.id}">Delete</button>
|
|
</div>
|
|
`;
|
|
li.classList.add('d-flex', 'justify-content-between', 'align-items-center');
|
|
eventsList.appendChild(li);
|
|
});
|
|
} else {
|
|
const li = document.createElement('li');
|
|
li.classList.add('list-group-item');
|
|
li.textContent = 'No events for this day.';
|
|
eventsList.appendChild(li);
|
|
}
|
|
eventsCard.style.display = 'block';
|
|
});
|
|
});
|
|
|
|
addEventBtn.addEventListener('click', () => {
|
|
if (selectedDate) {
|
|
eventDateInput.value = selectedDate.toISOString().slice(0, 10);
|
|
eventModal.show();
|
|
}
|
|
});
|
|
|
|
calendar.onMonthChange(() => {
|
|
fetchAndRenderEvents();
|
|
document.getElementById('eventsCard').style.display = 'none';
|
|
});
|
|
|
|
document.getElementById('saveEvent').addEventListener('click', () => {
|
|
const form = document.getElementById('eventForm');
|
|
const formData = new FormData(form);
|
|
const eventData = Object.fromEntries(formData.entries());
|
|
const eventId = document.getElementById('eventId').value;
|
|
|
|
const url = eventId ? 'api/update_event.php' : 'api/create_event.php';
|
|
|
|
fetch(url, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify(eventData)
|
|
})
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (data.success) {
|
|
eventModal.hide();
|
|
fetchAndRenderEvents();
|
|
if (selectedDate) {
|
|
calendar.emit('dateClick', null, selectedDate);
|
|
}
|
|
} else {
|
|
alert('Failed to save event: ' + data.message);
|
|
}
|
|
});
|
|
});
|
|
|
|
eventsList.addEventListener('click', (e) => {
|
|
if (e.target.classList.contains('edit-event')) {
|
|
const eventId = e.target.dataset.id;
|
|
fetch(`api/get_events_for_day.php?date=${selectedDate.toISOString().slice(0,10)}`)
|
|
.then(response => response.json())
|
|
.then(events => {
|
|
const event = events.find(ev => ev.id == eventId);
|
|
if (event) {
|
|
document.getElementById('eventId').value = event.id;
|
|
document.getElementById('eventTitle').value = event.title;
|
|
document.getElementById('leadId').value = event.lead_id;
|
|
document.getElementById('startTime').value = new Date(event.start_time).toTimeString().slice(0,5);
|
|
document.getElementById('endTime').value = new Date(event.end_time).toTimeString().slice(0,5);
|
|
document.getElementById('eventModalLabel').textContent = 'Edit Event';
|
|
eventModal.show();
|
|
}
|
|
});
|
|
} else if (e.target.classList.contains('delete-event')) {
|
|
const eventId = e.target.dataset.id;
|
|
if (confirm('Are you sure you want to delete this event?')) {
|
|
fetch('api/delete_event.php', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify({ id: eventId })
|
|
})
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (data.success) {
|
|
fetchAndRenderEvents();
|
|
if (selectedDate) {
|
|
calendar.emit('dateClick', null, selectedDate);
|
|
}
|
|
} else {
|
|
alert('Failed to delete event: ' + data.message);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
});
|
|
|
|
fetchAndRenderEvents();
|
|
});
|
|
</script>
|
|
|
|
</body>
|
|
</html>
|