add welcome message

This commit is contained in:
Flatlogic Bot 2026-03-13 17:39:36 +00:00
parent 7fefc460c2
commit f2a3c9ce49
5 changed files with 137 additions and 7 deletions

View File

@ -0,0 +1,40 @@
<?php
// db/migrations/add_welcome_template.php
require_once __DIR__ . '/../../db/config.php';
$pdo = db();
$templates = [
[
'event_name' => 'welcome_message',
'email_subject_en' => 'Welcome to CargoLink!',
'email_body_en' => "Dear {user_name},\n\nWelcome to CargoLink! We are excited to have you on board.\n\nYou can now log in to your dashboard and start using our services.\n\nBest regards,\nThe CargoLink Team",
'email_subject_ar' => 'مرحباً بك في كارجو لينك!',
'email_body_ar' => "عزيزي {user_name}،\n\nمرحباً بك في كارجو لينك! نحن سعداء بانضمامك إلينا.\n\nيمكنك الآن تسجيل الدخول إلى لوحة التحكم والبدء في استخدام خدماتنا.\n\nتحياتنا،\nفريق كارجو لينك",
'whatsapp_body_en' => "Welcome to CargoLink, {user_name}! 🚚\n\nWe're glad to have you with us. Log in now to get started: https://cargolink.om",
'whatsapp_body_ar' => "مرحباً بك في كارجو لينك، {user_name}! 🚚\n\nسعداء بانضمامك إلينا. سجل الدخول الآن للبدء: https://cargolink.om"
]
];
foreach ($templates as $t) {
$stmt = $pdo->prepare("SELECT id FROM notification_templates WHERE event_name = ?");
$stmt->execute([$t['event_name']]);
if (!$stmt->fetch()) {
$sql = "INSERT INTO notification_templates (event_name, email_subject_en, email_body_en, email_subject_ar, email_body_ar, whatsapp_body_en, whatsapp_body_ar) VALUES (?, ?, ?, ?, ?, ?, ?)";
$pdo->prepare($sql)->execute([
$t['event_name'],
$t['email_subject_en'],
$t['email_body_en'],
$t['email_subject_ar'],
$t['email_body_ar'],
$t['whatsapp_body_en'],
$t['whatsapp_body_ar']
]);
echo "Added template: {$t['event_name']}\n";
} else {
echo "Template already exists: {$t['event_name']}\n";
}
}

View File

@ -203,7 +203,25 @@ $translations = [
'select_city_placeholder' => 'Select City',
'loading_cities' => 'Loading...',
'error_loading_cities' => 'Error loading cities',
'cancel' => 'Cancel'
'cancel' => 'Cancel',
'my_profile' => 'My Profile',
'profile_picture' => 'Profile Picture',
'change_picture' => 'Change Picture',
'picture_hint' => 'Click the camera icon to update.',
'full_name' => 'Full Name',
'email_address' => 'Email Address',
'email_hint' => 'Email cannot be changed.',
'account_role' => 'Account Role',
'change_password' => 'Change Password',
'new_password' => 'New Password',
'confirm_password' => 'Confirm Password',
'save_changes' => 'Save Changes',
'passwords_do_not_match' => 'Passwords do not match.',
'password_too_short' => 'Password must be at least 6 characters.',
'profile_updated' => 'Profile updated successfully.',
'password_updated' => 'Password updated successfully.',
'upload_failed' => 'File upload failed.',
'invalid_image' => 'Invalid image format. Allowed: JPG, PNG, GIF, WEBP.'
),
"ar" => array (
'app_name' => 'CargoLink',
@ -395,7 +413,25 @@ $translations = [
'select_city_placeholder' => 'اختر المدينة',
'loading_cities' => 'جاري التحميل...',
'error_loading_cities' => 'خطأ في تحميل المدن',
'cancel' => 'إلغاء'
'cancel' => 'إلغاء',
'my_profile' => 'ملفي الشخصي',
'profile_picture' => 'صورة الملف الشخصي',
'change_picture' => 'تغيير الصورة',
'picture_hint' => 'انقر على أيقونة الكاميرا للتحديث.',
'full_name' => 'الاسم الكامل',
'email_address' => 'البريد الإلكتروني',
'email_hint' => 'لا يمكن تغيير البريد الإلكتروني.',
'account_role' => 'نوع الحساب',
'change_password' => 'تغيير كلمة المرور',
'new_password' => 'كلمة المرور الجديدة',
'confirm_password' => 'تأكيد كلمة المرور',
'save_changes' => 'حفظ التغييرات',
'passwords_do_not_match' => 'كلمات المرور غير متطابقة.',
'password_too_short' => 'يجب أن تكون كلمة المرور 6 أحرف على الأقل.',
'profile_updated' => 'تم تحديث الملف الشخصي بنجاح.',
'password_updated' => 'تم تحديث كلمة المرور بنجاح.',
'upload_failed' => 'فشل تحميل الملف.',
'invalid_image' => 'تنسيق الصورة غير صالح. المسموح: JPG, PNG, GIF, WEBP.'
)
];
@ -609,4 +645,4 @@ function has_permission(string $permissionSlug, ?int $userId = null): bool
function format_currency(float $amount): string
{
return number_format($amount, 3) . ' OMR';
}
}

