> $blocks */ public function replaceBlocks(PreregistrationPage $page, array $blocks, Request $request): void { DB::transaction(function () use ($page, $blocks, $request): void { $page->load('blocks'); $oldPaths = $this->collectBlockImagePaths($page); $page->blocks()->delete(); $orderedKeys = array_keys($blocks); usort($orderedKeys, function (string|int $a, string|int $b) use ($blocks): int { /** @var array $rowA */ $rowA = $blocks[$a]; /** @var array $rowB */ $rowB = $blocks[$b]; return ((int) ($rowA['sort_order'] ?? 0)) <=> ((int) ($rowB['sort_order'] ?? 0)); }); $allNewPaths = []; foreach ($orderedKeys as $blockKey) { /** @var array $blockRow */ $blockRow = $blocks[$blockKey]; $type = (string) $blockRow['type']; /** @var array $content */ $content = is_array($blockRow['content'] ?? null) ? $blockRow['content'] : []; if ($type === 'text' && array_key_exists('body', $content) && is_string($content['body'])) { $content['body'] = ltrim($content['body']); } if ($type === 'image') { $content = $this->mergeImageBlockFiles($page, (string) $blockKey, $content, $request); } $allNewPaths = array_merge($allNewPaths, $this->pathsFromImageTypeContent($type, $content)); PageBlock::query()->create([ 'preregistration_page_id' => $page->id, 'type' => $type, 'content' => $content, 'sort_order' => (int) ($blockRow['sort_order'] ?? 0), 'is_visible' => (bool) ($blockRow['is_visible'] ?? true), ]); } $allNewPaths = array_values(array_unique($allNewPaths)); foreach (array_diff($oldPaths, $allNewPaths) as $orphan) { if (is_string($orphan) && $orphan !== '') { Storage::disk('public')->delete($orphan); } } }); } public function seedDefaultBlocks(PreregistrationPage $page): void { $rows = [ [ 'type' => 'hero', 'sort_order' => 0, 'is_visible' => true, 'content' => [ 'headline' => $page->title, 'subheadline' => '', 'eyebrow_text' => '', 'eyebrow_style' => 'badge', 'text_alignment' => 'center', ], ], ]; $next = 1; if ($page->start_date->isFuture()) { $rows[] = [ 'type' => 'countdown', 'sort_order' => $next, 'is_visible' => true, 'content' => [ 'target_datetime' => $page->start_date->toIso8601String(), 'title' => 'De pre-registratie opent over:', 'expired_action' => 'reload', 'style' => 'large', 'show_labels' => true, 'labels' => [ 'days' => 'dagen', 'hours' => 'uren', 'minutes' => 'minuten', 'seconds' => 'seconden', ], ], ]; $next++; } $rows[] = [ 'type' => 'benefits', 'sort_order' => $next, 'is_visible' => true, 'content' => [ 'title' => 'Waarom voorregistreren?', 'items' => [ ['icon' => 'ticket', 'text' => 'Exclusieve korting op tickets'], ['icon' => 'clock', 'text' => 'Eerder toegang tot de ticketshop'], ], 'layout' => 'list', 'max_columns' => 2, ], ]; $next++; $rows[] = [ 'type' => 'social_proof', 'sort_order' => $next, 'is_visible' => true, 'content' => [ 'template' => 'Al {count} bezoekers aangemeld!', 'min_count' => 10, 'show_animation' => true, 'style' => 'pill', ], ]; $next++; $rows[] = [ 'type' => 'form', 'sort_order' => $next, 'is_visible' => true, 'content' => [ 'title' => 'Registreer nu', 'description' => '', 'button_label' => 'Registreer nu!', 'button_color' => '#F47B20', 'button_text_color' => '#FFFFFF', 'fields' => [ 'first_name' => [ 'enabled' => true, 'required' => true, 'label' => 'Voornaam', 'placeholder' => 'Je voornaam', ], 'last_name' => [ 'enabled' => true, 'required' => true, 'label' => 'Achternaam', 'placeholder' => 'Je achternaam', ], 'email' => [ 'enabled' => true, 'required' => true, 'label' => 'E-mailadres', 'placeholder' => 'je@email.nl', ], 'phone' => [ 'enabled' => false, 'required' => false, 'label' => 'Mobiel', 'placeholder' => '+31 6 12345678', ], ], 'show_field_icons' => true, 'privacy_text' => 'Door je te registreren ga je akkoord met onze privacyverklaring.', 'privacy_url' => '', ], ]; $page->blocks()->createMany($rows); } /** * @return list */ private function collectBlockImagePaths(PreregistrationPage $page): array { $paths = []; foreach ($page->blocks as $b) { if ($b->type !== 'image') { continue; } $paths = array_merge($paths, $this->pathsFromImageTypeContent('image', is_array($b->content) ? $b->content : [])); } return array_values(array_unique($paths)); } /** * @param array $content * @return list */ private function pathsFromImageTypeContent(string $type, array $content): array { if ($type !== 'image') { return []; } $p = data_get($content, 'image'); if (is_string($p) && $p !== '') { return [$p]; } return []; } /** * @param array $content * @return array */ private function mergeImageBlockFiles(PreregistrationPage $page, string $blockKey, array $content, Request $request): array { $disk = Storage::disk('public'); $dir = "preregister/pages/{$page->id}"; $link = $content['link_url'] ?? null; $content['link_url'] = is_string($link) && trim($link) !== '' ? trim($link) : null; if ($request->boolean("blocks.$blockKey.remove_block_image")) { $prev = $content['image'] ?? null; if (is_string($prev) && $prev !== '') { $disk->delete($prev); } $content['image'] = null; } $file = $request->file("blocks.$blockKey.block_image"); if ($this->isValidUpload($file)) { if (isset($content['image']) && is_string($content['image']) && $content['image'] !== '') { $disk->delete($content['image']); } $content['image'] = $file->store($dir, 'public'); } return $content; } private function isValidUpload(?UploadedFile $file): bool { return $file !== null && $file->isValid(); } }