Significant admin UI improvements
This commit is contained in:
parent
f015a90791
commit
bc5a8e0305
BIN
db/freesched.db
BIN
db/freesched.db
Binary file not shown.
1
pages/index.js
Normal file
1
pages/index.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
934
public/admin.js
934
public/admin.js
File diff suppressed because it is too large
Load Diff
1
public/index.html
Normal file
1
public/index.html
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
@ -26,6 +26,26 @@ function isValidUid(uid) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', async () => {
|
document.addEventListener('DOMContentLoaded', async () => {
|
||||||
|
// Add custom CSS for the current date to make it more distinguishable
|
||||||
|
const style = document.createElement('style');
|
||||||
|
style.textContent = `
|
||||||
|
.date-item.current {
|
||||||
|
border: 2px solid #ffc107 !important; /* Yellow border */
|
||||||
|
background-color: rgba(255, 193, 7, 0.1) !important; /* Light yellow background */
|
||||||
|
font-weight: bold !important;
|
||||||
|
color: #212529 !important; /* Ensure text is visible */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ensure current date styling takes precedence but doesn't interfere with selection */
|
||||||
|
.date-item.current.selected {
|
||||||
|
border: 2px solid #0d6efd !important; /* Blue border for selected */
|
||||||
|
background-color: #0d6efd !important; /* Dark blue background when selected */
|
||||||
|
color: white !important; /* White text for better contrast */
|
||||||
|
font-weight: bold !important;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
document.head.appendChild(style);
|
||||||
|
|
||||||
const uid = getUidFromPath();
|
const uid = getUidFromPath();
|
||||||
const mainContent = document.getElementById('mainContent');
|
const mainContent = document.getElementById('mainContent');
|
||||||
const uidError = document.getElementById('uidError');
|
const uidError = document.getElementById('uidError');
|
||||||
@ -94,6 +114,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|||||||
const firstDay = new Date(year, month, 1).getDay();
|
const firstDay = new Date(year, month, 1).getDay();
|
||||||
const daysInMonth = new Date(year, month + 1, 0).getDate();
|
const daysInMonth = new Date(year, month + 1, 0).getDate();
|
||||||
const today = new Date();
|
const today = new Date();
|
||||||
|
const currentMinutes = today.getHours() * 60 + today.getMinutes();
|
||||||
|
|
||||||
// Create blank cells for days before the first day of the month
|
// Create blank cells for days before the first day of the month
|
||||||
for (let i = 0; i < firstDay; i++) {
|
for (let i = 0; i < firstDay; i++) {
|
||||||
@ -115,13 +136,36 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|||||||
|
|
||||||
// Check if date is in the past
|
// Check if date is in the past
|
||||||
const isPastDate = date < startOfToday;
|
const isPastDate = date < startOfToday;
|
||||||
|
const isToday = date.toDateString() === today.toDateString();
|
||||||
|
|
||||||
if (date.toDateString() === today.toDateString()) {
|
if (isToday) {
|
||||||
day.classList.add('current');
|
day.classList.add('current');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if the date has available time slots
|
||||||
|
let hasAvailableTimes = false;
|
||||||
if (availability[dateStr]) {
|
if (availability[dateStr]) {
|
||||||
|
let times = [];
|
||||||
|
if (typeof availability[dateStr] === 'string') {
|
||||||
|
times = availability[dateStr].split(',').map(t => t.trim());
|
||||||
|
} else if (Array.isArray(availability[dateStr])) {
|
||||||
|
times = availability[dateStr].map(t => t.trim());
|
||||||
|
}
|
||||||
|
|
||||||
|
// For today, filter out past times
|
||||||
|
if (isToday) {
|
||||||
|
times = times.filter(time => timeToMinutes(time) > currentMinutes);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only mark as available if there are valid times
|
||||||
|
hasAvailableTimes = times.length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only add 'available' class if the date is not in the past AND has available times
|
||||||
|
if (hasAvailableTimes && !isPastDate) {
|
||||||
day.classList.add('available');
|
day.classList.add('available');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isPastDate) {
|
if (isPastDate) {
|
||||||
day.classList.add('disabled');
|
day.classList.add('disabled');
|
||||||
} else {
|
} else {
|
||||||
|
@ -151,7 +151,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear existing time slots or message
|
// Clear available time slots or message
|
||||||
timeSlotsContainer.innerHTML = '';
|
timeSlotsContainer.innerHTML = '';
|
||||||
|
|
||||||
// Get current time in minutes for comparison
|
// Get current time in minutes for comparison
|
||||||
|
@ -48,9 +48,10 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.sidebar h3 {
|
.sidebar h3 {
|
||||||
font-size: 1rem;
|
font-size: 0.9rem;
|
||||||
color: #666;
|
color: #666;
|
||||||
margin-bottom: 5px;
|
margin-bottom: 5px;
|
||||||
|
font-weight: 400;
|
||||||
}
|
}
|
||||||
|
|
||||||
.duration {
|
.duration {
|
||||||
@ -61,6 +62,8 @@
|
|||||||
.main-content {
|
.main-content {
|
||||||
width: 70%;
|
width: 70%;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
|
position: relative;
|
||||||
|
min-height: 600px; /* Ensure minimum height for the content area */
|
||||||
}
|
}
|
||||||
|
|
||||||
.calendar-header h1 {
|
.calendar-header h1 {
|
||||||
@ -174,11 +177,16 @@
|
|||||||
font-size: 0.75rem;
|
font-size: 0.75rem;
|
||||||
color: #666;
|
color: #666;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
position: relative;
|
position: absolute;
|
||||||
margin-top: 2rem;
|
bottom: 20px;
|
||||||
|
right: 20px;
|
||||||
opacity: 0.8;
|
opacity: 0.8;
|
||||||
transition: opacity 0.3s ease;
|
transition: opacity 0.3s ease;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
|
background-color: transparent;
|
||||||
|
padding: 5px;
|
||||||
|
margin: 0;
|
||||||
|
pointer-events: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.powered-by a {
|
.powered-by a {
|
||||||
@ -231,4 +239,66 @@
|
|||||||
#admin .col-md-6 {
|
#admin .col-md-6 {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.powered-by {
|
||||||
|
position: relative;
|
||||||
|
bottom: auto;
|
||||||
|
right: auto;
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 30px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sidebar buttons styling */
|
||||||
|
.sidebar .btn {
|
||||||
|
padding: 12px 20px;
|
||||||
|
font-size: 1.1rem;
|
||||||
|
font-weight: 500;
|
||||||
|
border: none;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar .btn-success {
|
||||||
|
background-color: #2e8b57; /* Money green color */
|
||||||
|
border-color: #2e8b57;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar .btn-success:hover {
|
||||||
|
background-color: #267349;
|
||||||
|
border-color: #267349;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar .btn-warning {
|
||||||
|
background-color: #ffc107;
|
||||||
|
border-color: #ffc107;
|
||||||
|
color: #212529;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar .btn-warning:hover {
|
||||||
|
background-color: #e0a800;
|
||||||
|
border-color: #e0a800;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar .btn-danger {
|
||||||
|
background-color: #dc3545;
|
||||||
|
border-color: #dc3545;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar .btn-danger:hover {
|
||||||
|
background-color: #c82333;
|
||||||
|
border-color: #c82333;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Dev Tools button styling */
|
||||||
|
.sidebar .btn-info {
|
||||||
|
background-color: #00bfff; /* Neon blue color */
|
||||||
|
border-color: #00bfff;
|
||||||
|
color: white;
|
||||||
|
box-shadow: 0 0 10px rgba(0, 191, 255, 0.5); /* Neon glow effect */
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar .btn-info:hover {
|
||||||
|
background-color: #0099cc;
|
||||||
|
border-color: #0099cc;
|
||||||
|
box-shadow: 0 0 15px rgba(0, 191, 255, 0.7); /* Enhanced glow on hover */
|
||||||
}
|
}
|
114
views/admin.html
114
views/admin.html
@ -19,15 +19,41 @@
|
|||||||
<h2 class="fs-5 text-dark fw-bold mb-2">Doug Masiero</h2>
|
<h2 class="fs-5 text-dark fw-bold mb-2">Doug Masiero</h2>
|
||||||
<h3 class="fs-6 text-muted mb-2">30 Minute Meeting</h3>
|
<h3 class="fs-6 text-muted mb-2">30 Minute Meeting</h3>
|
||||||
<p class="text-muted fs-6">30 min</p>
|
<p class="text-muted fs-6">30 min</p>
|
||||||
|
|
||||||
|
<div class="d-grid gap-3 w-100 mt-4">
|
||||||
|
<button class="btn btn-success btn-lg rounded-pill fw-medium px-3 py-2" id="createUid" style="height: 50px; font-size: 1rem;">Create</button>
|
||||||
|
<button class="btn btn-warning btn-lg rounded-pill fw-medium px-3 py-2" id="flushDatabase" disabled style="height: 50px; font-size: 1rem;">Clear</button>
|
||||||
|
<button class="btn btn-danger btn-lg rounded-pill fw-medium px-3 py-2" id="deleteUid" disabled style="height: 50px; font-size: 1rem;">Delete</button>
|
||||||
|
<button class="btn btn-info btn-lg rounded-pill fw-medium px-3 py-2" id="devToolsBtn" style="height: 50px; font-size: 1rem;">Dev Tools</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-8 main-content p-4">
|
</div>
|
||||||
<div class="calendar-header d-flex justify-content-between align-items-center text-dark fs-5 mb-3">
|
<div class="col-md-8 main-content p-4" style="min-height: 600px; position: relative;">
|
||||||
|
<div class="uid-section mb-4">
|
||||||
|
<h2 class="fs-4 text-dark fw-bold mb-3">Manage Schedule UIDs</h2>
|
||||||
|
<div class="row g-3 mb-4">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<select class="form-select form-select-lg" id="uidSelect">
|
||||||
|
<option value="">Select a Schedule UID...</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row g-3 mb-4">
|
||||||
|
<div class="col-12">
|
||||||
|
<div class="form-control-lg bg-light p-3">
|
||||||
|
<small class="d-block text-muted mb-1">Public Access URL:</small>
|
||||||
|
<span id="uidPlaceholder" class="text-muted">Select a UID above</span>
|
||||||
|
<a id="uidUrl" href="#" target="_blank" class="text-decoration-none text-break text-primary d-none">Select a UID above</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="calendar-header d-flex justify-content-between align-items-center text-dark fs-5 mb-3 d-none" id="calendarSection">
|
||||||
<button id="adminPrevMonth" class="btn btn-link p-0 text-decoration-none"><i class="bi bi-chevron-left"></i></button>
|
<button id="adminPrevMonth" class="btn btn-link p-0 text-decoration-none"><i class="bi bi-chevron-left"></i></button>
|
||||||
<span id="adminMonthYear" class="fw-bold"></span>
|
<span id="adminMonthYear" class="fw-bold"></span>
|
||||||
<button id="adminNextMonth" class="btn btn-link p-0 text-decoration-none"><i class="bi bi-chevron-right"></i></button>
|
<button id="adminNextMonth" class="btn btn-link p-0 text-decoration-none"><i class="bi bi-chevron-right"></i></button>
|
||||||
</div>
|
</div>
|
||||||
<div class="calendar mb-4">
|
<div class="calendar mb-4 d-none" id="calendarDatesSection">
|
||||||
<div class="days-of-week d-grid gap-2 mb-2" style="grid-template-columns: repeat(7, 1fr);">
|
<div class="days-of-week d-grid gap-2 mb-2" style="grid-template-columns: repeat(7, 1fr);">
|
||||||
<span class="text-muted fw-bold text-center p-2">SUN</span>
|
<span class="text-muted fw-bold text-center p-2">SUN</span>
|
||||||
<span class="text-muted fw-bold text-center p-2">MON</span>
|
<span class="text-muted fw-bold text-center p-2">MON</span>
|
||||||
@ -41,48 +67,14 @@
|
|||||||
<!-- Dates will be dynamically generated by JavaScript -->
|
<!-- Dates will be dynamically generated by JavaScript -->
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="uid-section mb-4">
|
|
||||||
<h2 class="fs-4 text-dark fw-bold mb-3">Manage Schedule UIDs</h2>
|
|
||||||
<div class="row g-3 mb-4">
|
|
||||||
<div class="col-md-6">
|
|
||||||
<select class="form-select form-select-lg" id="uidSelect">
|
|
||||||
<option value="">Select a Schedule UID...</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-3">
|
|
||||||
<button class="btn btn-warning btn-lg w-100" id="flushDatabase" disabled>Clear UID</button>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-3">
|
|
||||||
<button class="btn btn-danger btn-lg w-100" id="deleteUid" disabled>Delete UID</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row g-3 mb-4">
|
|
||||||
<div class="col-md-9">
|
|
||||||
<div class="mb-2">
|
|
||||||
<div class="input-group input-group-lg gap-2">
|
|
||||||
<input type="text" class="form-control" id="newUid" placeholder="Enter new UID (e.g., john-1on1)">
|
|
||||||
<button class="btn btn-success" id="createUid" style="min-width: 120px;">Create UID</button>
|
|
||||||
</div>
|
|
||||||
<div class="form-text">UIDs should be lowercase letters, numbers, and hyphens only</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row g-3 mb-4">
|
|
||||||
<div class="col-12">
|
|
||||||
<div class="form-control-lg bg-light p-3">
|
|
||||||
<small class="d-block text-muted mb-1">Selected UID URL:</small>
|
|
||||||
<a id="uidUrl" href="#" target="_blank" class="text-decoration-none text-break">Select a UID first</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="availability-section">
|
<div class="availability-section d-none" id="availabilitySection">
|
||||||
<div id="selectedDateDisplay" class="mb-3 text-muted fs-6"></div>
|
<div id="selectedDateDisplay" class="mb-3 text-muted fs-6"></div>
|
||||||
<div class="time-grid mb-3">
|
<div class="time-grid mb-3">
|
||||||
<div class="time-slots" id="timeSlots">
|
<div id="timeSlots" class="time-slots mb-4">
|
||||||
<!-- Time slots will be dynamically populated by JavaScript -->
|
<!-- Time slots will be dynamically populated here -->
|
||||||
|
<!-- The new time picker and time slot management UI will be inserted here -->
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -93,7 +85,15 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="container-fluid p-0">
|
<!-- Dev Tools Modal -->
|
||||||
|
<div class="modal fade" id="devToolsModal" tabindex="-1" aria-labelledby="devToolsModalLabel" aria-hidden="true">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header bg-info text-white">
|
||||||
|
<h5 class="modal-title" id="devToolsModalLabel">Developer Tools</h5>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
<div class="danger-zone border border-danger rounded p-4">
|
<div class="danger-zone border border-danger rounded p-4">
|
||||||
<h2 class="fs-4 text-danger fw-bold mb-3">⚠️ Danger Zone</h2>
|
<h2 class="fs-4 text-danger fw-bold mb-3">⚠️ Danger Zone</h2>
|
||||||
<p class="text-muted mb-4">The actions in this section can cause irreversible changes to the database. Please proceed with caution.</p>
|
<p class="text-muted mb-4">The actions in this section can cause irreversible changes to the database. Please proceed with caution.</p>
|
||||||
@ -101,10 +101,40 @@
|
|||||||
<div class="text-muted">This will permanently delete all UIDs and their associated availability data.</div>
|
<div class="text-muted">This will permanently delete all UIDs and their associated availability data.</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Create UID Modal -->
|
||||||
|
<div class="modal fade" id="createUidModal" tabindex="-1" aria-labelledby="createUidModalLabel" aria-hidden="true">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title" id="createUidModalLabel">Create New UID</h5>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="modalUidInput" class="form-label">Enter new UID</label>
|
||||||
|
<input type="text" class="form-control" id="modalUidInput" placeholder="e.g., john-1on1">
|
||||||
|
<div class="form-text">UIDs should be lowercase letters, numbers, and hyphens only</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||||
|
<button type="button" class="btn btn-success" id="confirmCreateUid">Create</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Bootstrap JS and Popper.js -->
|
<!-- Bootstrap JS and Popper.js -->
|
||||||
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.8/dist/umd/popper.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.8/dist/umd/popper.min.js"></script>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.min.js"></script>
|
||||||
|
|
||||||
<script src="/admin.js"></script>
|
<script src="/admin.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
Loading…
Reference in New Issue
Block a user