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:
+250
@@ -0,0 +1,250 @@
|
||||
<?php
|
||||
/**
|
||||
* admin/setup.php — Create or edit a rosary session.
|
||||
*/
|
||||
require_once __DIR__ . '/../config/db.php';
|
||||
require_once __DIR__ . '/../includes/auth.php';
|
||||
|
||||
require_auth();
|
||||
|
||||
$pdo = get_pdo();
|
||||
$user = current_user();
|
||||
$uid = (int)$user['id'];
|
||||
$site_name = get_setting('site_name', APP_NAME);
|
||||
|
||||
// Load existing session for editing
|
||||
$session = null;
|
||||
if (isset($_GET['id'])) {
|
||||
$stmt = $pdo->prepare('SELECT * FROM sessions WHERE id = ?');
|
||||
$stmt->execute([(int)$_GET['id']]);
|
||||
$session = $stmt->fetch();
|
||||
if (!$session) {
|
||||
header('Location: ' . BASE_URL . '/admin/');
|
||||
exit;
|
||||
}
|
||||
// Ownership check: must own or be admin
|
||||
if (!has_role('admin') && (int)$session['user_id'] !== $uid) {
|
||||
header('Location: ' . BASE_URL . '/admin/');
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
// Creating new session? Check rosary limit
|
||||
$limit_error = '';
|
||||
if (!$session && !can_create_rosary($uid, $user['rosary_limit'])) {
|
||||
$limit = $user['rosary_limit'];
|
||||
$limit_error = "You have reached your rosary limit ({$limit}). Please contact an administrator to increase your limit.";
|
||||
}
|
||||
|
||||
$page_title = $session ? 'Edit Session' : 'New Session';
|
||||
?>
|
||||
<!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><?= $page_title ?> — <?= htmlspecialchars($site_name) ?></title>
|
||||
<link rel="stylesheet" href="<?= BASE_URL ?>/assets/css/setup.css">
|
||||
<script>var BASE_URL = '<?= BASE_URL ?>';</script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="admin-container">
|
||||
<header class="admin-header">
|
||||
<h1>✝ <?= htmlspecialchars($site_name) ?></h1>
|
||||
<div class="header-actions">
|
||||
<a href="<?= BASE_URL ?>/" class="btn btn-ghost" style="font-size:13px">← View Site</a>
|
||||
<?php if (has_role('admin')): ?>
|
||||
<a href="<?= BASE_URL ?>/admin/users.php" class="btn btn-ghost">Users</a>
|
||||
<?php endif; ?>
|
||||
<?php if (has_role('superadmin')): ?>
|
||||
<a href="<?= BASE_URL ?>/admin/settings.php" class="btn btn-ghost">Settings</a>
|
||||
<?php endif; ?>
|
||||
<a href="<?= BASE_URL ?>/admin/profile.php" class="btn btn-ghost"><?= htmlspecialchars($user['display_name'] ?: $user['username']) ?></a>
|
||||
<a href="<?= BASE_URL ?>/admin/" class="btn btn-ghost">← Back</a>
|
||||
<a href="<?= BASE_URL ?>/logout" class="btn btn-ghost">Logout</a>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<h2><?= $page_title ?></h2>
|
||||
|
||||
<?php if ($limit_error): ?>
|
||||
<div class="alert alert-error"><?= htmlspecialchars($limit_error) ?></div>
|
||||
<?php else: ?>
|
||||
|
||||
<div id="form-message" class="alert" style="display:none"></div>
|
||||
|
||||
<form id="session-form" novalidate>
|
||||
<?php if ($session): ?>
|
||||
<input type="hidden" name="id" value="<?= (int)$session['id'] ?>">
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- Session Name -->
|
||||
<div class="form-group">
|
||||
<label for="name">Session Label <span class="required">*</span></label>
|
||||
<input type="text" id="name" name="name"
|
||||
placeholder="e.g. Medy"
|
||||
value="<?= htmlspecialchars($session['name'] ?? '') ?>"
|
||||
required>
|
||||
<p class="help-text" id="name-help">
|
||||
For novena: enter just the name (e.g. "Medy") — sessions will be created as
|
||||
"Medy — Day 1" through "Medy — Day 9".
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Occasion -->
|
||||
<div class="form-group">
|
||||
<label for="occasion">Occasion <span class="required">*</span></label>
|
||||
<select id="occasion" name="occasion" required>
|
||||
<option value="">— Select —</option>
|
||||
<option value="novena_deceased"
|
||||
<?= ($session['occasion'] ?? '') === 'novena_deceased' ? 'selected' : '' ?>>
|
||||
Novena for Deceased
|
||||
</option>
|
||||
<option value="divine_mercy_novena"
|
||||
<?= ($session['occasion'] ?? '') === 'divine_mercy_novena' ? 'selected' : '' ?>>
|
||||
Divine Mercy Novena
|
||||
</option>
|
||||
<option value="general_rosary"
|
||||
<?= ($session['occasion'] ?? '') === 'general_rosary' ? 'selected' : '' ?>>
|
||||
General Rosary
|
||||
</option>
|
||||
<option value="memorial"
|
||||
<?= ($session['occasion'] ?? '') === 'memorial' ? 'selected' : '' ?>>
|
||||
Memorial / Month's Mind
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- Mystery Set (non-novena) -->
|
||||
<div class="form-group" id="field-mystery_set_standard">
|
||||
<label for="mystery_set">Mystery Set <span class="required">*</span></label>
|
||||
<select id="mystery_set" name="mystery_set" required>
|
||||
<option value="">— Select —</option>
|
||||
<option value="sorrowful"
|
||||
<?= ($session['mystery_set'] ?? '') === 'sorrowful' ? 'selected' : '' ?>>
|
||||
Sorrowful Mysteries
|
||||
</option>
|
||||
<option value="joyful"
|
||||
<?= ($session['mystery_set'] ?? '') === 'joyful' ? 'selected' : '' ?>>
|
||||
Joyful Mysteries
|
||||
</option>
|
||||
<option value="glorious"
|
||||
<?= ($session['mystery_set'] ?? '') === 'glorious' ? 'selected' : '' ?>>
|
||||
Glorious Mysteries
|
||||
</option>
|
||||
<option value="luminous"
|
||||
<?= ($session['mystery_set'] ?? '') === 'luminous' ? 'selected' : '' ?>>
|
||||
Luminous Mysteries
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- Novena Mystery Mode (only shown for novena_deceased) -->
|
||||
<div class="form-group conditional-field" id="field-novena_mystery_mode" style="display:none">
|
||||
<label for="novena_mystery_mode">Mysteries for this Novena <span class="required">*</span></label>
|
||||
<select id="novena_mystery_mode" name="novena_mystery_mode">
|
||||
<option value="all_sorrowful"
|
||||
<?= ($session['mystery_set'] ?? '') === 'sorrowful' || ($session['mystery_set'] ?? '') === 'all_sorrowful' ? 'selected' : '' ?>>
|
||||
All Sorrowful (traditional for deceased)
|
||||
</option>
|
||||
<option value="by_day_of_week"
|
||||
<?= ($session['mystery_set'] ?? '') === 'by_day_of_week' ? 'selected' : '' ?>>
|
||||
By Day of Week — auto-selected at presentation time
|
||||
</option>
|
||||
</select>
|
||||
<p class="help-text">
|
||||
Day-of-week schedule: Sun & Wed = Glorious · Mon & Sat = Joyful ·
|
||||
Tue & Fri = Sorrowful · Thu = Luminous
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Novena Day -->
|
||||
<div class="form-group conditional-field" id="field-novena_day" style="display:none">
|
||||
<?php if ($session): ?>
|
||||
<label>Novena Day</label>
|
||||
<div class="form-static">Day <?= (int)($session['novena_day'] ?? 1) ?> of 9</div>
|
||||
<?php else: ?>
|
||||
<div class="novena-auto-notice">
|
||||
✓ Will automatically create <strong>Day 1 through Day 9</strong>.
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<!-- Subject Name (conditional) -->
|
||||
<div class="form-group conditional-field" id="field-subject_name" style="display:none">
|
||||
<label for="subject_name">Name of Deceased / Honoree</label>
|
||||
<input type="text" id="subject_name" name="subject_name"
|
||||
placeholder="e.g. Maria Santos"
|
||||
value="<?= htmlspecialchars($session['subject_name'] ?? '') ?>">
|
||||
</div>
|
||||
|
||||
<!-- Pronoun (conditional) -->
|
||||
<div class="form-group conditional-field" id="field-subject_pronoun" style="display:none">
|
||||
<label for="subject_pronoun">Pronoun</label>
|
||||
<select id="subject_pronoun" name="subject_pronoun">
|
||||
<option value="he"
|
||||
<?= ($session['subject_pronoun'] ?? 'he') === 'he' ? 'selected' : '' ?>>
|
||||
He / Him / His
|
||||
</option>
|
||||
<option value="she"
|
||||
<?= ($session['subject_pronoun'] ?? '') === 'she' ? 'selected' : '' ?>>
|
||||
She / Her / Her
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- Dates (conditional) -->
|
||||
<div class="form-group conditional-field" id="field-subject_dates" style="display:none">
|
||||
<label for="subject_dates">Life Dates</label>
|
||||
<input type="text" id="subject_dates" name="subject_dates"
|
||||
placeholder="e.g. Aug 12, 1949 – July 25, 2025"
|
||||
value="<?= htmlspecialchars($session['subject_dates'] ?? '') ?>">
|
||||
</div>
|
||||
|
||||
<!-- Photo -->
|
||||
<div class="form-group" id="field-photo">
|
||||
<label for="photo">Photo (optional)</label>
|
||||
<?php if (!empty($session['photo_path'])): ?>
|
||||
<div class="photo-preview">
|
||||
<img src="<?= htmlspecialchars('/' . ltrim($session['photo_path'], '/')) ?>"
|
||||
alt="Current photo" style="max-height:120px">
|
||||
<p class="help-text">Current photo. Upload a new one to replace it.</p>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<input type="file" id="photo" name="photo" accept="image/*">
|
||||
<p class="help-text">JPEG, PNG, WebP — max 5 MB. Recommended: square or landscape, at least 800 × 600 px. Shown on the home page card and cover slide.</p>
|
||||
<input type="hidden" id="photo_path" name="photo_path"
|
||||
value="<?= htmlspecialchars($session['photo_path'] ?? '') ?>">
|
||||
<div id="upload-status" style="display:none" class="upload-status"></div>
|
||||
</div>
|
||||
|
||||
<!-- Public toggle -->
|
||||
<div class="form-group">
|
||||
<label style="display:flex;align-items:center;gap:10px;cursor:pointer">
|
||||
<input type="checkbox" name="is_public" value="1"
|
||||
<?= (!$session || $session['is_public']) ? 'checked' : '' ?>
|
||||
style="width:18px;height:18px">
|
||||
<span>Make this session public (visible on your profile and the home page)</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="form-actions">
|
||||
<button type="submit" class="btn btn-primary btn-large" id="submit-btn"
|
||||
data-label-default="<?= $session ? 'Save Changes' : 'Create Session' ?>"
|
||||
data-label-novena-deceased="<?= $session ? 'Save Changes' : 'Create 9-Day Novena' ?>"
|
||||
data-label-divine-mercy="<?= $session ? 'Save Changes' : 'Create Divine Mercy Novena' ?>">
|
||||
<?= $session ? 'Save Changes' : 'Create Session' ?>
|
||||
</button>
|
||||
<a href="<?= BASE_URL ?>/admin/" class="btn btn-ghost">Cancel</a>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<?php endif; ?>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<script src="<?= BASE_URL ?>/assets/js/setup.js?v=5"></script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user