Add Rosary Builder — custom prayer-sequence sessions
Superuser+ can now build a custom prayer sequence from scratch: - Two-panel builder UI: step sequence (left) + searchable prayer library (right) - 16 standard prayers seeded globally; users can create private custom prayers - Admin can promote private prayers to global and manage the library - Four attribution modes per step: Leader/All, Leader only, All together, None - Optional subject name/pronoun for variable substitution in prayers - Custom sessions fully presented via the existing presenter (auto-split works) - migrate_v4.php creates custom_prayers + builder_steps tables Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,264 @@
|
||||
<?php
|
||||
/**
|
||||
* admin/builder.php — Rosary Builder
|
||||
* Available to superuser, admin, superadmin.
|
||||
* Create or edit a custom prayer-sequence session.
|
||||
*/
|
||||
require_once __DIR__ . '/../config/db.php';
|
||||
require_once __DIR__ . '/../includes/auth.php';
|
||||
|
||||
require_role('superuser');
|
||||
|
||||
$pdo = get_pdo();
|
||||
$user = current_user();
|
||||
$uid = (int)$user['id'];
|
||||
$is_admin = has_role('admin');
|
||||
$site_name = get_setting('site_name', APP_NAME);
|
||||
|
||||
// ── Load existing session for edit mode ──────────────────────────────────────
|
||||
$session = null;
|
||||
$edit_steps = [];
|
||||
|
||||
if (isset($_GET['id'])) {
|
||||
$stmt = $pdo->prepare("SELECT * FROM sessions WHERE id = ? AND occasion = 'custom'");
|
||||
$stmt->execute([(int)$_GET['id']]);
|
||||
$session = $stmt->fetch();
|
||||
if (!$session) {
|
||||
header('Location: ' . BASE_URL . '/admin/');
|
||||
exit;
|
||||
}
|
||||
if (!$is_admin && (int)$session['user_id'] !== $uid) {
|
||||
header('Location: ' . BASE_URL . '/admin/');
|
||||
exit;
|
||||
}
|
||||
// Load steps with prayer data
|
||||
$step_stmt = $pdo->prepare("
|
||||
SELECT bs.prayer_id, bs.attribution,
|
||||
cp.name, cp.leader_text, cp.all_text, cp.is_global, cp.created_by,
|
||||
IF(cp.is_global=1 AND u.role='superadmin','standard',
|
||||
IF(cp.is_global=1,'global','mine')) AS source_tag
|
||||
FROM builder_steps bs
|
||||
JOIN custom_prayers cp ON cp.id = bs.prayer_id
|
||||
LEFT JOIN users u ON u.id = cp.created_by
|
||||
WHERE bs.session_id = ?
|
||||
ORDER BY bs.step_order ASC
|
||||
");
|
||||
$step_stmt->execute([(int)$session['id']]);
|
||||
$edit_steps = $step_stmt->fetchAll();
|
||||
}
|
||||
|
||||
// ── Load prayer library ───────────────────────────────────────────────────────
|
||||
$lib_stmt = $pdo->prepare("
|
||||
SELECT cp.id, cp.name, cp.leader_text, cp.all_text, cp.is_global, cp.created_by,
|
||||
IF(cp.is_global=1 AND u.role='superadmin','standard',
|
||||
IF(cp.is_global=1,'global','mine')) AS source_tag
|
||||
FROM custom_prayers cp
|
||||
LEFT JOIN users u ON u.id = cp.created_by
|
||||
WHERE cp.is_global = 1 OR cp.created_by = ?
|
||||
ORDER BY (cp.is_global=1 AND u.role='superadmin') DESC, cp.name ASC
|
||||
");
|
||||
$lib_stmt->execute([$uid]);
|
||||
$prayers_data = $lib_stmt->fetchAll();
|
||||
|
||||
$page_title = $session ? 'Edit: ' . htmlspecialchars($session['name']) : 'Rosary Builder';
|
||||
?>
|
||||
<!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">
|
||||
<link rel="stylesheet" href="<?= BASE_URL ?>/assets/css/builder.css?v=1">
|
||||
</head>
|
||||
<body style="overflow:hidden">
|
||||
|
||||
<div class="admin-container" style="max-width:100%;padding:0">
|
||||
|
||||
<header class="admin-header" style="position:sticky;top:0;z-index:100;padding:0 24px;height:64px">
|
||||
<h1 style="font-size:1rem">✝ <?= htmlspecialchars($site_name) ?></h1>
|
||||
<div class="header-actions">
|
||||
<a href="<?= BASE_URL ?>/" class="btn btn-ghost" style="font-size:12px">← View Site</a>
|
||||
<?php if ($is_admin): ?>
|
||||
<a href="<?= BASE_URL ?>/admin/prayers.php" class="btn btn-ghost">Prayer Library</a>
|
||||
<?php endif; ?>
|
||||
<a href="<?= BASE_URL ?>/admin/" class="btn btn-ghost">← Dashboard</a>
|
||||
<a href="<?= BASE_URL ?>/logout" class="btn btn-ghost">Logout</a>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="builder-wrap">
|
||||
|
||||
<!-- Toolbar -->
|
||||
<div class="builder-toolbar">
|
||||
<h2>✒ <?= $session ? 'Edit Sequence' : 'Rosary Builder' ?></h2>
|
||||
<div class="divider"></div>
|
||||
<input type="text" id="session-name" class="session-name-input"
|
||||
placeholder="Session label (required)"
|
||||
value="<?= htmlspecialchars($session['name'] ?? '') ?>">
|
||||
<div class="toolbar-right">
|
||||
<label class="public-toggle">
|
||||
<input type="checkbox" id="is-public"
|
||||
<?= (!$session || $session['is_public']) ? 'checked' : '' ?>>
|
||||
Public
|
||||
</label>
|
||||
<?php if ($session): ?>
|
||||
<?php
|
||||
$owner_stmt = $pdo->prepare("SELECT username FROM users WHERE id = ?");
|
||||
$owner_stmt->execute([$session['user_id']]);
|
||||
$owner_uname = $owner_stmt->fetchColumn() ?: '';
|
||||
$present_url = BASE_URL . '/' . rawurlencode($owner_uname) . '/' . rawurlencode($session['slug'] ?? '');
|
||||
?>
|
||||
<a id="present-link" href="<?= htmlspecialchars($present_url) ?>"
|
||||
target="_blank" class="btn btn-ghost" style="font-size:13px">
|
||||
Present ↗
|
||||
</a>
|
||||
<?php else: ?>
|
||||
<a id="present-link" href="#" target="_blank"
|
||||
class="btn btn-ghost" style="font-size:13px;display:none">
|
||||
Present ↗
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
<button id="btn-save" class="btn btn-primary">Save Session</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Message bar -->
|
||||
<div id="builder-msg"></div>
|
||||
|
||||
<!-- Optional subject (for variable substitution in prayers like Eternal Rest) -->
|
||||
<details class="builder-subject">
|
||||
<summary>For a specific person (optional — enables {name}, {pronoun} substitutions)</summary>
|
||||
<div class="builder-subject-fields">
|
||||
<input type="text" id="subject-name"
|
||||
placeholder="Full name, e.g. Maria Santos"
|
||||
value="<?= htmlspecialchars($session['subject_name'] ?? '') ?>">
|
||||
<select id="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>
|
||||
<input type="text" id="subject-dates"
|
||||
placeholder="Life dates, e.g. Aug 12, 1949 – July 25, 2025"
|
||||
style="min-width:280px"
|
||||
value="<?= htmlspecialchars($session['subject_dates'] ?? '') ?>">
|
||||
</div>
|
||||
</details>
|
||||
|
||||
<!-- Two-panel body -->
|
||||
<div class="builder-body">
|
||||
|
||||
<!-- Left: Sequence -->
|
||||
<div class="builder-sequence">
|
||||
<div class="panel-header">
|
||||
<h3>Your Sequence</h3>
|
||||
<span id="step-count-badge" class="step-count-badge">0 prayers</span>
|
||||
</div>
|
||||
<div id="step-list"></div>
|
||||
</div>
|
||||
|
||||
<!-- Right: Prayer library -->
|
||||
<div class="builder-library">
|
||||
<div class="library-header">
|
||||
<input type="search" id="prayer-search" class="library-search"
|
||||
placeholder="🔍 Search prayers by name or text…">
|
||||
<div class="library-tabs">
|
||||
<button class="tab-btn active" data-tab="all">All</button>
|
||||
<button class="tab-btn" data-tab="standard">Standard</button>
|
||||
<button class="tab-btn" data-tab="mine">My Prayers</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="prayer-list">
|
||||
<div class="library-empty" style="grid-column:1/-1;padding:40px;text-align:center;color:var(--muted)">
|
||||
Loading…
|
||||
</div>
|
||||
</div>
|
||||
<div class="library-footer">
|
||||
<button id="btn-create-prayer" class="btn btn-secondary">+ Create Custom Prayer</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div><!-- /builder-body -->
|
||||
</div><!-- /builder-wrap -->
|
||||
</div><!-- /admin-container -->
|
||||
|
||||
|
||||
<!-- ── Create / Edit Prayer Modal ─────────────────────────────── -->
|
||||
<div id="prayer-modal" class="modal-overlay" hidden>
|
||||
<div class="modal-box">
|
||||
<h3 id="modal-title">New Custom Prayer</h3>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="modal-name">Prayer Name <span class="required">*</span></label>
|
||||
<input type="text" id="modal-name" class="form-control"
|
||||
placeholder="e.g. Opening Prayer, Special Intention…"
|
||||
style="width:100%;padding:9px 12px;border:1px solid var(--border);border-radius:6px;font-family:var(--font);font-size:14px">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Attribution</label>
|
||||
<div class="attr-radios">
|
||||
<label class="attr-radio-label">
|
||||
<input type="radio" name="modal-attr" value="leader_all" checked>
|
||||
<span><strong>Leader / All</strong><br><small>Two voices — leader speaks, congregation responds</small></span>
|
||||
</label>
|
||||
<label class="attr-radio-label">
|
||||
<input type="radio" name="modal-attr" value="leader_only">
|
||||
<span><strong>Leader only</strong><br><small>Leader speaks the whole prayer</small></span>
|
||||
</label>
|
||||
<label class="attr-radio-label">
|
||||
<input type="radio" name="modal-attr" value="all_only">
|
||||
<span><strong>All together</strong><br><small>Everyone prays in unison</small></span>
|
||||
</label>
|
||||
<label class="attr-radio-label">
|
||||
<input type="radio" name="modal-attr" value="none">
|
||||
<span><strong>No attribution</strong><br><small>Plain text — no leader/all labels</small></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group" id="modal-leader-group">
|
||||
<label for="modal-leader">Leader text</label>
|
||||
<textarea id="modal-leader" class="modal-textarea" rows="5"
|
||||
placeholder="What the leader says…"></textarea>
|
||||
<p class="help-hint">Use line breaks to control pacing. Variables: {name}, {pronoun_obj}, {pronoun_poss}</p>
|
||||
</div>
|
||||
|
||||
<div class="form-group" id="modal-all-group">
|
||||
<label for="modal-all">All / Response text</label>
|
||||
<textarea id="modal-all" class="modal-textarea" rows="3"
|
||||
placeholder="What everyone says together…"></textarea>
|
||||
</div>
|
||||
|
||||
<?php if ($is_admin): ?>
|
||||
<div class="form-group" id="modal-global-group">
|
||||
<label style="display:flex;align-items:center;gap:8px;cursor:pointer;font-weight:normal">
|
||||
<input type="checkbox" id="modal-global" style="width:16px;height:16px">
|
||||
Make this prayer available to all users (global library)
|
||||
</label>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<input type="hidden" id="modal-global">
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button id="modal-cancel" class="btn btn-ghost">Cancel</button>
|
||||
<button id="modal-save" class="btn btn-primary">Save Prayer</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<script>
|
||||
var BASE_URL = '<?= BASE_URL ?>';
|
||||
var IS_ADMIN = <?= $is_admin ? 'true' : 'false' ?>;
|
||||
var EDIT_SESSION_ID = <?= $session ? (int)$session['id'] : 'null' ?>;
|
||||
var PRAYERS_DATA = <?= json_encode(array_values($prayers_data)) ?>;
|
||||
var EXISTING_STEPS = <?= json_encode(array_map(fn($s) => [
|
||||
'prayer_id' => (int)$s['prayer_id'],
|
||||
'attribution' => $s['attribution'],
|
||||
], $edit_steps)) ?>;
|
||||
</script>
|
||||
<script src="<?= BASE_URL ?>/assets/js/builder.js?v=1"></script>
|
||||
</body>
|
||||
</html>
|
||||
+15
-2
@@ -94,6 +94,7 @@ $occasion_labels = [
|
||||
'divine_mercy_novena' => 'Divine Mercy Novena',
|
||||
'general_rosary' => 'General Rosary',
|
||||
'memorial' => 'Memorial',
|
||||
'custom' => 'Custom Sequence',
|
||||
];
|
||||
$mystery_labels = [
|
||||
'sorrowful' => 'Sorrowful',
|
||||
@@ -121,7 +122,11 @@ $novena_created = isset($_GET['novena_created']) ? (int)$_GET['novena_created']
|
||||
<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('superuser')): ?>
|
||||
<a href="<?= BASE_URL ?>/admin/builder.php" class="btn btn-ghost">✒ Builder</a>
|
||||
<?php endif; ?>
|
||||
<?php if (has_role('admin')): ?>
|
||||
<a href="<?= BASE_URL ?>/admin/prayers.php" class="btn btn-ghost">Prayers</a>
|
||||
<a href="<?= BASE_URL ?>/admin/users.php" class="btn btn-ghost">Users</a>
|
||||
<a href="<?= BASE_URL ?>/admin/audio.php" class="btn btn-ghost">Audio</a>
|
||||
<?php endif; ?>
|
||||
@@ -142,7 +147,12 @@ $novena_created = isset($_GET['novena_created']) ? (int)$_GET['novena_created']
|
||||
|
||||
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:20px">
|
||||
<h2 style="margin:0"><?= $is_admin ? 'All Sessions' : 'My Sessions' ?></h2>
|
||||
<a href="<?= BASE_URL ?>/admin/setup.php" class="btn btn-primary">+ New Session</a>
|
||||
<div style="display:flex;gap:8px">
|
||||
<?php if (has_role('superuser')): ?>
|
||||
<a href="<?= BASE_URL ?>/admin/builder.php" class="btn btn-secondary">✒ Build Custom</a>
|
||||
<?php endif; ?>
|
||||
<a href="<?= BASE_URL ?>/admin/setup.php" class="btn btn-primary">+ New Session</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if (empty($all_rows)): ?>
|
||||
@@ -224,7 +234,10 @@ $novena_created = isset($_GET['novena_created']) ? (int)$_GET['novena_created']
|
||||
target="_blank"
|
||||
class="btn btn-sm btn-primary">Present</a>
|
||||
<?php if ($is_admin || (int)$row['user_id'] === $uid): ?>
|
||||
<a href="<?= BASE_URL ?>/admin/setup.php?id=<?= $row['id'] ?>"
|
||||
<?php $edit_url = ($row['occasion'] === 'custom')
|
||||
? BASE_URL . '/admin/builder.php?id=' . $row['id']
|
||||
: BASE_URL . '/admin/setup.php?id=' . $row['id']; ?>
|
||||
<a href="<?= htmlspecialchars($edit_url) ?>"
|
||||
class="btn btn-sm btn-secondary">Edit</a>
|
||||
<form method="post" style="display:inline"
|
||||
onsubmit="return confirm('Delete this session?')">
|
||||
|
||||
@@ -0,0 +1,226 @@
|
||||
<?php
|
||||
/**
|
||||
* admin/prayers.php — Global prayer library management.
|
||||
* Admin and superadmin only.
|
||||
*/
|
||||
require_once __DIR__ . '/../config/db.php';
|
||||
require_once __DIR__ . '/../includes/auth.php';
|
||||
|
||||
require_role('admin');
|
||||
|
||||
$pdo = get_pdo();
|
||||
$user = current_user();
|
||||
$uid = (int)$user['id'];
|
||||
$site_name = get_setting('site_name', APP_NAME);
|
||||
|
||||
// Handle form actions
|
||||
$msg = '';
|
||||
$msg_type = 'success';
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$action = $_POST['action'] ?? '';
|
||||
|
||||
if ($action === 'delete') {
|
||||
$id = (int)($_POST['prayer_id'] ?? 0);
|
||||
if ($id) {
|
||||
// Check if in use
|
||||
$in_use = (int)$pdo->prepare("SELECT COUNT(*) FROM builder_steps WHERE prayer_id = ?")
|
||||
->execute([$id]) ? 0 : 0;
|
||||
$st = $pdo->prepare("SELECT COUNT(*) FROM builder_steps WHERE prayer_id = ?");
|
||||
$st->execute([$id]);
|
||||
if ((int)$st->fetchColumn() > 0) {
|
||||
$msg = 'Cannot delete: this prayer is used in one or more sessions.';
|
||||
$msg_type = 'error';
|
||||
} else {
|
||||
$pdo->prepare("DELETE FROM custom_prayers WHERE id = ?")->execute([$id]);
|
||||
$msg = 'Prayer deleted.';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($action === 'toggle_global') {
|
||||
$id = (int)($_POST['prayer_id'] ?? 0);
|
||||
$global = (int)($_POST['new_global'] ?? 0);
|
||||
if ($id) {
|
||||
$pdo->prepare("UPDATE custom_prayers SET is_global=? WHERE id=?")->execute([$global, $id]);
|
||||
$msg = $global ? 'Prayer made global.' : 'Prayer set to private.';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Load all prayers visible to admins
|
||||
$prayers = $pdo->prepare("
|
||||
SELECT cp.*,
|
||||
u.username AS creator_username, u.display_name AS creator_display, u.role AS creator_role,
|
||||
(SELECT COUNT(*) FROM builder_steps WHERE prayer_id = cp.id) AS use_count
|
||||
FROM custom_prayers cp
|
||||
LEFT JOIN users u ON u.id = cp.created_by
|
||||
ORDER BY (cp.is_global=1 AND u.role='superadmin') DESC, cp.is_global DESC, cp.name ASC
|
||||
");
|
||||
$prayers->execute();
|
||||
$prayers = $prayers->fetchAll();
|
||||
|
||||
$filter = $_GET['filter'] ?? 'all';
|
||||
?>
|
||||
<!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>Prayer Library — <?= htmlspecialchars($site_name) ?></title>
|
||||
<link rel="stylesheet" href="<?= BASE_URL ?>/assets/css/setup.css">
|
||||
<style>
|
||||
.filter-tabs { display:flex; gap:8px; margin-bottom:20px; flex-wrap:wrap; }
|
||||
.filter-tabs a { padding:6px 16px; border:1px solid var(--border); border-radius:20px; font-size:13px; text-decoration:none; color:var(--muted); }
|
||||
.filter-tabs a.active { background:var(--primary); border-color:var(--primary); color:#fff; font-weight:500; }
|
||||
.prayer-table { width:100%; border-collapse:collapse; }
|
||||
.prayer-table th, .prayer-table td { padding:10px 12px; text-align:left; border-bottom:1px solid var(--border); font-size:13px; vertical-align:top; }
|
||||
.prayer-table th { font-size:11px; text-transform:uppercase; letter-spacing:.05em; color:var(--muted); background:var(--bg); font-weight:600; }
|
||||
.prayer-table tbody tr:hover { background:var(--bg); }
|
||||
.prayer-preview { color:var(--muted); font-size:12px; margin-top:3px; }
|
||||
.badge-std { background:#fef9c3; color:#854d0e; }
|
||||
.badge-glob { background:#dcfce7; color:#166534; }
|
||||
.badge-priv { background:#ede9fe; color:#6d28d9; }
|
||||
.use-badge { background:#e0e7ff; color:#3730a3; padding:2px 8px; border-radius:4px; font-size:11px; font-weight:600; }
|
||||
.action-form { display:inline; }
|
||||
details.preview-detail { font-size:12px; color:var(--muted); margin-top:4px; }
|
||||
details.preview-detail summary { cursor:pointer; color:var(--primary); }
|
||||
details.preview-detail pre { white-space:pre-wrap; font-family:inherit; margin-top:6px; line-height:1.5; }
|
||||
</style>
|
||||
</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>
|
||||
<a href="<?= BASE_URL ?>/admin/builder.php" class="btn btn-ghost">Builder</a>
|
||||
<a href="<?= BASE_URL ?>/admin/users.php" class="btn btn-ghost">Users</a>
|
||||
<?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/" class="btn btn-ghost">← Dashboard</a>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<?php if ($msg): ?>
|
||||
<div class="alert alert-<?= $msg_type === 'error' ? 'error' : 'success' ?>" style="margin-bottom:16px">
|
||||
<?= htmlspecialchars($msg) ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:20px">
|
||||
<div>
|
||||
<h2 style="margin:0">Prayer Library</h2>
|
||||
<p style="margin:4px 0 0;font-size:13px;color:var(--muted)">
|
||||
Global prayers are available to all users in the Rosary Builder.
|
||||
</p>
|
||||
</div>
|
||||
<a href="<?= BASE_URL ?>/admin/builder.php" class="btn btn-primary">+ Open Builder</a>
|
||||
</div>
|
||||
|
||||
<!-- Filter tabs -->
|
||||
<div class="filter-tabs">
|
||||
<a href="?filter=all" class="<?= $filter==='all' ? 'active':'' ?>">All (<?= count($prayers) ?>)</a>
|
||||
<a href="?filter=standard" class="<?= $filter==='standard' ? 'active':'' ?>">Standard (<?= count(array_filter($prayers, fn($p)=>$p['is_global']&&$p['creator_role']==='superadmin')) ?>)</a>
|
||||
<a href="?filter=global" class="<?= $filter==='global' ? 'active':'' ?>">Global Custom (<?= count(array_filter($prayers, fn($p)=>$p['is_global']&&$p['creator_role']!=='superadmin')) ?>)</a>
|
||||
<a href="?filter=private" class="<?= $filter==='private' ? 'active':'' ?>">Private (<?= count(array_filter($prayers, fn($p)=>!$p['is_global'])) ?>)</a>
|
||||
</div>
|
||||
|
||||
<div class="sessions-table-wrap">
|
||||
<table class="prayer-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width:30%">Name / Preview</th>
|
||||
<th>Visibility</th>
|
||||
<th>Created by</th>
|
||||
<th>Used in</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php
|
||||
$shown = array_filter($prayers, function($p) use ($filter) {
|
||||
if ($filter === 'standard') return $p['is_global'] && $p['creator_role'] === 'superadmin';
|
||||
if ($filter === 'global') return $p['is_global'] && $p['creator_role'] !== 'superadmin';
|
||||
if ($filter === 'private') return !$p['is_global'];
|
||||
return true;
|
||||
});
|
||||
foreach ($shown as $p):
|
||||
$is_standard = $p['is_global'] && $p['creator_role'] === 'superadmin';
|
||||
$badge_class = $is_standard ? 'badge-std' : ($p['is_global'] ? 'badge-glob' : 'badge-priv');
|
||||
$badge_label = $is_standard ? 'Standard' : ($p['is_global'] ? 'Global' : 'Private');
|
||||
$creator = $p['creator_display'] ?: $p['creator_username'] ?: '—';
|
||||
?>
|
||||
<tr>
|
||||
<td>
|
||||
<strong><?= htmlspecialchars($p['name']) ?></strong>
|
||||
<details class="preview-detail">
|
||||
<summary>Preview</summary>
|
||||
<?php if ($p['leader_text']): ?>
|
||||
<pre><strong>Leader:</strong> <?= htmlspecialchars(mb_substr($p['leader_text'], 0, 200)) ?><?= strlen($p['leader_text'])>200?'…':'' ?></pre>
|
||||
<?php endif; ?>
|
||||
<?php if ($p['all_text']): ?>
|
||||
<pre><strong>All:</strong> <?= htmlspecialchars(mb_substr($p['all_text'], 0, 200)) ?><?= strlen($p['all_text'])>200?'…':'' ?></pre>
|
||||
<?php endif; ?>
|
||||
</details>
|
||||
</td>
|
||||
<td>
|
||||
<span class="source-badge <?= $badge_class ?>" style="padding:3px 8px;border-radius:4px;font-size:11px;font-weight:600">
|
||||
<?= $badge_label ?>
|
||||
</span>
|
||||
</td>
|
||||
<td style="color:var(--muted)"><?= htmlspecialchars($creator) ?></td>
|
||||
<td>
|
||||
<?php if ($p['use_count'] > 0): ?>
|
||||
<span class="use-badge"><?= $p['use_count'] ?> session<?= $p['use_count']!==1?'s':'' ?></span>
|
||||
<?php else: ?>
|
||||
<span style="color:var(--muted);font-size:12px">—</span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td class="actions">
|
||||
<?php if (!$is_standard): ?>
|
||||
<?php if ($p['is_global']): ?>
|
||||
<form method="post" class="action-form">
|
||||
<input type="hidden" name="action" value="toggle_global">
|
||||
<input type="hidden" name="prayer_id" value="<?= $p['id'] ?>">
|
||||
<input type="hidden" name="new_global" value="0">
|
||||
<button class="btn btn-sm btn-ghost">Make Private</button>
|
||||
</form>
|
||||
<?php else: ?>
|
||||
<form method="post" class="action-form">
|
||||
<input type="hidden" name="action" value="toggle_global">
|
||||
<input type="hidden" name="prayer_id" value="<?= $p['id'] ?>">
|
||||
<input type="hidden" name="new_global" value="1">
|
||||
<button class="btn btn-sm btn-secondary">Make Global</button>
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
<?php if ($p['use_count'] == 0): ?>
|
||||
<form method="post" class="action-form"
|
||||
onsubmit="return confirm('Delete "<?= htmlspecialchars(addslashes($p['name'])) ?>"?')">
|
||||
<input type="hidden" name="action" value="delete">
|
||||
<input type="hidden" name="prayer_id" value="<?= $p['id'] ?>">
|
||||
<button class="btn btn-sm btn-danger">Delete</button>
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
<?php else: ?>
|
||||
<span style="color:var(--muted);font-size:12px">Standard prayers cannot be deleted</span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php if (!$shown): ?>
|
||||
<tr>
|
||||
<td colspan="5" style="text-align:center;padding:40px;color:var(--muted)">No prayers in this category.</td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user