diff --git a/checkout.php b/checkout.php index 1c48f7f..0172862 100644 --- a/checkout.php +++ b/checkout.php @@ -36,6 +36,7 @@ $donation_id = $pdo->lastInsertId(); // Thawani Checkout Session Request $payload = [ 'client_reference_id' => (string)$donation_id, + 'mode' => 'payment', 'products' => [ [ 'name' => $case['title_en'], @@ -51,9 +52,7 @@ $payload = [ ] ]; -// In a real scenario, we'd use CURL to call Thawani API. -// Since we don't have real keys, we'll mock the redirect or show a simulation. - +// Check if keys are default/empty if (THAWANI_SECRET_KEY === 'rRQ26GcsZ60u9Y9v9876543210' || empty(THAWANI_SECRET_KEY)) { // Simulation Mode ?> @@ -82,22 +81,42 @@ if (THAWANI_SECRET_KEY === 'rRQ26GcsZ60u9Y9v9876543210' || empty(THAWANI_SECRET_ exit; } -// REAL CURL CALL (if keys were valid) -/* +// REAL CURL CALL $ch = curl_init(THAWANI_API_URL . '/checkout/session'); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload)); curl_setopt($ch, CURLOPT_HTTPHEADER, [ 'Content-Type: application/json', - 'Thawani-Api-Key: ' . THAWANI_SECRET_KEY + 'thawani-api-key: ' . THAWANI_SECRET_KEY ]); $response = curl_exec($ch); -$data = json_decode($response, true); -if (isset($data['data']['session_id'])) { - $session_id = $data['data']['session_id']; - header("Location: https://checkout.thawani.om/pay/" . $session_id . "?key=" . THAWANI_PUBLISHABLE_KEY); -} else { - echo "Thawani Error: " . ($data['description'] ?? 'Unknown error'); +$err = curl_error($ch); +curl_close($ch); + +if ($err) { + die("CURL Error: " . $err); +} + +$data = json_decode($response, true); + +if (isset($data['success']) && $data['success'] === true && isset($data['data']['session_id'])) { + $session_id = $data['data']['session_id']; + + // Save session_id to donation record + $stmt = $pdo->prepare("UPDATE donations SET transaction_id = ? WHERE id = ?"); + $stmt->execute([$session_id, $donation_id]); + + $checkout_url = (THAWANI_ENV === 'sandbox') + ? "https://uatcheckout.thawani.om/pay/" . $session_id . "?key=" . THAWANI_PUBLISHABLE_KEY + : "https://checkout.thawani.om/pay/" . $session_id . "?key=" . THAWANI_PUBLISHABLE_KEY; + + header("Location: " . $checkout_url); + exit; +} else { + echo "

Thawani Error

"; + echo "
";
+    print_r($data);
+    echo "
"; + echo "Go Back"; } -*/ \ No newline at end of file diff --git a/index.php b/index.php index 82482e7..83618c2 100644 --- a/index.php +++ b/index.php @@ -20,7 +20,7 @@ $texts = [ '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 for this category.', + 'no_cases' => 'No active cases found matching your criteria.', 'admin_panel' => 'Admin Panel', 'modal_title' => 'Make a Donation', 'modal_amount' => 'Amount (OMR)', @@ -28,6 +28,14 @@ $texts = [ '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', ], 'ar' => [ 'title' => 'ادعم قضية', @@ -41,7 +49,7 @@ $texts = [ 'lang_code' => 'en', 'hero_title' => 'أحدث تأثيراً حقيقياً اليوم', 'hero_sub' => 'اختر حملة من فئاتنا الموثوقة وساعد في تغيير الأرواح في دقائق.', - 'no_cases' => 'لا توجد حالات نشطة لهذه الفئة.', + 'no_cases' => 'لم يتم العثور على حالات نشطة تطابق بحثك.', 'admin_panel' => 'لوحة التحكم', 'modal_title' => 'تبرع الآن', 'modal_amount' => 'المبلغ (ريال عماني)', @@ -49,6 +57,14 @@ $texts = [ 'modal_email' => 'البريد الإلكتروني', 'modal_phone' => 'رقم الهاتف', 'modal_submit' => 'الانتقال للدفع', + 'top_priority' => 'أولوية قصوى', + 'urgent' => 'عاجل', + 'featured' => 'مميز', + 'search_placeholder' => 'ابحث عن حالة...', + 'search_btn' => 'بحث', + 'new_badge' => 'جديد', + 'monthly_giving' => 'انضم إلى دائرة العطاء الشهري', + 'clear_search' => 'مسح البحث', ] ]; @@ -59,16 +75,36 @@ $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 = " . (int)$selected_cat; + $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"; -$cases = $pdo->query($sql)->fetchAll(); + +$stmt = $pdo->prepare($sql); +$stmt->execute($params); +$cases = $stmt->fetchAll(); // Project meta $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? $t['subtitle']; @@ -149,8 +185,64 @@ function safe_truncate($text, $limit = 120) { margin-inline-end: 12px; } + /* Ads/Featured Section Styles */ + .ads-container { + background: #fff; + border-bottom: 1px solid #e5e7eb; + padding: 10px 0; + overflow: hidden; + } + + .ads-scroller { + display: flex; + align-items: center; + gap: 20px; + overflow-x: auto; + scrollbar-width: none; + -ms-overflow-style: none; + } + .ads-scroller::-webkit-scrollbar { + display: none; + } + + .ad-item { + display: flex; + align-items: center; + background: #f9fafb; + border: 1px solid #e5e7eb; + border-radius: 9999px; + padding: 4px 16px 4px 6px; + white-space: nowrap; + font-size: 0.875rem; + color: var(--text-main); + text-decoration: none; + transition: all 0.2s; + cursor: pointer; + } + + .ad-item:hover { + border-color: var(--primary-color); + background: #fff; + color: var(--primary-color); + } + + .ad-badge { + background: #ef4444; + color: #fff; + font-size: 0.7rem; + font-weight: 800; + padding: 4px 10px; + border-radius: 9999px; + margin-inline-end: 10px; + text-transform: uppercase; + } + + .ad-title { + font-weight: 600; + } + .hero { - padding: 4rem 0; + padding: 4rem 0 3rem 0; background: #fff; border-bottom: 1px solid #e5e7eb; text-align: center; @@ -168,9 +260,53 @@ function safe_truncate($text, $limit = 120) { 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; @@ -204,7 +340,7 @@ function safe_truncate($text, $limit = 120) { border-radius: 16px; overflow: hidden; border: 1px solid #e5e7eb; - transition: transform 0.2s, box-shadow 0.2s; + transition: transform 0.2s, box-shadow 0.2s, border-color 0.3s; height: 100%; display: flex; flex-direction: column; @@ -338,27 +474,68 @@ function safe_truncate($text, $limit = 120) {
- +
+ +
+
+
+ + +
+ + +
+ + +
+ + + + +
+ + + + +
+ + +
+
+
+
+

