Initial commit — Rosary Presenter App
Full source for loveandrosary.com: slide-based Rosary/novena/Divine Mercy Chaplet presentation tool with multi-user roles, SVG bead ring, audio uploads, donate strip, and public session profiles. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,145 @@
|
||||
<?php
|
||||
/**
|
||||
* novena_public.php — Public day-picker for a 9-day novena group.
|
||||
* Linked from index.php when a visitor clicks a novena card.
|
||||
*/
|
||||
require_once __DIR__ . '/config/db.php';
|
||||
require_once __DIR__ . '/includes/auth.php';
|
||||
require_once __DIR__ . '/includes/donate.php';
|
||||
|
||||
_auth_start();
|
||||
$pdo = get_pdo();
|
||||
$site_name = get_setting('site_name', APP_NAME);
|
||||
$logged_in = !empty($_SESSION['user_id']);
|
||||
|
||||
// Resolve group: ?group_id=X OR ?username=X&slug=Y
|
||||
$group = null;
|
||||
if (isset($_GET['group_id'])) {
|
||||
$stmt = $pdo->prepare('
|
||||
SELECT ng.*, u.username, u.display_name
|
||||
FROM novena_groups ng
|
||||
JOIN users u ON u.id = ng.user_id
|
||||
WHERE ng.id = ? AND ng.is_public = 1
|
||||
');
|
||||
$stmt->execute([(int)$_GET['group_id']]);
|
||||
$group = $stmt->fetch();
|
||||
} elseif (isset($_GET['username'], $_GET['slug'])) {
|
||||
$stmt = $pdo->prepare('
|
||||
SELECT ng.*, u.username, u.display_name
|
||||
FROM novena_groups ng
|
||||
JOIN users u ON u.id = ng.user_id
|
||||
WHERE u.username = ? AND ng.slug = ? AND ng.is_public = 1
|
||||
');
|
||||
$stmt->execute([$_GET['username'], $_GET['slug']]);
|
||||
$group = $stmt->fetch();
|
||||
}
|
||||
|
||||
if (!$group) {
|
||||
http_response_code(404);
|
||||
die('Novena not found.');
|
||||
}
|
||||
|
||||
// Load all available days
|
||||
$days_stmt = $pdo->prepare('
|
||||
SELECT id, novena_day, mystery_set, slug
|
||||
FROM sessions
|
||||
WHERE novena_group_id = ?
|
||||
ORDER BY novena_day
|
||||
');
|
||||
$days_stmt->execute([$group['id']]);
|
||||
$days_rows = $days_stmt->fetchAll();
|
||||
|
||||
$days_by_num = [];
|
||||
foreach ($days_rows as $d) {
|
||||
$days_by_num[(int)$d['novena_day']] = $d;
|
||||
}
|
||||
|
||||
$mystery_labels = [
|
||||
'sorrowful' => 'Sorrowful Mysteries',
|
||||
'joyful' => 'Joyful Mysteries',
|
||||
'glorious' => 'Glorious Mysteries',
|
||||
'luminous' => 'Luminous Mysteries',
|
||||
'by_day_of_week' => 'By Day of Week',
|
||||
'chaplet' => 'Chaplet of Divine Mercy',
|
||||
];
|
||||
|
||||
$disp_name = $group['display_name'] ?: $group['username'];
|
||||
$photo_src = $group['photo_path'] ? ('/' . ltrim($group['photo_path'], '/')) : '';
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="icon" type="image/svg+xml" href="<?= BASE_URL ?>/favicon.svg">
|
||||
<title><?= htmlspecialchars($group['name']) ?> — <?= htmlspecialchars($site_name) ?></title>
|
||||
<link rel="stylesheet" href="<?= BASE_URL ?>/assets/css/public.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<nav class="pub-nav">
|
||||
<a href="<?= BASE_URL ?>/" class="pub-nav-brand">✝ <span><?= htmlspecialchars($site_name) ?></span></a>
|
||||
<div class="pub-nav-links">
|
||||
<?php if ($logged_in): ?>
|
||||
<a href="<?= BASE_URL ?>/admin/">Dashboard</a>
|
||||
<a href="<?= BASE_URL ?>/logout">Logout</a>
|
||||
<?php else: ?>
|
||||
<a href="<?= BASE_URL ?>/login">Sign In</a>
|
||||
<a href="<?= BASE_URL ?>/register" class="btn-nav">Get Started</a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="novena-hero">
|
||||
<?php if ($photo_src): ?>
|
||||
<div class="novena-hero-photo-wrap">
|
||||
<img class="novena-hero-photo" src="<?= htmlspecialchars($photo_src) ?>" alt="">
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<div class="novena-hero-cross">✝</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="novena-hero-text">
|
||||
<p class="novena-hero-label"><?= $group['mystery_set'] === 'chaplet' ? 'Divine Mercy Novena' : '9-Day Novena' ?></p>
|
||||
<h1 class="novena-hero-title"><?= htmlspecialchars($group['name']) ?></h1>
|
||||
<?php if ($group['subject_name']): ?>
|
||||
<p class="novena-hero-subject">For <?= htmlspecialchars($group['subject_name']) ?></p>
|
||||
<?php endif; ?>
|
||||
<?php if ($group['subject_dates']): ?>
|
||||
<p class="novena-hero-dates"><?= htmlspecialchars($group['subject_dates']) ?></p>
|
||||
<?php endif; ?>
|
||||
<p class="novena-hero-by">By <?= htmlspecialchars($disp_name) ?></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pub-section">
|
||||
<h2>Select a Day</h2>
|
||||
<div class="novena-days-grid">
|
||||
<?php for ($d = 1; $d <= 9; $d++):
|
||||
$ses = $days_by_num[$d] ?? null;
|
||||
$mysteries = $ses ? ($mystery_labels[$ses['mystery_set']] ?? $ses['mystery_set']) : null;
|
||||
$url = $ses ? (BASE_URL . '/present.php?id=' . (int)$ses['id']) : null;
|
||||
?>
|
||||
<div class="novena-day-card <?= $ses ? '' : 'novena-day-missing' ?>">
|
||||
<div class="novena-day-number">Day <?= $d ?></div>
|
||||
<?php if ($ses): ?>
|
||||
<div class="novena-day-mysteries"><?= htmlspecialchars($mysteries) ?></div>
|
||||
<a href="<?= htmlspecialchars($url) ?>" class="novena-day-link">Pray →</a>
|
||||
<?php else: ?>
|
||||
<div class="novena-day-mysteries">Not yet added</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php endfor; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php render_donate_strip(); ?>
|
||||
|
||||
<footer class="pub-footer">
|
||||
<a href="<?= BASE_URL ?>/" style="color:inherit">← All Rosaries</a>
|
||||
•
|
||||
© <?= date('Y') ?> <?= htmlspecialchars($site_name) ?>
|
||||
</footer>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user