Commit 6fb137f8 authored by Mahmoud Aglan's avatar Mahmoud Aglan

fixes

parent 055dd94f
...@@ -253,7 +253,9 @@ class BookingWizardController extends Controller ...@@ -253,7 +253,9 @@ class BookingWizardController extends Controller
{ {
$this->authorize('sa.booking_wizard.use'); $this->authorize('sa.booking_wizard.use');
$errors = $this->validate($request->allPost(), [ $data = $request->all();
$validator = new \App\Core\Validator();
$result = $validator->validate($data, [
'unit_id' => 'required|integer', 'unit_id' => 'required|integer',
'date' => 'required|date', 'date' => 'required|date',
'start_time' => 'required|string', 'start_time' => 'required|string',
...@@ -261,7 +263,7 @@ class BookingWizardController extends Controller ...@@ -261,7 +263,7 @@ class BookingWizardController extends Controller
'participants' => 'required|integer|min:1', 'participants' => 'required|integer|min:1',
'booker_name' => 'required|string|min:2|max:200', 'booker_name' => 'required|string|min:2|max:200',
]); ]);
if ($errors) { if ($result->fails()) {
return $this->json(['success' => false, 'error' => 'بيانات الحجز غير مكتملة']); return $this->json(['success' => false, 'error' => 'بيانات الحجز غير مكتملة']);
} }
......
...@@ -197,7 +197,9 @@ $capacityColor = $capacityPct >= 90 ? '#DC2626' : ($capacityPct >= 70 ? '#D97706 ...@@ -197,7 +197,9 @@ $capacityColor = $capacityPct >= 90 ? '#DC2626' : ($capacityPct >= 70 ? '#D97706
<?= csrf_field() ?> <?= csrf_field() ?>
<div style="flex:1;min-width:200px;"> <div style="flex:1;min-width:200px;">
<label class="form-label" style="font-size:11px;">إضافة لاعب</label> <label class="form-label" style="font-size:11px;">إضافة لاعب</label>
<select name="player_id" class="form-input" style="font-size:12px;" required id="addPlayerSelect"> <select name="player_id" class="form-select" style="font-size:12px;" required id="addPlayerSelect"
data-searchable="true"
data-placeholder="ابحث عن لاعب بالاسم...">
<option value="">-- اختر لاعب --</option> <option value="">-- اختر لاعب --</option>
<?php foreach ($players as $p): ?> <?php foreach ($players as $p): ?>
<option value="<?= (int) $p['player_id'] ?>" data-enrollment="<?= (int) $p['enrollment_id'] ?>"><?= e($p['player_name']) ?></option> <option value="<?= (int) $p['player_id'] ?>" data-enrollment="<?= (int) $p['enrollment_id'] ?>"><?= e($p['player_name']) ?></option>
......
...@@ -558,7 +558,7 @@ class TutorialController extends Controller ...@@ -558,7 +558,7 @@ class TutorialController extends Controller
public function exportPdf(Request $request): Response public function exportPdf(Request $request): Response
{ {
set_time_limit(1800); set_time_limit(600);
$dlToken = $_GET['dl'] ?? ''; $dlToken = $_GET['dl'] ?? '';
...@@ -572,6 +572,8 @@ class TutorialController extends Controller ...@@ -572,6 +572,8 @@ class TutorialController extends Controller
include __DIR__ . '/../Views/export_pdf.php'; include __DIR__ . '/../Views/export_pdf.php';
$html = ob_get_clean(); $html = ob_get_clean();
$html = $this->inlineImages($html);
$wkhtmltopdf = null; $wkhtmltopdf = null;
foreach (['/usr/local/bin/wkhtmltopdf', '/usr/bin/wkhtmltopdf'] as $path) { foreach (['/usr/local/bin/wkhtmltopdf', '/usr/bin/wkhtmltopdf'] as $path) {
if (file_exists($path) && is_executable($path)) { if (file_exists($path) && is_executable($path)) {
...@@ -591,10 +593,11 @@ class TutorialController extends Controller ...@@ -591,10 +593,11 @@ class TutorialController extends Controller
$cmd = escapeshellarg($wkhtmltopdf) $cmd = escapeshellarg($wkhtmltopdf)
. ' --encoding utf-8 --page-size A4' . ' --encoding utf-8 --page-size A4'
. ' --margin-top 15 --margin-bottom 15 --margin-left 12 --margin-right 12' . ' --margin-top 15 --margin-bottom 15 --margin-left 12 --margin-right 12'
. ' --enable-local-file-access' . ' --disable-local-file-access'
. ' --disable-javascript'
. ' --no-stop-slow-scripts' . ' --no-stop-slow-scripts'
. ' --javascript-delay 200' . ' --image-quality 70'
. ' --image-quality 85' . ' --image-dpi 150'
. ' --print-media-type' . ' --print-media-type'
. ' ' . escapeshellarg($tmpInput) . ' ' . escapeshellarg($tmpInput)
. ' ' . escapeshellarg($tmpOutput) . ' ' . escapeshellarg($tmpOutput)
...@@ -710,6 +713,79 @@ class TutorialController extends Controller ...@@ -710,6 +713,79 @@ class TutorialController extends Controller
return $book; return $book;
} }
private function inlineImages(string $html): string
{
return (string) preg_replace_callback(
'#src="file://([^"]+\.(png|jpg|jpeg|gif|webp))"#i',
function (array $m): string {
$path = $m[1];
if (!file_exists($path)) {
return $m[0];
}
$resized = $this->resizeForPdf($path);
$mime = match (strtolower($m[2])) {
'jpg', 'jpeg' => 'image/jpeg',
'gif' => 'image/gif',
'webp' => 'image/webp',
default => 'image/png',
};
return 'src="data:' . $mime . ';base64,' . base64_encode($resized) . '"';
},
$html
);
}
private function resizeForPdf(string $path): string
{
$info = @getimagesize($path);
if (!$info) {
return (string) file_get_contents($path);
}
[$origW, $origH, $type] = $info;
$maxW = 1200;
if ($origW <= $maxW) {
$img = match ($type) {
IMAGETYPE_PNG => @imagecreatefrompng($path),
IMAGETYPE_JPEG => @imagecreatefromjpeg($path),
IMAGETYPE_GIF => @imagecreatefromgif($path),
IMAGETYPE_WEBP => @imagecreatefromwebp($path),
default => null,
};
if (!$img) {
return (string) file_get_contents($path);
}
ob_start();
imagejpeg($img, null, 65);
imagedestroy($img);
return (string) ob_get_clean();
}
$newW = $maxW;
$newH = (int) round($origH * ($maxW / $origW));
$src = match ($type) {
IMAGETYPE_PNG => @imagecreatefrompng($path),
IMAGETYPE_JPEG => @imagecreatefromjpeg($path),
IMAGETYPE_GIF => @imagecreatefromgif($path),
IMAGETYPE_WEBP => @imagecreatefromwebp($path),
default => null,
};
if (!$src) {
return (string) file_get_contents($path);
}
$dst = imagecreatetruecolor($newW, $newH);
imagecopyresampled($dst, $src, 0, 0, 0, 0, $newW, $newH, $origW, $origH);
imagedestroy($src);
ob_start();
imagejpeg($dst, null, 65);
imagedestroy($dst);
return (string) ob_get_clean();
}
private function extractTutorialContent(string $raw): string private function extractTutorialContent(string $raw): string
{ {
$start = strpos($raw, '<div class="tut-page">'); $start = strpos($raw, '<div class="tut-page">');
......
...@@ -161,7 +161,7 @@ function startExport() { ...@@ -161,7 +161,7 @@ function startExport() {
progressStep.textContent = step.label; progressStep.textContent = step.label;
stepIndex++; stepIndex++;
if (stepIndex < exportSteps.length) { if (stepIndex < exportSteps.length) {
stepTimer = setTimeout(animateStep, 90000); stepTimer = setTimeout(animateStep, 8000);
} }
} }
animateStep(); animateStep();
...@@ -191,7 +191,7 @@ function startExport() { ...@@ -191,7 +191,7 @@ function startExport() {
} }
}, 2000); }, 2000);
// Safety timeout: 25 minutes max // Safety timeout: 5 minutes max
setTimeout(function() { setTimeout(function() {
if (document.getElementById('duringExport').style.display !== 'none') { if (document.getElementById('duringExport').style.display !== 'none') {
clearInterval(cookieTimer); clearInterval(cookieTimer);
...@@ -201,7 +201,7 @@ function startExport() { ...@@ -201,7 +201,7 @@ function startExport() {
var f = document.getElementById('exportFrame'); var f = document.getElementById('exportFrame');
if (f) f.remove(); if (f) f.remove();
} }
}, 1500000); }, 300000);
} }
function finishExport(success) { function finishExport(success) {
......
...@@ -156,6 +156,17 @@ var SearchableSelect = (function() { ...@@ -156,6 +156,17 @@ var SearchableSelect = (function() {
}; };
Instance.prototype.selectValue = function(value) { Instance.prototype.selectValue = function(value) {
// For AJAX results, the option may not exist in the original <select>
if (value && !Array.from(this.select.options).some(function(o) { return o.value === value; })) {
var found = this.filteredOptions.find(function(o) { return o.value === value; });
if (found) {
var newOpt = document.createElement('option');
newOpt.value = found.value;
newOpt.textContent = found.text;
this.select.appendChild(newOpt);
this.options.push({value: found.value, text: found.text, group: found.group || '', el: newOpt});
}
}
this.select.value = value; this.select.value = value;
this.syncLabel(); this.syncLabel();
this.close(); this.close();
......
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