View File

@ -12,6 +12,20 @@ function render_header(string $title, string $active = '', bool $isFluid = false
$appName = get_setting('company_name', t('app_name'));
$logoPath = get_setting('logo_path');
$faviconPath = get_setting('favicon_path');
$navUserPic = '';
$navUserName = 'Account';
if (isset($_SESSION['user_id'])) {
try {
$stmt = db()->prepare("SELECT full_name, profile_picture FROM users WHERE id = ?");
$stmt->execute([$_SESSION['user_id']]);
$u = $stmt->fetch();
if ($u) {
$navUserName = $u['full_name'];
$navUserPic = $u['profile_picture'];
}
} catch (Throwable $e) {}
}
?>
<!doctype html>
<html lang="<?= e($lang) ?>" dir="<?= e($dir) ?>">
@ -96,13 +110,20 @@ function render_header(string $title, string $active = '', bool $isFluid = false
<div class="dropdown">
<?php if (isset($_SESSION['user_id'])): ?>
<a class="text-decoration-none text-muted fw-semibold dropdown-toggle" href="#" id="loginDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false">
Account
<a class="text-decoration-none text-muted fw-semibold dropdown-toggle d-flex align-items-center gap-2" href="#" id="loginDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false">
<?php if ($navUserPic): ?>
<img src="<?= e($navUserPic) ?>" alt="User" class="rounded-circle object-fit-cover shadow-sm" style="width:32px; height:32px;">
<?php else: ?>
<div class="rounded-circle bg-light d-flex align-items-center justify-content-center shadow-sm text-secondary" style="width:32px; height:32px;">
<i class="bi bi-person-fill"></i>
</div>
<?php endif; ?>
<span class="d-none d-sm-inline"><?= e($navUserName) ?></span>
</a>
<ul class="dropdown-menu dropdown-menu-end shadow-sm border-0 mt-3" aria-labelledby="loginDropdown" style="border-radius: 12px;">
<li>
<a class="dropdown-item py-2 <?= $active === 'profile' ? 'active' : '' ?>" href="<?= e(url_with_lang('profile.php')) ?>">
<i class="bi bi-person-circle text-primary me-2"></i>My Profile
<i class="bi bi-person-circle text-primary me-2"></i><?= e(t('my_profile')) ?>
</a>
</li>
<?php if (($_SESSION['user_role'] ?? '') === 'shipper'): ?>
@ -358,4 +379,4 @@ function render_admin_sidebar(string $active = 'dashboard'): void
</div>
</aside>
<?php
}
}

View File

@ -78,6 +78,22 @@ render_header('Login / Reset Password', 'login', false, false);
<div class="row justify-content-center align-items-center" style="min-height: 75vh;">
<div class="col-md-6 col-lg-5">
<div class="text-center mb-5">
<?php
$appName = get_setting('company_name', t('app_name'));
$logoPath = get_setting('logo_path');
?>
<?php if ($logoPath): ?>
<img src="<?= e($logoPath) ?>" alt="<?= e($appName) ?> Logo" class="img-fluid mb-3" style="max-height: 80px;">
<?php else: ?>
<div class="d-inline-flex align-items-center justify-content-center bg-primary text-white rounded-circle shadow-lg mb-3" style="width: 80px; height: 80px;">
<i class="bi bi-truck fs-1"></i>
</div>
<?php endif; ?>
<h1 class="fw-bold text-dark display-6"><?= e($appName) ?></h1>
<p class="text-muted lead">Your logistics partner</p>
</div>
<?php if ($errors): ?>
<div class="alert alert-danger shadow-sm rounded-4 border-0 mb-4">
<ul class="mb-0">

View File

@ -194,6 +194,23 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$pdo->rollBack();
} else {
$pdo->commit();
// Send Welcome Notification
$user = [
'id' => $userId,
'email' => $email,
'full_name' => $fullName,
'role' => $role,
'phone' => $phone
];
try {
require_once __DIR__ . '/includes/NotificationService.php';
NotificationService::send('welcome_message', $user, [], $lang);
} catch (Throwable $e) {
error_log('Failed to send welcome notification: ' . $e->getMessage());
}
$saved = true;
$saved_role = $role;
$values = [