qrCodes() ->where('type', QrCode::TYPE_CHURCH) ->latest() ->get(); $previewDataUris = $qrCodes->mapWithKeys(function (QrCode $qr) { return [$qr->id => $this->imageGenerator->previewDataUri($qr)]; }); return view('give.giving-pages.index', [ 'qrCodes' => $qrCodes, 'previewDataUris' => $previewDataUris, ]); } public function create(): View { return view('give.giving-pages.create'); } public function store(Request $request): RedirectResponse { $account = ladill_account(); $request->validate([ 'label' => ['required', 'string', 'max:120'], 'name' => ['required', 'string', 'max:120'], 'org_type' => ['required', 'in:church,school,mosque,ngo,club'], 'denomination' => ['nullable', 'string', 'max:120'], 'description' => ['nullable', 'string', 'max:2000'], 'phone' => ['nullable', 'string', 'max:30'], 'email' => ['nullable', 'email', 'max:200'], 'website' => ['nullable', 'url', 'max:2048'], 'address' => ['nullable', 'string', 'max:500'], 'service_times' => ['nullable', 'string', 'max:200'], 'brand_color' => ['nullable', 'string', 'max:20'], 'collection_types' => ['nullable', 'array', 'min:1'], 'collection_types.*' => ['string', 'max:80'], 'church_logo' => ['nullable', 'image', 'mimes:jpeg,jpg,png,gif,webp', 'max:4096'], 'church_cover' => ['nullable', 'image', 'mimes:jpeg,jpg,png,gif,webp', 'max:8192'], ]); $data = array_merge($request->all(), [ 'type' => QrCode::TYPE_CHURCH, 'currency' => 'GHS', 'accepts_payment' => true, 'church_logo' => $request->file('church_logo'), 'church_cover' => $request->file('church_cover'), ]); try { $qrCode = $this->manager->create($account, $data); } catch (RuntimeException $e) { return back()->withInput()->with('error', $e->getMessage()); } return redirect()->route('give.giving-pages.show', $qrCode)->with('success', 'Giving page created.'); } public function show(QrCode $givingPage): View { $this->authorizeGivingPage($givingPage); return view('give.giving-pages.show', [ 'qrCode' => $givingPage->fresh(), 'previewDataUri' => $this->imageGenerator->previewDataUri($givingPage), ]); } public function update(Request $request, QrCode $givingPage): RedirectResponse { $this->authorizeGivingPage($givingPage); $request->validate([ 'label' => ['sometimes', 'string', 'max:120'], 'name' => ['sometimes', 'string', 'max:120'], 'org_type' => ['sometimes', 'in:church,school,mosque,ngo,club'], 'denomination' => ['nullable', 'string', 'max:120'], 'description' => ['nullable', 'string', 'max:2000'], 'phone' => ['nullable', 'string', 'max:30'], 'email' => ['nullable', 'email', 'max:200'], 'website' => ['nullable', 'url', 'max:2048'], 'address' => ['nullable', 'string', 'max:500'], 'service_times' => ['nullable', 'string', 'max:200'], 'brand_color' => ['nullable', 'string', 'max:20'], 'collection_types' => ['nullable', 'array', 'min:1'], 'collection_types.*' => ['string', 'max:80'], 'is_active' => ['sometimes', 'boolean'], 'church_logo' => ['nullable', 'image', 'mimes:jpeg,jpg,png,gif,webp', 'max:4096'], 'church_cover' => ['nullable', 'image', 'mimes:jpeg,jpg,png,gif,webp', 'max:8192'], ]); $data = array_merge($request->all(), [ 'accepts_payment' => true, 'is_active' => $request->boolean('is_active', $givingPage->is_active), 'church_logo' => $request->file('church_logo'), 'church_cover' => $request->file('church_cover'), ]); try { $this->manager->update($givingPage, $data); } catch (RuntimeException $e) { return back()->withInput()->with('error', $e->getMessage()); } return back()->with('success', 'Giving page updated.'); } public function destroy(QrCode $givingPage): RedirectResponse { $this->authorizeGivingPage($givingPage); $this->manager->delete($givingPage); return redirect() ->route('give.giving-pages.index') ->with('success', 'Giving page deleted.'); } public function preview(QrCode $givingPage): Response { $this->authorizeGivingPage($givingPage); $qrCode = $this->imageGenerator->ensureValidImages($givingPage); $bytes = $this->imageGenerator->normalizeStoredPng($qrCode->png_path); if ($bytes === null) { $bytes = $this->imageGenerator->renderPng($qrCode->encodedPayload(), $qrCode->style()); $this->imageGenerator->generateAndStore($qrCode); } return response($bytes, 200, [ 'Content-Type' => 'image/png', 'Cache-Control' => 'private, max-age=3600', ]); } public function download(QrCode $givingPage, string $format): StreamedResponse { $this->authorizeGivingPage($givingPage); $qrCode = $this->imageGenerator->ensureValidImages($givingPage); $path = $format === 'svg' ? $qrCode->svg_path : $qrCode->png_path; $filename = Str::slug($qrCode->label).'-qr.'.($format === 'svg' ? 'svg' : 'png'); if ($format === 'png') { $bytes = $this->imageGenerator->normalizeStoredPng($path); if ($bytes === null) { $bytes = $this->imageGenerator->renderPng($qrCode->encodedPayload(), $qrCode->style()); $this->imageGenerator->generateAndStore($qrCode); } return response()->streamDownload(fn () => print($bytes), $filename, [ 'Content-Type' => 'image/png', ]); } if ($format === 'pdf') { $bytes = $this->imageGenerator->normalizeStoredPng($qrCode->png_path); if ($bytes === null) { $bytes = $this->imageGenerator->renderPng($qrCode->encodedPayload(), $qrCode->style()); $this->imageGenerator->generateAndStore($qrCode); } $pdf = $this->pdfExporter->fromPng($bytes, $qrCode->label); return response()->streamDownload(fn () => print($pdf), Str::slug($qrCode->label).'-qr.pdf', [ 'Content-Type' => 'application/pdf', ]); } abort_unless($path && Storage::disk('qr')->exists($path), 404); return Storage::disk('qr')->download($path, $filename); } private function authorizeGivingPage(QrCode $givingPage): void { abort_unless($givingPage->type === QrCode::TYPE_CHURCH, 404); abort_unless($givingPage->user_id === ladill_account()->id, 403); } }