diff --git a/admin.php b/admin.php index 66476a8..0036a89 100644 --- a/admin.php +++ b/admin.php @@ -318,7 +318,9 @@ render_head( - + + + diff --git a/admin_courses.php b/admin_courses.php index 2549b01..1c6df1c 100644 --- a/admin_courses.php +++ b/admin_courses.php @@ -185,7 +185,7 @@ $items = $stmt->fetchAll(PDO::FETCH_ASSOC); - + @@ -303,7 +303,7 @@ $items = $stmt->fetchAll(PDO::FETCH_ASSOC);
- +
@@ -392,7 +392,7 @@ $items = $stmt->fetchAll(PDO::FETCH_ASSOC);
- +
diff --git a/admin_plans.php b/admin_plans.php new file mode 100644 index 0000000..d71c6c9 --- /dev/null +++ b/admin_plans.php @@ -0,0 +1,267 @@ + 0) { + $stmt = db()->prepare("DELETE FROM plans WHERE id = ?"); + $stmt->execute([$post_id]); + header('Location: ' . app_url('admin.php', ['page' => 'plans'])); + exit; + } + + if ($post_action === 'edit' || $post_action === 'add') { + $plan_key = $_POST['plan_key'] ?? ''; + $name_en = $_POST['name_en'] ?? ''; + $name_ar = $_POST['name_ar'] ?? ''; + $price_monthly = (float)($_POST['price_monthly'] ?? 0); + $price_yearly = (float)($_POST['price_yearly'] ?? 0); + $subjects_limit = (int)($_POST['subjects_limit'] ?? 1); + + $features_en_raw = $_POST['features_en'] ?? ''; + $features_ar_raw = $_POST['features_ar'] ?? ''; + + // Convert multiline text into JSON array + $features_en = array_values(array_filter(array_map('trim', explode("\n", $features_en_raw)))); + $features_ar = array_values(array_filter(array_map('trim', explode("\n", $features_ar_raw)))); + + $features_en_json = json_encode($features_en, JSON_UNESCAPED_UNICODE); + $features_ar_json = json_encode($features_ar, JSON_UNESCAPED_UNICODE); + + if ($post_action === 'edit' && $post_id > 0) { + $stmt = db()->prepare("UPDATE plans SET plan_key=?, name_en=?, name_ar=?, price_monthly=?, price_yearly=?, subjects_limit=?, features_en=?, features_ar=? WHERE id=?"); + $stmt->execute([$plan_key, $name_en, $name_ar, $price_monthly, $price_yearly, $subjects_limit, $features_en_json, $features_ar_json, $post_id]); + } else { + $stmt = db()->prepare("INSERT INTO plans (plan_key, name_en, name_ar, price_monthly, price_yearly, subjects_limit, features_en, features_ar) VALUES (?, ?, ?, ?, ?, ?, ?, ?)"); + $stmt->execute([$plan_key, $name_en, $name_ar, $price_monthly, $price_yearly, $subjects_limit, $features_en_json, $features_ar_json]); + } + header('Location: ' . app_url('admin.php', ['page' => 'plans'])); + exit; + } +} + +// list view +$search = $_GET['search'] ?? ''; +$page_num = max(1, (int)($_GET['p'] ?? 1)); +$limit = 10; +$offset = ($page_num - 1) * $limit; + +$where = ""; +$params = []; +if ($search !== '') { + $where = "WHERE name_en LIKE ? OR name_ar LIKE ? OR plan_key LIKE ?"; + $params[] = "%$search%"; + $params[] = "%$search%"; + $params[] = "%$search%"; +} + +$total_stmt = db()->prepare("SELECT COUNT(*) FROM plans $where"); +$total_stmt->execute($params); +$total = $total_stmt->fetchColumn(); +$pages = ceil($total / $limit); + +$stmt = db()->prepare("SELECT * FROM plans $where ORDER BY id DESC LIMIT $limit OFFSET $offset"); +$stmt->execute($params); +$items = $stmt->fetchAll(PDO::FETCH_ASSOC); +?> +
+
+

+
+
+ +
+
+ +
+
+ + + + + + +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ID
+
+
+ +
+ +
+
+
+
+ + 1): ?> + + + + + + diff --git a/checkout.php b/checkout.php index 94cdd62..6423723 100644 --- a/checkout.php +++ b/checkout.php @@ -265,7 +265,7 @@ render_nav('pricing.php');
- + diff --git a/includes/app.php b/includes/app.php index 1eccee7..1834784 100644 --- a/includes/app.php +++ b/includes/app.php @@ -434,11 +434,16 @@ function subject_modules(array $subject): array return current_lang() === 'ar' ? $subject['modules_ar'] : $subject['modules_en']; } +function format_price(float $amount): string +{ + return number_format($amount, 3) . ' ' . t('OMR', 'ر.ع.'); +} + function price_label(array $plan, string $cycle = 'monthly'): string { $amount = $cycle === 'yearly' ? $plan['price_yearly'] : $plan['price_monthly']; $suffix = $cycle === 'yearly' ? t('/year', '/سنة') : t('/month', '/شهر'); - return number_format((float)$amount, 3) . ' ' . t('OMR', 'ر.ع.') . $suffix; + return format_price((float)$amount) . ' ' . $suffix; } function ensure_subscription_table(): void diff --git a/index.php b/index.php index fa0e38c..eea1f2d 100644 --- a/index.php +++ b/index.php @@ -39,36 +39,6 @@ $metrics = ['subjects' => count($subjects), 'teachers' => db()->query("SELECT CO Hero Image -
-
-

- -
-
-
-
- -

-
- Thawani -
-
-
- -

-
- Meet -
-
-
- -

-
- Wablas -
-
- -
@@ -108,7 +78,7 @@ $metrics = ['subjects' => count($subjects), 'teachers' => db()->query("SELECT CO

- +

diff --git a/login.php b/login.php index 5001268..f1cfde8 100644 --- a/login.php +++ b/login.php @@ -38,6 +38,15 @@ render_nav('login.php');
+
+ + Logo + +
+ +
+ +

diff --git a/patch_index2.py b/patch_index2.py new file mode 100644 index 0000000..1d7539b --- /dev/null +++ b/patch_index2.py @@ -0,0 +1,15 @@ +import re + +with open("index.php", "r", encoding="utf-8") as f: + content = f.read() + +# Pattern to remove the entire panel-card block +pattern = r'
[\s\S]*?
\s*<\?php endif; \?>' +replacement = '' + +new_content = re.sub(pattern, replacement, content) + +with open("index.php", "w", encoding="utf-8") as f: + f.write(new_content) + +print("done") \ No newline at end of file diff --git a/profile.php b/profile.php index 432732a..ca4154a 100644 --- a/profile.php +++ b/profile.php @@ -14,14 +14,38 @@ $error = ''; if ($_SERVER['REQUEST_METHOD'] === 'POST') { $name = trim($_POST['name'] ?? ''); $email = trim($_POST['email'] ?? ''); + $phone = trim($_POST['phone'] ?? ''); $password = $_POST['password'] ?? ''; $password_confirm = $_POST['password_confirm'] ?? ''; + + $profile_picture = $user['profile_picture'] ?? null; + + // Handle image upload + if (isset($_FILES['profile_picture']) && $_FILES['profile_picture']['error'] === UPLOAD_ERR_OK) { + $allowed_types = ['image/jpeg', 'image/png', 'image/webp', 'image/gif']; + if (in_array($_FILES['profile_picture']['type'], $allowed_types)) { + $ext = pathinfo($_FILES['profile_picture']['name'], PATHINFO_EXTENSION); + $filename = 'user_' . $user['id'] . '_' . time() . '.' . $ext; + $upload_dir = __DIR__ . '/assets/images/uploads/'; + if (!is_dir($upload_dir)) { + mkdir($upload_dir, 0775, true); + } + $dest = $upload_dir . $filename; + if (move_uploaded_file($_FILES['profile_picture']['tmp_name'], $dest)) { + $profile_picture = 'assets/images/uploads/' . $filename; + } else { + $error = t('Failed to move uploaded file.', 'فشل نقل الملف المرفوع.'); + } + } else { + $error = t('Invalid image format. Only JPG, PNG, WEBP, and GIF are allowed.', 'تنسيق الصورة غير صالح. يُسمح فقط بـ JPG و PNG و WEBP و GIF.'); + } + } if (empty($name) || empty($email)) { - $error = t('Name and email are required.', 'الاسم والبريد الإلكتروني مطلوبان.'); + if (!$error) $error = t('Name and email are required.', 'الاسم والبريد الإلكتروني مطلوبان.'); } elseif ($password !== $password_confirm) { - $error = t('Passwords do not match.', 'كلمتا المرور غير متطابقتين.'); - } else { + if (!$error) $error = t('Passwords do not match.', 'كلمتا المرور غير متطابقتين.'); + } elseif (!$error) { $stmt = db()->prepare("SELECT id FROM users WHERE email = ? AND id != ?"); $stmt->execute([$email, $user['id']]); if ($stmt->fetchColumn()) { @@ -29,11 +53,11 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { } else { if ($password) { $hash = password_hash($password, PASSWORD_DEFAULT); - $update = db()->prepare("UPDATE users SET name = ?, email = ?, password = ? WHERE id = ?"); - $update->execute([$name, $email, $hash, $user['id']]); + $update = db()->prepare("UPDATE users SET name = ?, email = ?, phone = ?, profile_picture = ?, password = ? WHERE id = ?"); + $update->execute([$name, $email, $phone, $profile_picture, $hash, $user['id']]); } else { - $update = db()->prepare("UPDATE users SET name = ?, email = ? WHERE id = ?"); - $update->execute([$name, $email, $user['id']]); + $update = db()->prepare("UPDATE users SET name = ?, email = ?, phone = ?, profile_picture = ? WHERE id = ?"); + $update->execute([$name, $email, $phone, $profile_picture, $user['id']]); } $success = t('Profile updated successfully.', 'تم تحديث الملف الشخصي بنجاح.'); $user = get_logged_in_user(); // Refresh @@ -50,22 +74,45 @@ render_nav('profile.php');
-

+ +
+

+ + Profile Picture + +
+ +
+ +
+
-
+ + +
+ + +
+
+
-
+
+
+ + +
+
@@ -83,4 +130,4 @@ render_nav('profile.php');
- + \ No newline at end of file