Commit ffa74159 authored by Mahmoud Aglan's avatar Mahmoud Aglan

go

parent 4372c4e4
......@@ -14,7 +14,8 @@ MenuRegistry::register('branches_settings', [
'children' => [
['label_ar' => 'الفروع', 'label_en' => 'Branches', 'route' => '/branches', 'permission' => 'settings.view', 'order' => 1],
['label_ar' => 'إعدادات النظام', 'label_en' => 'Settings', 'route' => '/settings', 'permission' => 'settings.view', 'order' => 2],
['label_ar' => 'سجل المراجعة', 'label_en' => 'Audit Log', 'route' => '/audit', 'permission' => 'report.view_audit', 'order' => 3],
['label_ar' => 'العلامة التجارية', 'label_en' => 'Branding', 'route' => '/settings/branding', 'permission' => 'settings.edit', 'order' => 3],
['label_ar' => 'سجل المراجعة', 'label_en' => 'Audit Log', 'route' => '/audit', 'permission' => 'report.view_audit', 'order' => 4],
],
]);
......
<?php
use App\Modules\Settings\Services\BrandingService;
$design = BrandingService::carnetDesign();
$clubNameAr = BrandingService::clubNameAr();
$clubNameEn = BrandingService::clubNameEn();
$clubSubtitle = BrandingService::subtitle();
$logoUrl = BrandingService::logo();
$bgColor = $design['front_bg_color'];
$textColor = $design['front_text_color'];
$showSub = $design['front_show_subtitle'];
$showEn = $design['front_show_english_name'];
$showType = $design['front_show_member_type'];
$showQr = $design['front_show_qr'];
$qrPos = $design['front_qr_position'];
$logoPos = $design['front_logo_position'];
$showStrip = $design['back_show_branch_strip'];
$stripColor = $design['back_strip_color'];
$showInstr = $design['back_show_instructions'];
$instrText = $design['back_instructions_text'];
$backFields = $design['back_fields'] ?? [];
// QR position CSS
$qrStyle = 'position:absolute;';
if (str_contains($qrPos, 'bottom')) $qrStyle .= 'bottom:15px;'; else $qrStyle .= 'top:15px;';
if (str_contains($qrPos, 'left')) $qrStyle .= 'left:15px;'; else $qrStyle .= 'right:15px;';
// Logo position CSS
$logoAlign = 'text-align:center;';
if ($logoPos === 'top-right') $logoAlign = 'text-align:right;';
elseif ($logoPos === 'top-left') $logoAlign = 'text-align:left;';
// Back field data map
$fieldLabels = [
'full_name_ar' => 'الاسم',
'full_name_en' => 'Name',
'membership_number' => 'رقم العضوية',
'branch_name' => 'الفرع',
'issued_at' => 'تاريخ الإصدار',
'national_id' => 'الرقم القومي',
'phone' => 'الهاتف',
];
$fieldValues = [
'full_name_ar' => $carnet['full_name_ar'] ?? '—',
'full_name_en' => $carnet['full_name_en'] ?? '—',
'membership_number' => $carnet['membership_number'] ?? '—',
'branch_name' => $carnet['branch_name'] ?? '—',
'issued_at' => isset($carnet['issued_at']) ? substr($carnet['issued_at'], 0, 10) : '—',
'national_id' => $carnet['national_id'] ?? '—',
'phone' => $carnet['phone'] ?? '—',
];
?>
<?php $__template->layout('Layout.print'); ?>
<?php $__template->section('title'); ?>كارنيه العضوية — <?= e($carnet['membership_number'] ?? $carnet['carnet_number']) ?><?php $__template->endSection(); ?>
<?php $__template->section('content'); ?>
<style>
@media print { body { margin: 0; } }
@media print { body { margin: 0; } .print-header { display: none; } }
.carnet-container { width: 340px; margin: 20px auto; font-family: 'Cairo', Arial, sans-serif; }
.carnet-front {
width: 340px; height: 215px; background: #0D7377; border-radius: 12px;
color: #fff; padding: 20px; position: relative; overflow: hidden; margin-bottom: 15px;
width: 340px; height: 215px; background: <?= e($bgColor) ?>; border-radius: 12px;
color: <?= e($textColor) ?>; padding: 20px; position: relative; overflow: hidden; margin-bottom: 15px;
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
}
.carnet-back {
width: 340px; height: 215px; background: #fff; border-radius: 12px;
border: 2px solid #0D7377; padding: 20px; position: relative;
border: 2px solid <?= e($stripColor) ?>; padding: 20px; position: relative;
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
}
.carnet-front .club-name { text-align: center; font-size: 16px; font-weight: 700; margin-bottom: 4px; }
.carnet-front .club-subtitle { text-align: center; font-size: 11px; opacity: 0.8; margin-bottom: 15px; }
.carnet-front .club-name { <?= $logoAlign ?> font-size: 16px; font-weight: 700; margin-bottom: 4px; }
.carnet-front .club-subtitle { <?= $logoAlign ?> font-size: 11px; opacity: 0.8; margin-bottom: 15px; }
.carnet-front .front-logo { <?= $logoAlign ?> margin-bottom: 8px; }
.carnet-front .front-logo img { max-height: 30px; }
.carnet-front .member-name { font-size: 14px; font-weight: 700; margin-bottom: 5px; }
.carnet-front .member-name-en { font-size: 11px; opacity: 0.8; margin-bottom: 8px; }
.carnet-front .member-number { font-size: 20px; font-weight: 700; letter-spacing: 2px; direction: ltr; text-align: right; }
.carnet-front .qr-area { position: absolute; bottom: 15px; left: 15px; width: 70px; height: 70px; background: #fff; border-radius: 6px; padding: 5px; }
.carnet-front .member-type { font-size: 11px; margin-top: 5px; opacity: 0.8; }
.carnet-front .qr-area { <?= $qrStyle ?> width: 70px; height: 70px; background: #fff; border-radius: 6px; padding: 5px; }
.carnet-front .qr-area svg { width: 60px; height: 60px; }
.carnet-front .carnet-num { position: absolute; bottom: 15px; right: 15px; font-size: 10px; opacity: 0.7; }
.carnet-back .back-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px; border-bottom: 2px solid #0D7377; padding-bottom: 10px; }
.carnet-back .back-header .logo-text { font-size: 12px; font-weight: 700; color: #0D7377; }
.carnet-back .branch-strip { position: absolute; left: 0; top: 0; bottom: 0; width: 30px; background: #0D7377; border-radius: 12px 0 0 12px; writing-mode: vertical-rl; text-orientation: mixed; display: flex; align-items: center; justify-content: center; color: #fff; font-size: 11px; font-weight: 600; }
.carnet-back .back-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px; border-bottom: 2px solid <?= e($stripColor) ?>; padding-bottom: 10px; }
.carnet-back .back-header .logo-text { font-size: 12px; font-weight: 700; color: <?= e($stripColor) ?>; }
.carnet-back .back-header .back-logo img { max-height: 25px; }
.carnet-back .branch-strip { position: absolute; left: 0; top: 0; bottom: 0; width: 30px; background: <?= e($stripColor) ?>; border-radius: 12px 0 0 12px; writing-mode: vertical-rl; text-orientation: mixed; display: flex; align-items: center; justify-content: center; color: #fff; font-size: 11px; font-weight: 600; }
.carnet-back .instructions { font-size: 10px; color: #6B7280; text-align: center; position: absolute; bottom: 10px; left: 40px; right: 10px; }
.carnet-back .member-info { margin-right: 35px; font-size: 12px; color: #1A1A2E; }
.carnet-back .member-info div { margin-bottom: 4px; }
.carnet-back .member-info strong { color: #0D7377; }
.carnet-back .member-info strong { color: <?= e($stripColor) ?>; }
</style>
<div class="carnet-container">
<!-- Front -->
<div class="carnet-front">
<div class="club-name">THE CLUB — نادي النادي شيراتون</div>
<div class="club-subtitle">SPORTS CITY</div>
<?php if ($logoUrl): ?>
<div class="front-logo"><img src="<?= e($logoUrl) ?>" alt="Logo"></div>
<?php endif; ?>
<div class="club-name"><?= e($clubNameEn) ?><?= e($clubNameAr) ?></div>
<?php if ($showSub): ?>
<div class="club-subtitle"><?= e($clubSubtitle) ?></div>
<?php endif; ?>
<div class="member-name"><?= e($carnet['full_name_ar']) ?></div>
<?php if ($carnet['full_name_en']): ?>
<div style="font-size:11px;opacity:0.8;margin-bottom:8px;"><?= e($carnet['full_name_en']) ?></div>
<?php if ($showEn && !empty($carnet['full_name_en'])): ?>
<div class="member-name-en"><?= e($carnet['full_name_en']) ?></div>
<?php endif; ?>
<div class="member-number"><?= e($carnet['membership_number'] ?? '—') ?></div>
<div style="font-size:11px;margin-top:5px;opacity:0.8;">
<?= $carnet['carnet_type'] === 'seasonal' ? 'عضوية موسمية' : 'عضو عامل' ?>
</div>
<div class="qr-area"><?= $qrSvg ?></div>
<?php if ($showType): ?>
<div class="member-type"><?= $carnet['carnet_type'] === 'seasonal' ? 'عضوية موسمية' : 'عضو عامل' ?></div>
<?php endif; ?>
<?php if ($showQr): ?>
<div class="qr-area"><?= $qrSvg ?></div>
<?php endif; ?>
<div class="carnet-num"><?= e($carnet['carnet_number']) ?></div>
</div>
<!-- Back -->
<div class="carnet-back">
<div class="branch-strip"><?= e($carnet['branch_name'] ?? 'فرع شيراتون') ?></div>
<?php if ($showStrip): ?>
<div class="branch-strip"><?= e($carnet['branch_name'] ?? 'فرع شيراتون') ?></div>
<?php endif; ?>
<div class="back-header">
<div class="logo-text">THE CLUB<br>نادي النادي</div>
<div style="font-size:20px;">🇪🇬</div>
<?php if ($logoUrl): ?>
<div class="back-logo"><img src="<?= e($logoUrl) ?>" alt="Logo"></div>
<?php else: ?>
<div class="logo-text"><?= e($clubNameEn) ?><br><?= e($clubNameAr) ?></div>
<?php endif; ?>
</div>
<div class="member-info">
<div><strong>الاسم:</strong> <?= e($carnet['full_name_ar']) ?></div>
<div><strong>رقم العضوية:</strong> <?= e($carnet['membership_number'] ?? '—') ?></div>
<div><strong>الفرع:</strong> <?= e($carnet['branch_name'] ?? '—') ?></div>
<div><strong>تاريخ الإصدار:</strong> <?= e(substr($carnet['issued_at'], 0, 10)) ?></div>
<?php foreach ($backFields as $field): ?>
<?php if (isset($fieldLabels[$field])): ?>
<div><strong><?= e($fieldLabels[$field]) ?>:</strong> <?= e($fieldValues[$field] ?? '—') ?></div>
<?php endif; ?>
<?php endforeach; ?>
</div>
<div class="instructions">برجاء حمل هذه البطاقة أثناء التواجد بالنادي وتقديمها عند الطلب</div>
<?php if ($showInstr): ?>
<div class="instructions"><?= e($instrText) ?></div>
<?php endif; ?>
</div>
</div>
<?php $__template->endSection(); ?>
\ No newline at end of file
<?php $__template->endSection(); ?>
This diff is collapsed.
<?php
declare(strict_types=1);
namespace App\Modules\Settings\Controllers;
use App\Core\Controller;
use App\Core\Request;
use App\Core\Response;
use App\Core\App;
use App\Modules\Settings\Models\SystemConfig;
use App\Modules\Settings\Services\BrandingService;
class BrandingController extends Controller
{
public function index(Request $request): Response
{
return $this->view('Settings.Views.branding', [
'logo' => BrandingService::logo(),
'clubNameAr' => BrandingService::clubNameAr(),
'clubNameEn' => BrandingService::clubNameEn(),
'subtitle' => BrandingService::subtitle(),
'carnetDesign' => BrandingService::carnetDesign(),
'receiptDesign' => BrandingService::receiptDesign(),
]);
}
public function updateLogo(Request $request): Response
{
// Handle club name / subtitle fields
$clubNameAr = trim($request->post('club_name_ar', ''));
$clubNameEn = trim($request->post('club_name_en', ''));
$subtitle = trim($request->post('club_subtitle', ''));
if ($clubNameAr !== '') {
SystemConfig::set('branding.club_name_ar', $clubNameAr);
}
if ($clubNameEn !== '') {
SystemConfig::set('branding.club_name_en', $clubNameEn);
}
SystemConfig::set('branding.club_subtitle', $subtitle);
// Handle logo upload
if ($request->hasFile('logo_file')) {
$file = $request->file('logo_file');
if ($file && $file['error'] === UPLOAD_ERR_OK) {
// Validate size (max 2MB)
if ($file['size'] > 2 * 1024 * 1024) {
return $this->redirect('/settings/branding')->withError('حجم الشعار يجب أن لا يتجاوز 2 ميجا');
}
// Validate MIME type
$finfo = new \finfo(FILEINFO_MIME_TYPE);
$mimeType = $finfo->file($file['tmp_name']);
$allowedTypes = ['image/png', 'image/jpeg', 'image/jpg', 'image/svg+xml', 'image/webp'];
if (!in_array($mimeType, $allowedTypes)) {
return $this->redirect('/settings/branding')->withError('نوع الملف غير مسموح (PNG, JPG, SVG, WebP فقط)');
}
// Generate filename
$ext = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
if ($ext === 'svg') $ext = 'svg';
$storedFilename = 'logo_' . date('Ymd_His') . '_' . bin2hex(random_bytes(4)) . '.' . $ext;
// Ensure upload directory exists
$uploadDir = App::getInstance()->basePath() . '/storage/uploads/branding/';
if (!is_dir($uploadDir)) {
mkdir($uploadDir, 0755, true);
}
$filePath = $uploadDir . $storedFilename;
if (!move_uploaded_file($file['tmp_name'], $filePath)) {
return $this->redirect('/settings/branding')->withError('فشل في حفظ الشعار');
}
// Delete old logo file if exists
$oldPath = BrandingService::logoFilePath();
if ($oldPath && file_exists($oldPath)) {
@unlink($oldPath);
}
// Save path to config
SystemConfig::set('branding.logo_path', 'storage/uploads/branding/' . $storedFilename);
BrandingService::clearCache();
}
}
// Handle logo removal
if ($request->post('remove_logo') === '1') {
$oldPath = BrandingService::logoFilePath();
if ($oldPath && file_exists($oldPath)) {
@unlink($oldPath);
}
SystemConfig::set('branding.logo_path', '');
}
BrandingService::clearCache();
return $this->redirect('/settings/branding')->withSuccess('تم تحديث الهوية البصرية بنجاح');
}
public function updateCarnetDesign(Request $request): Response
{
$design = [
'front_bg_color' => $request->post('front_bg_color', '#0D7377'),
'front_text_color' => $request->post('front_text_color', '#ffffff'),
'front_show_subtitle' => $request->post('front_show_subtitle') === '1',
'front_show_english_name'=> $request->post('front_show_english_name') === '1',
'front_show_member_type' => $request->post('front_show_member_type') === '1',
'front_show_qr' => $request->post('front_show_qr') === '1',
'front_qr_position' => $request->post('front_qr_position', 'bottom-left'),
'front_logo_position' => $request->post('front_logo_position', 'top-center'),
'back_show_branch_strip' => $request->post('back_show_branch_strip') === '1',
'back_strip_color' => $request->post('back_strip_color', '#0D7377'),
'back_show_instructions' => $request->post('back_show_instructions') === '1',
'back_instructions_text' => trim($request->post('back_instructions_text', '')),
'back_fields' => $request->post('back_fields') ? (array) $request->post('back_fields') : ['full_name_ar', 'membership_number'],
];
$json = json_encode($design, JSON_UNESCAPED_UNICODE);
SystemConfig::set('branding.carnet_design', $json);
BrandingService::clearCache();
return $this->redirect('/settings/branding')->withSuccess('تم تحديث تصميم الكارنيه بنجاح');
}
public function updateReceiptDesign(Request $request): Response
{
$design = [
'show_logo' => $request->post('show_logo') === '1',
'show_watermark' => $request->post('show_watermark') === '1',
'watermark_text' => trim($request->post('watermark_text', '')),
'watermark_opacity' => max(0.01, min(0.2, (float) $request->post('watermark_opacity', '0.06'))),
'header_color' => $request->post('header_color', '#0D7377'),
'show_footer_print_info' => $request->post('show_footer_print_info') === '1',
];
$json = json_encode($design, JSON_UNESCAPED_UNICODE);
SystemConfig::set('branding.receipt_design', $json);
BrandingService::clearCache();
return $this->redirect('/settings/branding')->withSuccess('تم تحديث تصميم الإيصال بنجاح');
}
}
......@@ -5,4 +5,10 @@ return [
['GET', '/settings', 'Settings\Controllers\SettingsController@index', ['auth'], 'settings.view'],
['GET', '/settings/group/{group}', 'Settings\Controllers\SettingsController@editGroup', ['auth'], 'settings.edit'],
['POST', '/settings/group/{group}', 'Settings\Controllers\SettingsController@updateGroup', ['auth', 'csrf'], 'settings.edit'],
// Branding
['GET', '/settings/branding', 'Settings\Controllers\BrandingController@index', ['auth'], 'settings.edit'],
['POST', '/settings/branding/logo', 'Settings\Controllers\BrandingController@updateLogo', ['auth', 'csrf'], 'settings.edit'],
['POST', '/settings/branding/carnet', 'Settings\Controllers\BrandingController@updateCarnetDesign', ['auth', 'csrf'], 'settings.edit'],
['POST', '/settings/branding/receipt', 'Settings\Controllers\BrandingController@updateReceiptDesign',['auth', 'csrf'], 'settings.edit'],
];
\ No newline at end of file
<?php
declare(strict_types=1);
namespace App\Modules\Settings\Services;
use App\Core\App;
/**
* BrandingService — Centralized access to branding configuration.
* Reads from system_config (group: branding) and caches per-request.
*/
class BrandingService
{
private static ?array $cache = null;
private static function load(): array
{
if (self::$cache !== null) {
return self::$cache;
}
try {
$db = App::getInstance()->db();
$rows = $db->select(
"SELECT config_key, config_value, config_type FROM system_config WHERE group_name = 'branding'"
);
} catch (\Throwable $e) {
$rows = [];
}
$data = [];
foreach ($rows as $row) {
$key = str_replace('branding.', '', $row['config_key']);
$value = $row['config_value'];
if ($row['config_type'] === 'json' && $value) {
$decoded = json_decode($value, true);
$data[$key] = is_array($decoded) ? $decoded : [];
} else {
$data[$key] = $value;
}
}
self::$cache = $data;
return $data;
}
/**
* Clear the cache (after updating branding settings).
*/
public static function clearCache(): void
{
self::$cache = null;
}
/**
* Get URL path to the logo image, or null if not set.
*/
public static function logo(): ?string
{
$data = self::load();
$path = $data['logo_path'] ?? null;
if ($path && $path !== '') {
// Return as web-accessible URL relative to public/
// Logo is stored in storage/uploads/branding/ — we need to serve it
// via a relative path from the app root
$basePath = rtrim(parse_url(config('app.url', ''), PHP_URL_PATH) ?: '', '/');
return $basePath . '/' . ltrim($path, '/');
}
return null;
}
/**
* Get the absolute file path to the logo, or null.
*/
public static function logoFilePath(): ?string
{
$data = self::load();
$path = $data['logo_path'] ?? null;
if ($path && $path !== '') {
$full = App::getInstance()->basePath() . '/' . ltrim($path, '/');
return file_exists($full) ? $full : null;
}
return null;
}
public static function clubNameAr(): string
{
$data = self::load();
return $data['club_name_ar'] ?? 'نادي النادي شيراتون';
}
public static function clubNameEn(): string
{
$data = self::load();
return $data['club_name_en'] ?? 'THE CLUB Sheraton';
}
public static function subtitle(): string
{
$data = self::load();
return $data['club_subtitle'] ?? 'SPORTS CITY';
}
/**
* Get carnet design configuration as an associative array.
*/
public static function carnetDesign(): array
{
$data = self::load();
$design = $data['carnet_design'] ?? [];
// Merge with defaults so views always have every key
return array_merge([
'front_bg_color' => '#0D7377',
'front_text_color' => '#ffffff',
'front_show_subtitle' => true,
'front_show_english_name' => true,
'front_show_member_type'=> true,
'front_show_qr' => true,
'front_qr_position' => 'bottom-left',
'front_logo_position' => 'top-center',
'back_show_branch_strip'=> true,
'back_strip_color' => '#0D7377',
'back_show_instructions'=> true,
'back_instructions_text'=> 'برجاء حمل هذه البطاقة أثناء التواجد بالنادي وتقديمها عند الطلب',
'back_fields' => ['full_name_ar', 'membership_number', 'branch_name', 'issued_at'],
], $design);
}
/**
* Get receipt design configuration as an associative array.
*/
public static function receiptDesign(): array
{
$data = self::load();
$design = $data['receipt_design'] ?? [];
return array_merge([
'show_logo' => true,
'show_watermark' => true,
'watermark_text' => 'نادي النادي شيراتون',
'watermark_opacity' => 0.06,
'header_color' => '#0D7377',
'show_footer_print_info'=> true,
], $design);
}
}
This diff is collapsed.
......@@ -6,6 +6,7 @@
use App\Core\App;
use App\Core\Registries\MenuRegistry;
use App\Modules\Settings\Services\BrandingService;
$currentPath = parse_url($_SERVER['REQUEST_URI'] ?? '/', PHP_URL_PATH);
$employee = App::getInstance()->currentEmployee();
......@@ -150,7 +151,12 @@ if (empty($menuItems)) {
?>
<div class="sidebar-header">
<div class="sidebar-brand">THE CLUB</div>
<?php $brandLogo = BrandingService::logo(); ?>
<?php if ($brandLogo): ?>
<img src="<?= e($brandLogo) ?>" alt="<?= e(BrandingService::clubNameEn()) ?>" class="sidebar-logo">
<?php else: ?>
<div class="sidebar-brand"><?= e(BrandingService::clubNameEn()) ?></div>
<?php endif; ?>
</div>
<nav class="sidebar-nav">
......
<?php
use App\Core\CSRF;
use App\Modules\Settings\Services\BrandingService;
$brandLogo = BrandingService::logo();
$brandNameAr = BrandingService::clubNameAr();
$brandNameEn = BrandingService::clubNameEn();
?>
<!DOCTYPE html>
<html lang="ar" dir="rtl">
......@@ -269,11 +274,17 @@ use App\Core\CSRF;
<div class="auth-card">
<div class="auth-header">
<div class="auth-logo">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg>
</div>
<h1>نادي النادي شيراتون</h1>
<p>THE CLUB Sheraton</p>
<?php if ($brandLogo): ?>
<div class="auth-logo" style="background:transparent;box-shadow:none;">
<img src="<?= e($brandLogo) ?>" alt="<?= e($brandNameEn) ?>" style="max-width:48px;max-height:48px;object-fit:contain;">
</div>
<?php else: ?>
<div class="auth-logo">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg>
</div>
<?php endif; ?>
<h1><?= e($brandNameAr) ?></h1>
<p><?= e($brandNameEn) ?></p>
</div>
<?php
......
......@@ -6,6 +6,7 @@
use App\Core\App;
use App\Core\CSRF;
use App\Modules\Settings\Services\BrandingService;
$app = App::getInstance();
$employee = $app->currentEmployee();
......@@ -90,7 +91,7 @@ $currentPath = parse_url($_SERVER['REQUEST_URI'] ?? '/', PHP_URL_PATH);
<!-- Footer -->
<footer class="page-footer">
<span>THE CLUB Sheraton &copy; <?= date('Y') ?></span>
<span><?= e(BrandingService::clubNameEn()) ?> &copy; <?= date('Y') ?></span>
<span>v1.0.0</span>
<span><?= arabic_date(date('Y-m-d')) ?></span>
</footer>
......
<?php use App\Modules\Settings\Services\BrandingService; ?>
<!DOCTYPE html>
<html lang="ar" dir="rtl">
<head>
......@@ -44,7 +45,11 @@
</head>
<body>
<div class="print-header">
<h2>نادي النادي شيراتون</h2>
<?php $printLogo = BrandingService::logo(); ?>
<?php if ($printLogo): ?>
<img src="<?= e($printLogo) ?>" alt="Logo" style="max-height:40px;margin-bottom:8px;">
<?php endif; ?>
<h2><?= e(BrandingService::clubNameAr()) ?></h2>
<p><?= arabic_date(today()) ?></p>
</div>
......
<?php
declare(strict_types=1);
use App\Core\Database;
return function (Database $db): void {
$configs = [
[
'config_key' => 'branding.logo_path',
'config_value' => '',
'config_type' => 'string',
'group_name' => 'branding',
'description_ar' => 'مسار شعار النادي',
'description_en' => 'Club logo file path',
'is_editable' => 1,
],
[
'config_key' => 'branding.club_name_ar',
'config_value' => 'نادي النادي شيراتون',
'config_type' => 'string',
'group_name' => 'branding',
'description_ar' => 'اسم النادي بالعربية',
'description_en' => 'Club name in Arabic',
'is_editable' => 1,
],
[
'config_key' => 'branding.club_name_en',
'config_value' => 'THE CLUB Sheraton',
'config_type' => 'string',
'group_name' => 'branding',
'description_ar' => 'اسم النادي بالإنجليزية',
'description_en' => 'Club name in English',
'is_editable' => 1,
],
[
'config_key' => 'branding.club_subtitle',
'config_value' => 'SPORTS CITY',
'config_type' => 'string',
'group_name' => 'branding',
'description_ar' => 'العنوان الفرعي للنادي',
'description_en' => 'Club subtitle',
'is_editable' => 1,
],
[
'config_key' => 'branding.carnet_design',
'config_value' => json_encode([
'front_bg_color' => '#0D7377',
'front_text_color' => '#ffffff',
'front_show_subtitle' => true,
'front_show_english_name'=> true,
'front_show_member_type' => true,
'front_show_qr' => true,
'front_qr_position' => 'bottom-left',
'front_logo_position' => 'top-center',
'back_show_branch_strip' => true,
'back_strip_color' => '#0D7377',
'back_show_instructions' => true,
'back_instructions_text' => 'برجاء حمل هذه البطاقة أثناء التواجد بالنادي وتقديمها عند الطلب',
'back_fields' => ['full_name_ar', 'membership_number', 'branch_name', 'issued_at'],
], JSON_UNESCAPED_UNICODE),
'config_type' => 'json',
'group_name' => 'branding',
'description_ar' => 'تصميم الكارنيه (وجه وخلفية)',
'description_en' => 'Carnet card design (front & back)',
'is_editable' => 1,
],
[
'config_key' => 'branding.receipt_design',
'config_value' => json_encode([
'show_logo' => true,
'show_watermark' => true,
'watermark_text' => 'نادي النادي شيراتون',
'watermark_opacity' => 0.06,
'header_color' => '#0D7377',
'show_footer_print_info' => true,
], JSON_UNESCAPED_UNICODE),
'config_type' => 'json',
'group_name' => 'branding',
'description_ar' => 'تصميم الإيصال (شعار وعلامة مائية)',
'description_en' => 'Receipt design (logo & watermark)',
'is_editable' => 1,
],
];
foreach ($configs as $config) {
$existing = $db->selectOne(
"SELECT id FROM system_config WHERE config_key = ?",
[$config['config_key']]
);
if ($existing) {
continue;
}
$db->insert('system_config', array_merge($config, [
'created_at' => date('Y-m-d H:i:s'),
'updated_at' => date('Y-m-d H:i:s'),
]));
}
};
This diff is collapsed.
......@@ -202,6 +202,17 @@ code {
background-clip: text;
}
.sidebar-logo {
max-height: 36px;
max-width: 180px;
object-fit: contain;
transition: opacity var(--duration-normal) ease;
}
.sidebar-logo:hover {
opacity: 0.85;
}
.sidebar-toggle {
background: none;
border: none;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment