diff --git a/app/Http/Controllers/Admin/QrCodeController.php b/app/Http/Controllers/Admin/QrCodeController.php index 6b102c2..dbb1d0b 100644 --- a/app/Http/Controllers/Admin/QrCodeController.php +++ b/app/Http/Controllers/Admin/QrCodeController.php @@ -3,9 +3,59 @@ namespace App\Http\Controllers\Admin; use App\Http\Controllers\Controller; -use Illuminate\Http\Request; +use App\Models\Program; +use App\Services\AuditLogService; +use App\Services\QrCodeService; +use Illuminate\Support\Str; +use Illuminate\Http\RedirectResponse; +use Illuminate\Http\Response; +use Illuminate\View\View; class QrCodeController extends Controller { - // + public function __construct(private QrCodeService $qrCodeService) {} + + public function show(Program $program): View + { + $qrCode = $program->qrCodes()->where('is_active', true)->latest()->first(); + + return view('admin.programs.qr', compact('program', 'qrCode')); + } + + public function generate(Program $program): RedirectResponse + { + $qrCode = $this->qrCodeService->generateForProgram($program); + + AuditLogService::log('qrcode.generated', $program); + + return redirect() + ->route('admin.programs.qr.show', $program) + ->with('success', 'QR Code berjaya dijana.'); + } + + public function download(Program $program): Response|RedirectResponse + { + $qrCode = $program->qrCodes()->where('is_active', true)->latest()->first(); + + if (! $qrCode) { + return back()->with('error', 'QR Code belum dijana.'); + } + + $png = $this->qrCodeService->getRawPng($qrCode); + $filename = 'QR_' . Str::slug($program->title) . '_' . now()->format('Ymd') . '.png'; + + return response($png, 200, [ + 'Content-Type' => 'image/png', + 'Content-Disposition' => 'attachment; filename="' . $filename . '"', + ]); + } + + public function deactivate(Program $program): RedirectResponse + { + $program->qrCodes()->where('is_active', true)->update(['is_active' => false]); + + AuditLogService::log('qrcode.deactivated', $program); + + return back()->with('success', 'QR Code berjaya dinyahaktifkan.'); + } } diff --git a/app/Services/QrCodeService.php b/app/Services/QrCodeService.php new file mode 100644 index 0000000..876436d --- /dev/null +++ b/app/Services/QrCodeService.php @@ -0,0 +1,51 @@ +qrCodes()->where('is_active', true)->update(['is_active' => false]); + + $token = Str::random(48); + $url = route('public.checkin.show', $token); + $path = 'public/qrcodes/' . $token . '.png'; + $absPath = Storage::path($path); + + // Ensure directory exists + Storage::makeDirectory('public/qrcodes'); + + // Generate QR code PNG (400×400, with quiet zone) + $png = QrCode::format('png') + ->size(400) + ->margin(2) + ->errorCorrection('H') + ->generate($url); + + Storage::put($path, $png); + + return $program->qrCodes()->create([ + 'token' => $token, + 'qr_image_path' => $path, + 'is_active' => true, + ]); + } + + public function getPublicUrl(ProgramQrCode $qrCode): string + { + return Storage::url($qrCode->qr_image_path); + } + + public function getRawPng(ProgramQrCode $qrCode): string + { + return Storage::get($qrCode->qr_image_path); + } +} diff --git a/resources/views/admin/programs/qr.blade.php b/resources/views/admin/programs/qr.blade.php new file mode 100644 index 0000000..f0821e2 --- /dev/null +++ b/resources/views/admin/programs/qr.blade.php @@ -0,0 +1,171 @@ +@extends('layouts.admin') + +@section('title', 'QR Code — ' . $program->title) +@section('header', 'QR Code Program') + +@section('breadcrumb') +
+ {{ $program->start_date->format('d M Y') }} + @if($program->start_date->ne($program->end_date)) + — {{ $program->end_date->format('d M Y') }} + @endif + · {{ $program->location }} +
+ + {{-- Check-in URL --}} +{{ route('public.checkin.show', $qrCode->token) }}
+
+ + Jana QR Code untuk membolehkan peserta scan dan check-in ke program ini. +
+ +