Significant admin UI improvements

This commit is contained in:
Doug Masiero 2025-02-25 00:27:29 -05:00
parent f015a90791
commit bc5a8e0305
8 changed files with 910 additions and 270 deletions

Binary file not shown.

1
pages/index.js Normal file
View File

@ -0,0 +1 @@

File diff suppressed because it is too large Load Diff

1
public/index.html Normal file
View File

@ -0,0 +1 @@

View File

@ -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 {

View File

@ -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

View File

@ -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 */
} }

View File

@ -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>
<div class="col-md-8 main-content p-4"> <div class="col-md-8 main-content p-4" style="min-height: 600px; position: relative;">
<div class="calendar-header d-flex justify-content-between align-items-center text-dark fs-5 mb-3"> <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,18 +85,56 @@
</div> </div>
</div> </div>
<div class="container-fluid p-0"> <!-- Dev Tools Modal -->
<div class="danger-zone border border-danger rounded p-4"> <div class="modal fade" id="devToolsModal" tabindex="-1" aria-labelledby="devToolsModalLabel" aria-hidden="true">
<h2 class="fs-4 text-danger fw-bold mb-3">⚠️ Danger Zone</h2> <div class="modal-dialog">
<p class="text-muted mb-4">The actions in this section can cause irreversible changes to the database. Please proceed with caution.</p> <div class="modal-content">
<button class="btn btn-outline-danger w-100 mb-2" id="resetDatabase">Reset Global Database</button> <div class="modal-header bg-info text-white">
<div class="text-muted">This will permanently delete all UIDs and their associated availability data.</div> <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">
<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>
<button class="btn btn-outline-danger w-100 mb-2" id="resetDatabase">Reset Global Database</button>
<div class="text-muted">This will permanently delete all UIDs and their associated availability data.</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>
</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>