38394-vm/index.php
2026-02-15 08:01:20 +00:00

645 lines
24 KiB
PHP

<?php
require_once 'db/config.php';
// Language configuration
$lang = $_GET['lang'] ?? 'ar';
if (!in_array($lang, ['en', 'ar'])) $lang = 'ar';
$dir = ($lang === 'ar') ? 'rtl' : 'ltr';
// UI Text
$texts = [
'en' => [
'title' => 'Support a Cause',
'subtitle' => 'Empower communities worldwide through your generosity.',
'all_cats' => 'All Categories',
'raised' => 'Raised',
'of' => 'of',
'goal' => 'Goal',
'donate_now' => 'Donate Now',
'lang_name' => 'العربية',
'lang_code' => 'ar',
'hero_title' => 'Make a Real Impact Today',
'hero_sub' => 'Choose a campaign from our trusted categories and help change lives in minutes.',
'no_cases' => 'No active cases found matching your criteria.',
'admin_panel' => 'Admin Panel',
'modal_title' => 'Make a Donation',
'modal_amount' => 'Amount (OMR)',
'modal_name' => 'Your Name',
'modal_email' => 'Your Email',
'modal_phone' => 'Phone Number',
'modal_submit' => 'Proceed to Payment',
'top_priority' => 'Top Priority',
'urgent' => 'Urgent',
'featured' => 'Featured',
'search_placeholder' => 'Search for a case...',
'search_btn' => 'Search',
'new_badge' => 'NEW',
'monthly_giving' => 'Join our monthly giving circle',
'clear_search' => 'Clear Search',
'priority_notice' => 'LATEST UPDATES',
'donate_type_me' => 'Donate for myself',
'donate_type_gift' => 'Donate as a gift',
'recipient_name' => 'Recipient Name',
'recipient_phone' => 'Recipient Phone',
'gift_message' => 'Gift Message',
'gift_notice' => 'The system will send a notification to the recipient.',
'read_more' => 'Read More',
'close' => 'Close',
'home' => 'Home',
'about_us' => 'About Us',
'contact_us' => 'Contact Us',
'modal_name_placeholder' => 'Anonymous Donor',
'modal_email_placeholder' => 'you@example.com',
'modal_phone_placeholder' => '12345678',
'modal_phone_hint' => 'Enter 8 digits. 968 will be added automatically.',
],
'ar' => [
'title' => 'ادعم قضية',
'subtitle' => 'مكن المجتمعات في جميع أنحاء العالم من خلال كرمك.',
'all_cats' => 'جميع الفئات',
'raised' => 'تم جمع',
'of' => 'من',
'goal' => 'الهدف',
'donate_now' => 'تبرع الآن',
'lang_name' => 'English',
'lang_code' => 'en',
'hero_title' => 'أحدث تأثيراً حقيقياً اليوم',
'hero_sub' => 'اختر حملة من فئاتنا الموثوقة وساعد في تغيير الأرواح في دقائق.',
'no_cases' => 'لم يتم العثور على حالات نشطة تطابق بحثك.',
'admin_panel' => 'لوحة التحكم',
'modal_title' => 'تبرع الآن',
'modal_amount' => 'المبلغ (ريال عماني)',
'modal_name' => 'الاسم',
'modal_email' => 'البريد الإلكتروني',
'modal_phone' => 'رقم الهاتف',
'modal_submit' => 'الانتقال للدفع',
'top_priority' => 'أولوية قصوى',
'urgent' => 'عاجل',
'featured' => 'مميز',
'search_placeholder' => 'ابحث عن حالة...',
'search_btn' => 'بحث',
'new_badge' => 'جديد',
'monthly_giving' => 'انضم إلى دائرة العطاء الشهري',
'clear_search' => 'مسح البحث',
'priority_notice' => 'آخر التحديثات',
'donate_type_me' => 'تبرع لنفسي',
'donate_type_gift' => 'تبرع كهدية لشخص آخر',
'recipient_name' => 'اسم المستلم',
'recipient_phone' => 'رقم هاتف المستلم',
'gift_message' => 'رسالة الهدية',
'gift_notice' => 'سيقوم النظام بإرسال إشعار إلى المستلم.',
'read_more' => 'اقرأ المزيد',
'close' => 'إغلاق',
'home' => 'الرئيسية',
'about_us' => 'من نحن',
'contact_us' => 'اتصل بنا',
'modal_name_placeholder' => 'فاعل خير',
'modal_email_placeholder' => 'you@example.com',
'modal_phone_placeholder' => '12345678',
'modal_phone_hint' => 'أدخل 8 أرقام. ستتم إضافة 968 تلقائيًا.',
]
];
$t = $texts[$lang];
// Database fetch
$pdo = db();
$profile = $pdo->query("SELECT * FROM org_profile LIMIT 1")->fetch();
$categories = $pdo->query("SELECT * FROM categories")->fetchAll();
$selected_cat = $_GET['cat'] ?? 'all';
$search_query = trim($_GET['search'] ?? '');
// Fetch featured/top priority cases separately for the "ads" section
$featured_cases = $pdo->query("SELECT c.*, cat.name_en as cat_name_en, cat.name_ar as cat_name_ar
FROM cases c
LEFT JOIN categories cat ON c.category_id = cat.id
WHERE c.status = 'active' AND (c.importance = 'top_priority' OR c.importance = 'urgent')
ORDER BY c.importance = 'top_priority' DESC, c.id DESC LIMIT 5")->fetchAll();
$params = [];
$sql = "SELECT c.*, cat.name_en as cat_name_en, cat.name_ar as cat_name_ar
FROM cases c
LEFT JOIN categories cat ON c.category_id = cat.id
WHERE c.status = 'active'";
if ($selected_cat !== 'all') {
$sql .= " AND c.category_id = :cat";
$params['cat'] = (int)$selected_cat;
}
if ($search_query !== '') {
$sql .= " AND (c.title_en LIKE :search OR c.title_ar LIKE :search OR c.desc_en LIKE :search OR c.desc_ar LIKE :search)";
$params['search'] = "%$search_query%";
}
$sql .= " ORDER BY CASE WHEN c.importance = 'top_priority' THEN 1 WHEN c.importance = 'urgent' THEN 2 ELSE 3 END, c.id DESC";
$stmt = $pdo->prepare($sql);
$stmt->execute($params);
$cases = $stmt->fetchAll();
// Helpers for safe string operations
function safe_strlen($text) {
if (empty($text)) return 0;
if (function_exists('mb_strlen')) {
return mb_strlen($text);
}
return strlen($text);
}
function safe_truncate($text, $limit = 120) {
if (empty($text)) return '';
if (function_exists('mb_strimwidth')) {
return mb_strimwidth($text, 0, $limit, "...");
}
return (strlen($text) > $limit) ? substr($text, 0, $limit) . "..." : $text;
}
require_once 'includes/header.php';
?>
<style>
.hero {
padding: 4rem 0 3rem 0;
background: #fff;
border-bottom: 1px solid #e5e7eb;
text-align: center;
margin-bottom: 3rem;
}
.hero h1 {
font-size: 2.5rem;
font-weight: 800;
margin-bottom: 1rem;
letter-spacing: -0.025em;
}
.hero p {
font-size: 1.125rem;
color: var(--text-muted);
max-width: 600px;
margin: 0 auto 2rem auto;
}
.search-container {
max-width: 500px;
margin: 0 auto;
}
.search-box {
display: flex;
background: #f3f4f6;
border-radius: 9999px;
padding: 6px;
border: 1px solid #e5e7eb;
transition: border-color 0.3s, background 0.3s;
}
.search-box:focus-within {
border-color: var(--primary-color);
background: #fff;
box-shadow: 0 0 0 4px rgba(5, 150, 105, 0.1);
}
.search-box input {
border: none;
background: transparent;
padding: 0.5rem 1.5rem;
flex-grow: 1;
outline: none;
font-size: 0.9375rem;
}
.search-btn {
background: var(--primary-color);
color: #fff;
border: none;
border-radius: 9999px;
padding: 0.5rem 1.5rem;
font-weight: 600;
font-size: 0.875rem;
transition: background 0.2s;
}
.search-btn:hover {
background: var(--primary-hover);
}
.cat-tabs {
margin-bottom: 2rem;
display: flex;
gap: 0.75rem;
overflow-x: auto;
padding-bottom: 0.5rem;
justify-content: center;
}
.cat-tab {
padding: 0.5rem 1.25rem;
border-radius: 9999px;
background: #fff;
border: 1px solid #e5e7eb;
color: var(--text-muted);
text-decoration: none;
white-space: nowrap;
transition: all 0.2s;
font-weight: 500;
font-size: 0.9375rem;
}
.cat-tab:hover, .cat-tab.active {
background: var(--primary-color);
color: #fff;
border-color: var(--primary-color);
}
.case-card {
background: #fff;
border-radius: 16px;
overflow: hidden;
border: 1px solid #e5e7eb;
transition: transform 0.2s, box-shadow 0.2s, border-color 0.3s;
height: 100%;
display: flex;
flex-direction: column;
position: relative;
}
.case-card:hover {
transform: translateY(-4px);
box-shadow: 0 12px 20px -5px rgba(0, 0, 0, 0.08);
}
.case-image {
height: 220px;
width: 100%;
object-fit: cover;
}
.importance-badge {
position: absolute;
top: 1rem;
right: 1rem;
padding: 0.35rem 0.75rem;
border-radius: 9999px;
font-size: 0.75rem;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.025em;
color: #fff;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
[dir="rtl"] .importance-badge { right: auto; left: 1rem; }
.badge-urgent { background-color: #ef4444; }
.badge-top_priority { background-color: #8b5cf6; }
.badge-normal { display: none; }
.case-content {
padding: 1.5rem;
flex-grow: 1;
display: flex;
flex-direction: column;
}
.case-cat {
font-size: 0.8125rem;
color: var(--primary-color);
font-weight: 700;
margin-bottom: 0.5rem;
text-transform: uppercase;
letter-spacing: 0.05em;
}
.case-title {
font-size: 1.25rem;
font-weight: 700;
margin-bottom: 0.75rem;
color: var(--text-main);
line-height: 1.4;
}
.progress-container {
margin: 1.25rem 0;
padding: 1.25rem;
background: #f9fafb;
border-radius: 12px;
}
.progress {
height: 8px;
border-radius: 9999px;
background-color: #e5e7eb;
margin-bottom: 0.75rem;
}
.progress-bar {
background-color: var(--primary-color);
}
.progress-stats {
display: flex;
justify-content: space-between;
font-size: 0.8125rem;
color: var(--text-muted);
}
.btn-donate {
background-color: var(--primary-color);
color: #fff;
border: none;
padding: 0.875rem 1.5rem;
border-radius: 12px;
font-weight: 700;
width: 100%;
transition: all 0.2s;
margin-top: auto;
}
.btn-donate:hover {
background-color: var(--primary-hover);
color: #fff;
transform: scale(1.02);
}
[dir="rtl"] .hero h1 {
letter-spacing: 0;
}
.donate-type-selector {
display: flex;
background: #f3f4f6;
padding: 4px;
border-radius: 12px;
margin-bottom: 1.5rem;
}
.donate-type-btn {
flex: 1;
text-align: center;
padding: 8px;
border-radius: 10px;
cursor: pointer;
font-weight: 600;
font-size: 0.875rem;
transition: all 0.2s;
}
.donate-type-btn.active {
background: #fff;
color: var(--primary-color);
box-shadow: 0 2px 4px rgba(0,0,0,0.05);
}
#giftFields {
display: none;
border: 1px solid #e5e7eb;
padding: 1.25rem;
border-radius: 12px;
background: #f9fafb;
margin-top: 1rem;
}
</style>
<header class="hero">
<div class="container">
<h1><?= $t['hero_title'] ?></h1>
<p><?= $t['hero_sub'] ?></p>
<div class="search-container mt-4">
<form action="index.php" method="GET" class="search-box">
<input type="hidden" name="lang" value="<?= $lang ?>">
<input type="hidden" name="cat" value="<?= $selected_cat ?>">
<input type="text" name="search" placeholder="<?= $t['search_placeholder'] ?>" value="<?= htmlspecialchars($search_query) ?>" aria-label="Search">
<button type="submit" class="search-btn">
<i class="bi bi-search me-1"></i> <?= $t['search_btn'] ?>
</button>
</form>
</div>
</div>
</header>
<main class="container">
<div class="cat-tabs">
<a href="?lang=<?= $lang ?>&cat=all&search=<?= urlencode($search_query) ?>" class="cat-tab <?= $selected_cat === 'all' ? 'active' : '' ?>">
<?= $t['all_cats'] ?>
</a>
<?php foreach ($categories as $cat): ?>
<a href="?lang=<?= $lang ?>&cat=<?= $cat['id'] ?>&search=<?= urlencode($search_query) ?>" class="cat-tab <?= $selected_cat == $cat['id'] ? 'active' : '' ?>">
<?= $lang === 'en' ? $cat['name_en'] : $cat['name_ar'] ?>
</a>
<?php endforeach; ?>
</div>
<div class="row g-4">
<?php if (empty($cases)): ?>
<div class="col-12 text-center py-5">
<div class="bg-white p-5 rounded-4 border">
<i class="bi bi-search d-block mb-3 fs-1 text-muted"></i>
<p class="text-muted fw-medium"><?= $t['no_cases'] ?></p>
<?php if ($search_query !== ''): ?>
<a href="?lang=<?= $lang ?>&cat=<?= $selected_cat ?>" class="btn btn-outline-primary rounded-pill px-4 mt-2">
<?= $t['clear_search'] ?>
</a>
<?php endif; ?>
</div>
</div>
<?php endif; ?>
<?php foreach ($cases as $case): ?>
<?php
$pct = min(100, round(($case['raised'] / $case['goal']) * 100));
$full_desc = $lang === 'en' ? $case['desc_en'] : $case['desc_ar'];
$is_long = safe_strlen($full_desc) > 120;
$truncated_desc = safe_truncate($full_desc, 120);
?>
<div class="col-md-6 col-lg-4" id="case-<?= $case['id'] ?>">
<div class="case-card">
<?php if ($case['importance'] !== 'normal'): ?>
<div class="importance-badge badge-<?= $case['importance'] ?>">
<i class="bi bi-lightning-fill me-1"></i>
<?= $t[$case['importance']] ?? str_replace('_', ' ', $case['importance']) ?>
</div>
<?php endif; ?>
<?php if ($case['image_url']): ?>
<img src="<?= htmlspecialchars($case['image_url']) ?>" class="case-image" alt="Case Image">
<?php else: ?>
<div class="case-image bg-secondary d-flex align-items-center justify-content-center text-white">
<i class="bi bi-image fs-1"></i>
</div>
<?php endif; ?>
<div class="case-content">
<span class="case-cat"><?= $lang === 'en' ? ($case['cat_name_en'] ?? 'General') : ($case['cat_name_ar'] ?? 'عام') ?></span>
<h3 class="case-title">
<a href="case.php?id=<?= $case['id'] ?>&lang=<?= $lang ?>" class="text-decoration-none" style="color: inherit;">
<?= $lang === 'en' ? $case['title_en'] : $case['title_ar'] ?>
</a>
</h3>
<p class="text-muted small mb-0">
<?= htmlspecialchars($truncated_desc) ?>
</p>
<div class="progress-container">
<div class="progress">
<div class="progress-bar" role="progressbar" style="width: <?= $pct ?>%" aria-valuenow="<?= $pct ?>" aria-valuemin="0" aria-valuemax="100"></div>
</div>
<div class="progress-stats">
<span><strong><?= $t['raised'] ?>:</strong> OMR <?= number_format($case['raised']) ?></span>
<span><strong><?= $t['goal'] ?>:</strong> OMR <?= number_format($case['goal']) ?></span>
</div>
</div>
<button class="btn btn-donate" data-bs-toggle="modal" data-bs-target="#donateModal"
data-case-id="<?= $case['id'] ?>"
data-case-title="<?= htmlspecialchars($lang === 'en' ? $case['title_en'] : $case['title_ar']) ?>">
<?= $t['donate_now'] ?>
</button>
</div>
</div>
</div>
<?php endforeach; ?>
</div>
</main>
<!-- Donate Modal -->
<div class="modal fade" id="donateModal" tabindex="-1">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content border-0 shadow-lg rounded-4">
<form action="checkout.php" method="POST">
<input type="hidden" name="lang" value="<?= $lang ?>">
<div class="modal-header border-0 pb-0">
<h5 class="modal-title fw-bold"><?= $t['modal_title'] ?></h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body p-4">
<div class="p-3 bg-light rounded-3 mb-4 border-start border-success border-4">
<p id="modalCaseTitle" class="fw-bold text-success mb-0"></p>
</div>
<!-- Donate Type Selector -->
<div class="donate-type-selector">
<div class="donate-type-btn active" data-type="me" onclick="setDonateType('me')">
<?= $t['donate_type_me'] ?>
</div>
<div class="donate-type-btn" data-type="gift" onclick="setDonateType('gift')">
<?= $t['donate_type_gift'] ?>
</div>
</div>
<input type="hidden" name="is_gift" id="isGiftInput" value="0">
<input type="hidden" name="case_id" id="modalCaseId">
<div class="mb-3">
<label class="form-label small fw-bold text-muted"><?= $t['modal_amount'] ?></label>
<div class="d-flex justify-content-between mb-2">
<button type="button" class="btn btn-outline-primary btn-sm flex-grow-1 mx-1" onclick="setAmount(1)">1</button>
<button type="button" class="btn btn-outline-primary btn-sm flex-grow-1 mx-1" onclick="setAmount(5)">5</button>
<button type="button" class="btn btn-outline-primary btn-sm flex-grow-1 mx-1" onclick="setAmount(20)">20</button>
<button type="button" class="btn btn-outline-primary btn-sm flex-grow-1 mx-1" onclick="setAmount(50)">50</button>
<button type="button" class="btn btn-outline-secondary btn-sm flex-grow-1 mx-1" onclick="setAmount('more')">More</button>
</div>
<div class="input-group">
<span class="input-group-text bg-white border-end-0">OMR</span>
<input type="number" name="amount" class="form-control border-start-0 ps-0" step="1" min="1" placeholder="10" required>
</div>
</div>
<div class="mb-3">
<label class="form-label small fw-bold text-muted"><?= $t['modal_name'] ?></label>
<input type="text" name="donor_name" class="form-control" placeholder="<?= $t['modal_name_placeholder'] ?>">
</div>
<div class="row g-3 mb-3">
<div class="col-md-6">
<label class="form-label small fw-bold text-muted"><?= $t['modal_email'] ?></label>
<input type="email" name="donor_email" class="form-control" placeholder="<?= $t['modal_email_placeholder'] ?>">
</div>
<div class="col-md-6">
<label class="form-label small fw-bold text-muted"><?= $t['modal_phone'] ?></label>
<input type="tel" name="donor_phone" class="form-control" placeholder="<?= $t['modal_phone_placeholder'] ?>" required pattern="\d{8}" title="Please enter 8 digits.">
<div class="form-text small"><?= $t['modal_phone_hint'] ?></div>
</div>
</div>
<!-- Gift Fields -->
<div id="giftFields">
<div class="mb-3">
<label class="form-label small fw-bold text-muted"><?= $t['recipient_name'] ?></label>
<input type="text" name="gift_recipient_name" class="form-control" placeholder="Recipient Name">
</div>
<div class="mb-3">
<label class="form-label small fw-bold text-muted"><?= $t['recipient_phone'] ?></label>
<input type="tel" name="gift_recipient_phone" id="giftRecipientPhone" class="form-control" placeholder="<?= $t['modal_phone_placeholder'] ?>" pattern="\d{8}" title="Please enter 8 digits.">
<div class="form-text small"><?= $t['modal_phone_hint'] ?></div>
</div>
<div class="mb-3">
<label class="form-label small fw-bold text-muted"><?= $t['gift_message'] ?></label>
<textarea name="gift_message" class="form-control" rows="2" placeholder="Your message here..."></textarea>
</div>
<div class="small text-success">
<i class="bi bi-info-circle me-1"></i> <?= $t['gift_notice'] ?>
</div>
</div>
</div>
<div class="modal-footer border-0 p-4 pt-0">
<button type="submit" class.php'; ?>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
<script src="assets/js/main.js?v=<?php echo time(); ?>"></script>
<script>
const donateModal = document.getElementById('donateModal');
if (donateModal) {
donateModal.addEventListener('show.bs.modal', event => {
const button = event.relatedTarget;
const caseId = button.getAttribute('data-case-id');
const caseTitle = button.getAttribute('data-case-title');
donateModal.querySelector('#modalCaseId').value = caseId;
donateModal.querySelector('#modalCaseTitle').textContent = caseTitle;
});
}
function setDonateType(type) {
const isGift = type === 'gift';
document.getElementById('isGiftInput').value = isGift ? '1' : '0';
document.getElementById('giftFields').style.display = isGift ? 'block' : 'none';
document.querySelectorAll('.donate-type-btn').forEach(btn => {
btn.classList.toggle('active', btn.getAttribute('data-type') === type);
});
const recipientPhone = document.getElementById('giftRecipientPhone');
if (isGift) {
recipientPhone.setAttribute('required', 'required');
} else {
recipientPhone.removeAttribute('required');
}
}
function setAmount(amount) {
const amountInput = donateModal.querySelector('input[name="amount"]');
if (amount === 'more') {
amountInput.value = '';
amountInput.focus();
} else {
amountInput.value = amount;
}
}
function highlightCase(id) {
const el = document.getElementById('case-' + id);
if (el) {
el.scrollIntoView({ behavior: 'smooth', block: 'center' });
const card = el.querySelector('.case-card');
if (card) {
card.style.borderColor = 'var(--primary-color)';
card.style.boxShadow = '0 0 20px rgba(5, 150, 105, 0.2)';
setTimeout(() => {
card.style.borderColor = '';
card.style.boxShadow = '';
}, 2000);
}
}
}
</script>
</body>
</html>