filename:
views/public/schedule.php
branch:
main
back to repo
<?php
$pageTitle = "Schedule – Seven O'Clock Dinner Club";
// Simple calendar representation: always highlight 7pm dinners.
?>
<?php
// Optional RSVP shortcut: ?rsvp=today (used by the main page button).
// Use a single timezone reference throughout the page to avoid "day off by one" issues.
// Default to New York, but allow overriding during development (e.g. Los Angeles).
$tzName = getenv('APP_TIMEZONE') ?: 'America/New_York';
$tz = new DateTimeZone($tzName);
// Current date boundary in the app's timezone.
$now = new DateTimeImmutable('now', $tz);
$today = $now->setTime(0, 0, 0);
if (!empty($_GET['rsvp']) && isLoggedIn() && $_GET['rsvp'] === 'today') {
$dateStr = $today->format('Y-m-d');
$nowStr = (new DateTimeImmutable('now'))->format('Y-m-d H:i:s');
$stmt = $db->prepare('
INSERT INTO rsvps (user_id, dinner_date, created_at)
VALUES (?, ?, ?)
ON DUPLICATE KEY UPDATE created_at = VALUES(created_at)
');
$uid = (int)currentUserId();
$stmt->bind_param('iss', $uid, $dateStr, $nowStr);
$stmt->execute();
// Avoid repeat RSVP on refresh.
header('Location: ' . url('schedule'));
exit;
}
?>
<section class="page-grid">
<div class="card" data-animate-initial>
<div class="muted" style="font-size: 11px; letter-spacing: 0.18em; text-transform: uppercase; margin-bottom: 10px;">
Calendar
</div>
<h1 style="font-family: 'Georgia', 'Times New Roman', serif; font-weight: 400; font-size: 26px; margin: 0 0 12px;">
Give or take ~15 minutes.
</h1>
</div>
<div class="card" data-animate>
<div class="muted" style="font-size: 12px; text-transform: uppercase; letter-spacing: 0.18em; margin-bottom: 10px;">
This month at a glance
</div>
<div style="display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 6px; font-size: 12px;">
<?php
$daysOfWeek = ['Mon','Tue','Wed','Thu','Fri','Sat','Sun'];
foreach ($daysOfWeek as $dow): ?>
<div class="muted" style="text-align: center; padding-bottom: 4px; border-bottom: 1px solid rgba(0,0,0,0.06);">
<?= htmlspecialchars($dow, ENT_QUOTES, 'UTF-8') ?>
</div>
<?php endforeach; ?>
<?php
$firstOfMonth = $today->modify('first day of this month');
$startDow = (int)$firstOfMonth->format('N'); // 1 (Mon) - 7 (Sun)
for ($i = 1; $i < $startDow; $i++): ?>
<div></div>
<?php endfor;
$daysInMonth = (int)$today->format('t');
for ($day = 1; $day <= $daysInMonth; $day++):
$date = $firstOfMonth->setDate((int)$firstOfMonth->format('Y'), (int)$firstOfMonth->format('m'), $day);
$isToday = $date->format('Y-m-d') === $today->format('Y-m-d');
?>
<div style="border-radius: 10px; padding: 8px 4px; text-align: center; border: 1px solid <?= $isToday ? 'rgba(178,146,99,0.85)' : 'rgba(0,0,0,0.04)' ?>; background: <?= $isToday ? 'rgba(178,146,99,0.22)' : 'rgba(255,255,255,0.7)' ?>; position: relative;">
<div style="font-size: 12px;"><?= $day ?></div>
<div style="margin-top: 4px; font-size: 10px; text-transform: uppercase; letter-spacing: 0.14em;" class="muted">
7 pm
</div>
</div>
<?php endfor; ?>
</div>
<p class="muted" style="margin-top: 14px; font-size: 12px;">
Any changes to the schedule will be communicated.
</p>
</div>
</section>
<?php
// Render today's RSVP list.
$todayStr = $today->format('Y-m-d');
$rsvpStmt = $db->prepare('
SELECT m.display_name, m.photo_url, u.id AS user_id
FROM rsvps r
JOIN users u ON u.id = r.user_id
JOIN member_profiles m ON m.user_id = u.id
WHERE r.dinner_date = ?
ORDER BY r.created_at DESC, u.id ASC
');
$rsvpStmt->bind_param('s', $todayStr);
$rsvpStmt->execute();
$rsvps = $rsvpStmt->get_result()->fetch_all(MYSQLI_ASSOC);
$myRsvpStmt = null;
$myRsvp = false;
if (isLoggedIn()) {
$myRsvpStmt = $db->prepare('SELECT 1 FROM rsvps WHERE user_id = ? AND dinner_date = ? LIMIT 1');
$myUid = (int)currentUserId();
$myRsvpStmt->bind_param('is', $myUid, $todayStr);
$myRsvpStmt->execute();
$myRsvp = (bool)($myRsvpStmt->get_result()->fetch_assoc());
}
?>
<?php
// Render chat messages for the current date (last 24 hours).
$chatFromTs = $now->modify('-24 hours')->format('Y-m-d H:i:s');
$chatStmt = $db->prepare('
SELECT
c.user_id,
m.display_name,
m.photo_url,
c.body,
c.created_at
FROM chat_messages c
JOIN member_profiles m ON m.user_id = c.user_id
WHERE c.dinner_date = ?
AND c.created_at >= ?
ORDER BY c.created_at DESC, c.id DESC
');
$chatStmt->bind_param('ss', $todayStr, $chatFromTs);
$chatStmt->execute();
$initialMessages = $chatStmt->get_result()->fetch_all(MYSQLI_ASSOC);
?>
<section class="page-grid" style="margin-top: 18px;">
<div class="card" data-animate-initial id="rsvp-today">
<div class="muted" style="font-size: 11px; letter-spacing: 0.18em; text-transform: uppercase; margin-bottom: 10px;">
RSVPs for today
</div>
<?php if (isLoggedIn()): ?>
<div style="display:flex; flex-wrap:wrap; align-items:baseline; justify-content:space-between; gap: 12px; margin-bottom: 10px;">
<h1 style="font-family: 'Georgia', 'Times New Roman', serif; font-weight: 400; font-size: 22px; margin: 0;">
<?= htmlspecialchars($today->format('F j, Y'), ENT_QUOTES, 'UTF-8') ?>
</h1>
<?php if ($myRsvp): ?>
<span
class="pill"
style="background: rgba(72, 150, 90, 0.18); border: 1px solid rgba(72,150,90,0.55); color: inherit; cursor: not-allowed; white-space:nowrap;"
aria-disabled="true"
>
You're in
</span>
<?php else: ?>
<a
href="<?= htmlspecialchars(url('schedule?rsvp=today'), ENT_QUOTES, 'UTF-8') ?>"
class="pill pill-accent"
style="border-style: dashed; text-decoration:none; white-space:nowrap;"
>
RSVP Today
</a>
<?php endif; ?>
</div>
<?php endif; ?>
<?php if (!isLoggedIn()): ?>
<h1 style="font-family: 'Georgia', 'Times New Roman', serif; font-weight: 400; font-size: 22px; margin: 0 0 10px;">
<?= htmlspecialchars($today->format('F j, Y'), ENT_QUOTES, 'UTF-8') ?>
</h1>
<?php endif; ?>
<?php if ($rsvps): ?>
<div style="display:flex; flex-wrap:wrap; gap: 10px;">
<?php foreach ($rsvps as $r): ?>
<?php $memberUserId = (int)($r['user_id'] ?? 0); ?>
<?php if ($memberUserId > 0): ?>
<a
href="<?= htmlspecialchars(url('members?user_id=' . $memberUserId), ENT_QUOTES, 'UTF-8') ?>"
style="display:flex; align-items:center; gap: 8px; padding: 8px 10px; border-radius: 12px; border: 1px solid rgba(0,0,0,0.06); background: rgba(255,255,255,0.65); text-decoration:none; color: inherit;"
aria-label="View <?= htmlspecialchars($r['display_name'] ?? 'member', ENT_QUOTES, 'UTF-8') ?> on members page"
>
<?php $photo = $r['photo_url'] ?? null; ?>
<?php if (!empty($photo)): ?>
<img src="<?= htmlspecialchars($photo, ENT_QUOTES, 'UTF-8') ?>" alt="" style="width: 28px; height: 28px; border-radius: 999px; object-fit: cover; border: 1px solid rgba(0,0,0,0.08);">
<?php else: ?>
<div aria-hidden="true" style="width: 28px; height: 28px; border-radius: 999px; background: rgba(0,0,0,0.06); border: 1px solid rgba(0,0,0,0.08);"></div>
<?php endif; ?>
<div style="display:flex; flex-direction:column; line-height:1.2;">
<div style="font-size: 12px; font-weight: 500;">
<?= htmlspecialchars($r['display_name'] ?? 'Unknown', ENT_QUOTES, 'UTF-8') ?>
<?php if (isLoggedIn() && (int)($r['user_id'] ?? 0) === (int)currentUserId()): ?>
<span class="muted" style="font-size: 10px;">(you)</span>
<?php endif; ?>
</div>
</div>
</a>
<?php else: ?>
<div style="display:flex; align-items:center; gap: 8px; padding: 8px 10px; border-radius: 12px; border: 1px solid rgba(0,0,0,0.06); background: rgba(255,255,255,0.65);">
<div class="muted" style="font-size: 12px;">Unknown member</div>
</div>
<?php endif; ?>
<?php endforeach; ?>
</div>
<?php else: ?>
<p class="muted" style="font-size: 13px; margin: 0;">
No RSVPs yet for today.
</p>
<?php endif; ?>
<?php if (!isLoggedIn()): ?>
<div class="muted" style="margin-top: 8px; font-size: 12px;">
Sign in to RSVP.
</div>
<?php endif; ?>
</div>
</section>
<section class="page-grid" style="margin-top: 18px;">
<div class="card" data-animate-initial>
<div class="muted" style="font-size: 11px; letter-spacing: 0.18em; text-transform: uppercase; margin-bottom: 10px;">
Chat
</div>
<div id="chat-messages"
style="max-height: 320px; overflow:auto; padding: 12px; border-radius: 14px; border: 1px solid rgba(0,0,0,0.08); background: rgba(255,255,255,0.7); display:flex; flex-direction:column; gap: 10px;">
<?php if (!$initialMessages): ?>
<div class="muted" style="font-size: 13px;">No messages yet.</div>
<?php else: ?>
<?php foreach ($initialMessages as $m): ?>
<div style="display:flex; align-items:flex-start; gap: 10px; padding: 10px 10px; border-radius: 12px; border: 1px solid rgba(0,0,0,0.06); background: rgba(255,255,255,0.65);">
<?php $photo = $m['photo_url'] ?? null; ?>
<?php if (!empty($photo)): ?>
<div style="width:30px; height:30px; border-radius:999px; overflow:hidden; background:rgba(0,0,0,0.06); border:1px solid rgba(0,0,0,0.08); flex:0 0 auto;">
<img src="<?= htmlspecialchars($photo, ENT_QUOTES, 'UTF-8') ?>" alt="" style="width:100%; height:100%; object-fit:cover;">
</div>
<?php else: ?>
<div style="width:30px; height:30px; border-radius:999px; background:rgba(0,0,0,0.06); border:1px solid rgba(0,0,0,0.08); flex:0 0 auto; display:flex; align-items:center; justify-content:center; font-family:'Georgia','Times New Roman',serif; font-size:14px;">
<?= htmlspecialchars(strtoupper(mb_substr($m['display_name'] ?? '?', 0, 1)), ENT_QUOTES, 'UTF-8') ?>
</div>
<?php endif; ?>
<div style="flex:1; min-width:0;">
<div style="display:flex; align-items:flex-start; justify-content:space-between; gap:12px; margin-bottom:3px;">
<div style="font-size:12px; font-weight:600;">
<?= htmlspecialchars($m['display_name'] ?? 'Unknown', ENT_QUOTES, 'UTF-8') ?>
</div>
<div class="muted" style="font-size:11px; margin-top:1px; text-align:right; white-space:nowrap;">
<?= htmlspecialchars((new DateTimeImmutable($m['created_at']))->format('M j, Y g:i A'), ENT_QUOTES, 'UTF-8') ?>
</div>
</div>
<div style="font-size:13px; line-height:1.5;">
<?= nl2br(htmlspecialchars($m['body'] ?? '', ENT_QUOTES, 'UTF-8')) ?>
</div>
</div>
</div>
<?php endforeach; ?>
<?php endif; ?>
</div>
<div style="margin-top: 12px; display:flex; gap: 10px; align-items:flex-start;">
<?php if (isLoggedIn()): ?>
<form id="chat-send-form"
method="POST"
action="<?= htmlspecialchars(url('api/chat-send'), ENT_QUOTES, 'UTF-8') ?>"
style="flex:1; display:flex; gap: 10px; align-items:flex-start;">
<input type="hidden" name="dinner_date" value="<?= htmlspecialchars($todayStr, ENT_QUOTES, 'UTF-8') ?>">
<textarea name="body" rows="2" maxlength="2000" required
placeholder="Write a message…"
style="flex:1; resize: vertical; min-height: 42px; padding: 10px 12px; border-radius: 14px; border: 1px solid rgba(0,0,0,0.12); background: rgba(255,255,255,0.85);"></textarea>
<button type="submit" class="pill pill-accent" style="align-self:stretch; padding: 10px 14px; white-space: nowrap;">
Send
</button>
</form>
<?php else: ?>
<div class="muted" style="font-size: 13px;">
Sign in to send messages.
</div>
<?php endif; ?>
</div>
</div>
</section>
<?php
// Chat is server-rendered on page load for reliability.
// If we re-introduce polling later, we can do it in a dedicated block.
?>