From 43ff6d6407def63a717d3d06241b4d2a08aae99a Mon Sep 17 00:00:00 2001 From: boban Date: Sat, 16 May 2026 17:01:16 +0200 Subject: [PATCH] =?UTF-8?q?fix(FIX-10):=206=20bugs=20=E2=80=94=20route=20U?= =?UTF-8?q?LID,=20QR=20modal,=20bio=20unique,=20nav=20active,=20copy=20btn?= =?UTF-8?q?,=20analytics=20context?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Workspace.getRouteKeyName()='ulid' so route() generates ULID URLs not ID - QR modal 4xl→5xl; import QRCode in @script→window.QRCode (no ESM in @script) - Bio slug unique rule scoped to (workspace_id, domain_id) not global - updateActiveNav uses URL.pathname not raw getAttribute('href') (absolute URL fix) - Add resources/views/components/ui/copy-button.blade.php Alpine component - Analytics Index.render/baseQuery use $workspaceId not require_workspace() — prevents RuntimeException on Livewire action calls without middleware Co-Authored-By: Claude Sonnet 4.6 --- app/Domains/Workspace/Models/Workspace.php | 5 +++ app/Livewire/Modals/CreateBioPage.php | 17 ++++++++-- app/Livewire/Modals/CreateQrCode.php | 2 +- app/Livewire/Pages/Analytics/Index.php | 16 +++++----- resources/js/bootstrap.js | 3 ++ .../views/components/ui/copy-button.blade.php | 31 +++++++++++++++++++ resources/views/layouts/nimuli-app.blade.php | 2 +- .../livewire/modals/create-qr-code.blade.php | 2 +- 8 files changed, 65 insertions(+), 13 deletions(-) create mode 100644 resources/views/components/ui/copy-button.blade.php diff --git a/app/Domains/Workspace/Models/Workspace.php b/app/Domains/Workspace/Models/Workspace.php index 3f64dbc..995d846 100644 --- a/app/Domains/Workspace/Models/Workspace.php +++ b/app/Domains/Workspace/Models/Workspace.php @@ -43,6 +43,11 @@ class Workspace extends Model 'trial_ends_at' => 'datetime', ]; + public function getRouteKeyName(): string + { + return 'ulid'; + } + /** @return BelongsTo */ public function owner(): BelongsTo { diff --git a/app/Livewire/Modals/CreateBioPage.php b/app/Livewire/Modals/CreateBioPage.php index 5dfa013..eddffcd 100644 --- a/app/Livewire/Modals/CreateBioPage.php +++ b/app/Livewire/Modals/CreateBioPage.php @@ -6,6 +6,7 @@ use App\Domains\Bio\Models\BioPage; use App\Domains\Workspace\Models\Workspace; use App\Livewire\Pages\Bio\Index; use Illuminate\Support\Str; +use Illuminate\Validation\Rule; use Illuminate\View\View; use LivewireUI\Modal\ModalComponent; @@ -19,12 +20,24 @@ class CreateBioPage extends ModalComponent public string $slug = ''; - /** @return array */ + /** @return array */ protected function rules(): array { + $wsId = $this->workspaceId; + if (! $wsId) { + $ws = current_workspace(); + $wsId = $ws !== null ? $ws->id : 0; + } + return [ 'title' => 'required|max:200', - 'slug' => 'nullable|alpha_dash|max:80|unique:bio_pages,slug', + 'slug' => [ + 'nullable', 'alpha_dash', 'max:80', + Rule::unique('bio_pages', 'slug') + ->where('workspace_id', $wsId) + ->whereNull('domain_id') + ->whereNull('deleted_at'), + ], ]; } diff --git a/app/Livewire/Modals/CreateQrCode.php b/app/Livewire/Modals/CreateQrCode.php index fe65a47..8f5b19a 100644 --- a/app/Livewire/Modals/CreateQrCode.php +++ b/app/Livewire/Modals/CreateQrCode.php @@ -191,7 +191,7 @@ class CreateQrCode extends ModalComponent public static function modalMaxWidth(): string { - return '4xl'; + return '5xl'; } public function render(): View diff --git a/app/Livewire/Pages/Analytics/Index.php b/app/Livewire/Pages/Analytics/Index.php index bbe369b..b8cc98e 100644 --- a/app/Livewire/Pages/Analytics/Index.php +++ b/app/Livewire/Pages/Analytics/Index.php @@ -59,9 +59,9 @@ class Index extends Component /** @return Builder */ private function baseQuery(): Builder { - $workspace = require_workspace(); + $wsId = $this->workspaceId; - $q = Click::where('workspace_id', $workspace->id) + $q = Click::where('workspace_id', $wsId) ->where('clicked_at', '>=', $this->rangeStart()); if ($this->country) { @@ -71,7 +71,7 @@ class Index extends Component $q->where('device', $this->device); } if ($this->linkId) { - $link = Link::where('workspace_id', $workspace->id)->where('ulid', $this->linkId)->first(); + $link = Link::where('workspace_id', $wsId)->where('ulid', $this->linkId)->first(); if ($link) { $q->where('link_id', $link->id); } @@ -91,11 +91,11 @@ class Index extends Component public function render(): View { - $workspace = require_workspace(); + $wsId = $this->workspaceId; $totalFiltered = $this->baseQuery()->count(); - $allTime = Click::where('workspace_id', $workspace->id)->count(); + $allTime = Click::where('workspace_id', $wsId)->count(); $byCountry = (clone $this->baseQuery()) ->whereNotNull('country') @@ -111,20 +111,20 @@ class Index extends Component ->orderByDesc('total') ->get(); - $countries = Click::where('workspace_id', $workspace->id) + $countries = Click::where('workspace_id', $wsId) ->whereNotNull('country') ->distinct() ->pluck('country') ->sort() ->values(); - $devices = Click::where('workspace_id', $workspace->id) + $devices = Click::where('workspace_id', $wsId) ->whereNotNull('device') ->distinct() ->pluck('device') ->values(); - $links = Link::where('workspace_id', $workspace->id) + $links = Link::where('workspace_id', $wsId) ->orderBy('slug') ->get(['ulid', 'slug', 'title']); diff --git a/resources/js/bootstrap.js b/resources/js/bootstrap.js index af989b7..2918e7b 100644 --- a/resources/js/bootstrap.js +++ b/resources/js/bootstrap.js @@ -16,6 +16,9 @@ window.Echo = new Echo({ enabledTransports: ['ws', 'wss'], }); +import QRCode from 'qrcode'; +window.QRCode = QRCode; + import { Chart, LineController, LineElement, diff --git a/resources/views/components/ui/copy-button.blade.php b/resources/views/components/ui/copy-button.blade.php new file mode 100644 index 0000000..746cf78 --- /dev/null +++ b/resources/views/components/ui/copy-button.blade.php @@ -0,0 +1,31 @@ +@props(['value', 'label' => 'Kopieren']) + + diff --git a/resources/views/layouts/nimuli-app.blade.php b/resources/views/layouts/nimuli-app.blade.php index 956c559..b1e2e59 100644 --- a/resources/views/layouts/nimuli-app.blade.php +++ b/resources/views/layouts/nimuli-app.blade.php @@ -153,7 +153,7 @@ function updateActiveNav() { var path = window.location.pathname; document.querySelectorAll('[data-nav-link]').forEach(function (el) { - var href = el.getAttribute('href'); + var href = new URL(el.href, location.origin).pathname; var isActive = href && (path === href || path.startsWith(href + '/')); el.classList.toggle('bg-blue/10', isActive); el.classList.toggle('text-blue', isActive); diff --git a/resources/views/livewire/modals/create-qr-code.blade.php b/resources/views/livewire/modals/create-qr-code.blade.php index 00a074a..9428c72 100644 --- a/resources/views/livewire/modals/create-qr-code.blade.php +++ b/resources/views/livewire/modals/create-qr-code.blade.php @@ -151,7 +151,7 @@ @script