+ +
+ +
- + - + @@ -370,6 +547,11 @@ function safe_truncate($text, $limit = 120) {

+ + + + +
@@ -379,12 +561,12 @@ function safe_truncate($text, $limit = 120) { $pct = min(100, round(($case['raised'] / $case['goal']) * 100)); $desc = safe_truncate($lang === 'en' ? $case['desc_en'] : $case['desc_ar'], 120); ?> -
+
- +
@@ -489,6 +671,22 @@ function safe_truncate($text, $limit = 120) { donateModal.querySelector('#modalCaseTitle').textContent = caseTitle; }); } + + 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); + } + } + } \ No newline at end of file diff --git a/success.php b/success.php index 1e26147..e9fe085 100644 --- a/success.php +++ b/success.php @@ -1,5 +1,6 @@ prepare("SELECT * FROM donations WHERE id = ? AND status = 'pending'"); $stmt->execute([$donation_id]); $donation = $stmt->fetch(); } else { - // Real Thawani verification logic would go here - // In real scenario, we'd fetch the donation record by the session_id or client_reference_id - $stmt = $pdo->prepare("SELECT * FROM donations WHERE transaction_id = ? OR id = (SELECT id FROM donations WHERE status='pending' LIMIT 1)"); // Simplified for now - // Actually, in real Thawani flow, we should query by session_id - // For now, let's keep it simple as the project seems to be in a prototype/simulation phase - $stmt = $pdo->prepare("SELECT * FROM donations WHERE id = ? AND status = 'pending'"); - $stmt->execute([$donation_id]); - $donation = $stmt->fetch(); + // Real Thawani verification + $ch = curl_init(THAWANI_API_URL . '/checkout/session/' . $session_id); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_HTTPHEADER, [ + 'Content-Type: application/json', + 'thawani-api-key: ' . THAWANI_SECRET_KEY + ]); + $response = curl_exec($ch); + curl_close($ch); + + $data = json_decode($response, true); + + if (isset($data['success']) && $data['success'] === true && $data['data']['payment_status'] === 'paid') { + $donation_id = $data['data']['client_reference_id']; + $stmt = $pdo->prepare("SELECT * FROM donations WHERE id = ? AND status = 'pending'"); + $stmt->execute([$donation_id]); + $donation = $stmt->fetch(); + } } +// 2. Process success if ($donation) { // Update donation status $pdo->prepare("UPDATE donations SET status = 'completed', transaction_id = ? WHERE id = ?") @@ -48,7 +62,12 @@ if ($donation) { $success = true; } else { - $success = false; + // Check if it was already completed (user refreshed page) + $stmt = $pdo->prepare("SELECT * FROM donations WHERE transaction_id = ? AND status = 'completed'"); + $stmt->execute([$session_id]); + if ($stmt->fetch()) { + $success = true; + } } ?> @@ -58,26 +77,54 @@ if ($donation) { Donation Successful - CharityHub + - -
- -
-
- - - -
-

Thank You!

-

Your donation has been successfully processed. You have made a real difference today.

-
-

A confirmation message has been sent to your WhatsApp number.

- Back to Home + +
+
+
+ +
+
+ + + +
+

Thank You!

+

Your donation has been successfully processed. Your generosity helps us continue our mission.

+
+
+ Transaction ID + +
+
+ Status + Completed +
+
+

A confirmation message has been sent to your WhatsApp number.

+ Return to Home +
+ +
+
+ + + +
+

Payment Verification Failed

+

We couldn't verify your payment. If you believe this is an error, please contact support.

+ Back to Home +
+
- -
Something went wrong or the donation was already processed.
- Back to Home - +
- \ No newline at end of file +