diff --git a/app/Http/Controllers/ProductController.php b/app/Http/Controllers/ProductController.php index 3252786..315d2bd 100644 --- a/app/Http/Controllers/ProductController.php +++ b/app/Http/Controllers/ProductController.php @@ -40,26 +40,78 @@ public function show(string $locale, int $id) $collection = $product['collections'][0] ?? null; - $variantsData = $this->products->variantSummaries($product); - - $firstVariant = $product['variants'][0] ?? null; - $option = $firstVariant['options'][0]['option'] ?? null; - - // The "Color" option type is the only one that writes a hex code into - // meta (see boboko/core's ColorOptionType) — its presence is how we - // tell a color option (swatches) from any other option (buttons). - $optionIsColor = collect($product['variants']) - ->contains(fn (array $variant) => !empty($variant['options'][0]['meta']['hex'] ?? null)); + [$productOptions, $variantsData] = $this->buildOptionPicker($id); return view('product.show', [ 'collection' => $collection, 'product' => $product, - 'option' => $option, - 'optionIsColor' => $optionIsColor, + 'productOptions' => $productOptions, 'variantsData' => $variantsData, ]); } + /** + * One button/swatch group per product option (a product can have several + * — e.g. a custom-photo product with size + style + person-count, each + * combination resolved client-side to one exact ProductVariant, see + * product-form-controller.js) plus the per-variant data the picker + * resolves a selection against. + * + * Reads live Eloquent rather than the Meilisearch-indexed $product array + * the rest of the page uses (same reasoning as checkStock() below): the + * index has no concept of option/value display order (Lunar's + * `position` column) or a stable value id, both of which the picker + * needs — to render values in the merchant's intended order, and to + * match a combination back to one exact variant without relying on + * translated label strings staying unique. + * + * @return array{0: array, 1: array} + */ + private function buildOptionPicker(int $productId): array + { + $variants = ProductVariant::query() + ->where('product_id', $productId) + ->with(['values.option', 'prices', 'images']) + ->get(); + + $productOptions = $variants + ->flatMap(fn (ProductVariant $variant) => $variant->values) + ->unique('id') + ->groupBy(fn ($value) => $value->option->handle) + ->map(function ($values, $handle) { + $sorted = $values->sortBy([['position', 'asc'], ['id', 'asc']]); + + return [ + 'handle' => $handle, + 'label' => $sorted->first()->option->translate('name'), + // The "Color" option type is the only one that writes a + // hex code into meta (see boboko/core's ColorOptionType) + // — its presence is how we tell a color option (swatches) + // from any other option (buttons). + 'isColor' => $sorted->contains(fn ($v) => !empty($v->meta['hex'] ?? null)), + 'values' => $sorted->map(fn ($v) => [ + 'id' => $v->id, + 'label' => $v->translate('name'), + 'hex' => $v->meta['hex'] ?? null, + ])->values()->all(), + ]; + }) + ->values() + ->all(); + + $variantsData = $variants->map(fn (ProductVariant $variant) => [ + 'id' => $variant->id, + 'price' => $variant->prices->first()?->price?->decimal(), + 'image' => $variant->images->first()?->getUrl(), + // handle => selected value id, for matching a combination of + // selections back to this variant — see selectVariant() in + // product-form-controller.js. + 'options' => $variant->values->mapWithKeys(fn ($v) => [$v->option->handle => $v->id])->all(), + ])->values()->all(); + + return [$productOptions, $variantsData]; + } + /** * A storefront-owned, checkout-module-independent stock check — the * product page's "Add to cart" calls this first and only submits to the diff --git a/composer.lock b/composer.lock index fb66c1d..7bca38a 100644 --- a/composer.lock +++ b/composer.lock @@ -515,11 +515,11 @@ }, { "name": "boboko/core", - "version": "0.18.0", + "version": "0.19.0", "source": { "type": "git", "url": "https://code.radical-elements.com/boboko/core.git", - "reference": "2cc6f5e5f0d43102001d65b60810423a35e83e1f" + "reference": "0437057e5d604e3c05479089071fcbe79ad69bb7" }, "require": { "laravel/framework": "^12.0", @@ -558,7 +558,8 @@ "Modules\\Core\\Providers\\CartServiceProvider", "Modules\\Core\\Providers\\ReviewServiceProvider", "Modules\\Core\\Providers\\ShippingServiceProvider", - "Modules\\Core\\Providers\\OrderServiceProvider" + "Modules\\Core\\Providers\\OrderServiceProvider", + "Modules\\Core\\Providers\\PrivacyServiceProvider" ] } }, @@ -568,7 +569,7 @@ } }, "description": "Core module — authentication and shared panel behaviour", - "time": "2026-09-15T21:06:04+00:00" + "time": "2026-09-17T22:30:37+00:00" }, { "name": "brick/math", @@ -1062,16 +1063,16 @@ }, { "name": "danharrin/livewire-rate-limiting", - "version": "v2.2.1", + "version": "v2.3.0", "source": { "type": "git", "url": "https://github.com/danharrin/livewire-rate-limiting.git", - "reference": "69436717dc70e30f80d7f8fd02504c22992a9ad5" + "reference": "46c4ceaf7997c713c79afe7c507a39649f6c9d6f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/danharrin/livewire-rate-limiting/zipball/69436717dc70e30f80d7f8fd02504c22992a9ad5", - "reference": "69436717dc70e30f80d7f8fd02504c22992a9ad5", + "url": "https://api.github.com/repos/danharrin/livewire-rate-limiting/zipball/46c4ceaf7997c713c79afe7c507a39649f6c9d6f", + "reference": "46c4ceaf7997c713c79afe7c507a39649f6c9d6f", "shasum": "" }, "require": { @@ -1112,7 +1113,7 @@ "type": "github" } ], - "time": "2026-08-06T08:41:51+00:00" + "time": "2026-09-18T07:38:01+00:00" }, { "name": "dflydev/dot-access-data", @@ -1329,27 +1330,25 @@ }, { "name": "doctrine/lexer", - "version": "3.0.1", + "version": "3.0.2", "source": { "type": "git", "url": "https://github.com/doctrine/lexer.git", - "reference": "31ad66abc0fc9e1a1f2d9bc6a42668d2fbbcd6dd" + "reference": "e96fe45e92a54233726014a7cc7340abf29bb14c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/lexer/zipball/31ad66abc0fc9e1a1f2d9bc6a42668d2fbbcd6dd", - "reference": "31ad66abc0fc9e1a1f2d9bc6a42668d2fbbcd6dd", + "url": "https://api.github.com/repos/doctrine/lexer/zipball/e96fe45e92a54233726014a7cc7340abf29bb14c", + "reference": "e96fe45e92a54233726014a7cc7340abf29bb14c", "shasum": "" }, "require": { "php": "^8.1" }, "require-dev": { - "doctrine/coding-standard": "^12", - "phpstan/phpstan": "^1.10", - "phpunit/phpunit": "^10.5", - "psalm/plugin-phpunit": "^0.18.3", - "vimeo/psalm": "^5.21" + "doctrine/coding-standard": "^14", + "phpstan/phpstan": "^2", + "phpunit/phpunit": "^10.5.58 || ^12.5.4" }, "type": "library", "autoload": { @@ -1386,7 +1385,7 @@ ], "support": { "issues": "https://github.com/doctrine/lexer/issues", - "source": "https://github.com/doctrine/lexer/tree/3.0.1" + "source": "https://github.com/doctrine/lexer/tree/3.0.2" }, "funding": [ { @@ -1402,7 +1401,7 @@ "type": "tidelift" } ], - "time": "2024-02-05T11:56:58+00:00" + "time": "2026-06-14T20:44:06+00:00" }, { "name": "dompdf/dompdf", @@ -1692,7 +1691,7 @@ }, { "name": "filament/actions", - "version": "v4.13.2", + "version": "v4.13.4", "source": { "type": "git", "url": "https://github.com/filamentphp/actions.git", @@ -1741,16 +1740,16 @@ }, { "name": "filament/filament", - "version": "v4.13.2", + "version": "v4.13.4", "source": { "type": "git", "url": "https://github.com/filamentphp/panels.git", - "reference": "ff848c7750b49f0bb532d44c6768f0e601fb09d2" + "reference": "1215d7d79b5609f66c1e432933610eefa0ab3ad6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filamentphp/panels/zipball/ff848c7750b49f0bb532d44c6768f0e601fb09d2", - "reference": "ff848c7750b49f0bb532d44c6768f0e601fb09d2", + "url": "https://api.github.com/repos/filamentphp/panels/zipball/1215d7d79b5609f66c1e432933610eefa0ab3ad6", + "reference": "1215d7d79b5609f66c1e432933610eefa0ab3ad6", "shasum": "" }, "require": { @@ -1795,20 +1794,20 @@ "issues": "https://github.com/filamentphp/filament/issues", "source": "https://github.com/filamentphp/filament" }, - "time": "2026-09-15T16:56:27+00:00" + "time": "2026-09-20T19:15:07+00:00" }, { "name": "filament/forms", - "version": "v4.13.2", + "version": "v4.13.4", "source": { "type": "git", "url": "https://github.com/filamentphp/forms.git", - "reference": "18e3382115ed3062a074736c9e80cfcb3ffe2221" + "reference": "10d7ba430544ae706a406713105ba37b18f52008" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filamentphp/forms/zipball/18e3382115ed3062a074736c9e80cfcb3ffe2221", - "reference": "18e3382115ed3062a074736c9e80cfcb3ffe2221", + "url": "https://api.github.com/repos/filamentphp/forms/zipball/10d7ba430544ae706a406713105ba37b18f52008", + "reference": "10d7ba430544ae706a406713105ba37b18f52008", "shasum": "" }, "require": { @@ -1845,20 +1844,20 @@ "issues": "https://github.com/filamentphp/filament/issues", "source": "https://github.com/filamentphp/filament" }, - "time": "2026-09-15T17:00:54+00:00" + "time": "2026-09-20T18:45:30+00:00" }, { "name": "filament/infolists", - "version": "v4.13.2", + "version": "v4.13.4", "source": { "type": "git", "url": "https://github.com/filamentphp/infolists.git", - "reference": "b05093c8ff726d28eb75df29fa21bdd836386ded" + "reference": "1979591422ff823543622b87e0276cdca3f863e8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filamentphp/infolists/zipball/b05093c8ff726d28eb75df29fa21bdd836386ded", - "reference": "b05093c8ff726d28eb75df29fa21bdd836386ded", + "url": "https://api.github.com/repos/filamentphp/infolists/zipball/1979591422ff823543622b87e0276cdca3f863e8", + "reference": "1979591422ff823543622b87e0276cdca3f863e8", "shasum": "" }, "require": { @@ -1890,20 +1889,20 @@ "issues": "https://github.com/filamentphp/filament/issues", "source": "https://github.com/filamentphp/filament" }, - "time": "2026-09-15T16:59:31+00:00" + "time": "2026-09-20T18:45:56+00:00" }, { "name": "filament/notifications", - "version": "v4.13.2", + "version": "v4.13.4", "source": { "type": "git", "url": "https://github.com/filamentphp/notifications.git", - "reference": "f481bcfb705ad650f96336e7496814419907639c" + "reference": "40989f93ec3dc36f5582024ca41f99333a4c0ea7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filamentphp/notifications/zipball/f481bcfb705ad650f96336e7496814419907639c", - "reference": "f481bcfb705ad650f96336e7496814419907639c", + "url": "https://api.github.com/repos/filamentphp/notifications/zipball/40989f93ec3dc36f5582024ca41f99333a4c0ea7", + "reference": "40989f93ec3dc36f5582024ca41f99333a4c0ea7", "shasum": "" }, "require": { @@ -1937,20 +1936,20 @@ "issues": "https://github.com/filamentphp/filament/issues", "source": "https://github.com/filamentphp/filament" }, - "time": "2026-09-15T16:55:37+00:00" + "time": "2026-09-20T18:48:58+00:00" }, { "name": "filament/query-builder", - "version": "v4.13.2", + "version": "v4.13.4", "source": { "type": "git", "url": "https://github.com/filamentphp/query-builder.git", - "reference": "f7c1eb9eeaded573838c1f3b8d0a63f55434331a" + "reference": "0428645f4cd0a232b6bc446437cbfafa366e56c0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filamentphp/query-builder/zipball/f7c1eb9eeaded573838c1f3b8d0a63f55434331a", - "reference": "f7c1eb9eeaded573838c1f3b8d0a63f55434331a", + "url": "https://api.github.com/repos/filamentphp/query-builder/zipball/0428645f4cd0a232b6bc446437cbfafa366e56c0", + "reference": "0428645f4cd0a232b6bc446437cbfafa366e56c0", "shasum": "" }, "require": { @@ -1983,20 +1982,20 @@ "issues": "https://github.com/filamentphp/filament/issues", "source": "https://github.com/filamentphp/filament" }, - "time": "2026-09-15T16:55:48+00:00" + "time": "2026-09-20T18:53:32+00:00" }, { "name": "filament/schemas", - "version": "v4.13.2", + "version": "v4.13.4", "source": { "type": "git", "url": "https://github.com/filamentphp/schemas.git", - "reference": "fec2747e8cf1e6ca76d6c883c7f1019da994f771" + "reference": "dc4eeb57671b104b9e60f6d3f435f803c705e6df" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filamentphp/schemas/zipball/fec2747e8cf1e6ca76d6c883c7f1019da994f771", - "reference": "fec2747e8cf1e6ca76d6c883c7f1019da994f771", + "url": "https://api.github.com/repos/filamentphp/schemas/zipball/dc4eeb57671b104b9e60f6d3f435f803c705e6df", + "reference": "dc4eeb57671b104b9e60f6d3f435f803c705e6df", "shasum": "" }, "require": { @@ -2028,11 +2027,11 @@ "issues": "https://github.com/filamentphp/filament/issues", "source": "https://github.com/filamentphp/filament" }, - "time": "2026-09-08T10:20:09+00:00" + "time": "2026-09-20T18:49:21+00:00" }, { "name": "filament/spatie-laravel-media-library-plugin", - "version": "v4.13.2", + "version": "v4.13.4", "source": { "type": "git", "url": "https://github.com/filamentphp/spatie-laravel-media-library-plugin.git", @@ -2069,16 +2068,16 @@ }, { "name": "filament/support", - "version": "v4.13.2", + "version": "v4.13.4", "source": { "type": "git", "url": "https://github.com/filamentphp/support.git", - "reference": "6ff50570ff1f2c6c1caf6ed1e7a2ce146b901106" + "reference": "6bd7bdb5f5ff3b1a70cac6dabe28f5d996a36bcc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filamentphp/support/zipball/6ff50570ff1f2c6c1caf6ed1e7a2ce146b901106", - "reference": "6ff50570ff1f2c6c1caf6ed1e7a2ce146b901106", + "url": "https://api.github.com/repos/filamentphp/support/zipball/6bd7bdb5f5ff3b1a70cac6dabe28f5d996a36bcc", + "reference": "6bd7bdb5f5ff3b1a70cac6dabe28f5d996a36bcc", "shasum": "" }, "require": { @@ -2124,20 +2123,20 @@ "issues": "https://github.com/filamentphp/filament/issues", "source": "https://github.com/filamentphp/filament" }, - "time": "2026-09-15T16:59:53+00:00" + "time": "2026-09-20T19:14:52+00:00" }, { "name": "filament/tables", - "version": "v4.13.2", + "version": "v4.13.4", "source": { "type": "git", "url": "https://github.com/filamentphp/tables.git", - "reference": "51f2f2d19eddae424b8b4a08ab9a14770e2acc9d" + "reference": "8a0c6634d752e0b71ed0871f92d533c0d03d7601" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filamentphp/tables/zipball/51f2f2d19eddae424b8b4a08ab9a14770e2acc9d", - "reference": "51f2f2d19eddae424b8b4a08ab9a14770e2acc9d", + "url": "https://api.github.com/repos/filamentphp/tables/zipball/8a0c6634d752e0b71ed0871f92d533c0d03d7601", + "reference": "8a0c6634d752e0b71ed0871f92d533c0d03d7601", "shasum": "" }, "require": { @@ -2170,20 +2169,20 @@ "issues": "https://github.com/filamentphp/filament/issues", "source": "https://github.com/filamentphp/filament" }, - "time": "2026-09-15T16:56:17+00:00" + "time": "2026-09-20T18:53:09+00:00" }, { "name": "filament/widgets", - "version": "v4.13.2", + "version": "v4.13.4", "source": { "type": "git", "url": "https://github.com/filamentphp/widgets.git", - "reference": "3d5a4dde469ad9f8e6cb2d5928e4882f6a92afe1" + "reference": "5ec044730102c3444d019232d8edc3d8922876c6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filamentphp/widgets/zipball/3d5a4dde469ad9f8e6cb2d5928e4882f6a92afe1", - "reference": "3d5a4dde469ad9f8e6cb2d5928e4882f6a92afe1", + "url": "https://api.github.com/repos/filamentphp/widgets/zipball/5ec044730102c3444d019232d8edc3d8922876c6", + "reference": "5ec044730102c3444d019232d8edc3d8922876c6", "shasum": "" }, "require": { @@ -2214,7 +2213,7 @@ "issues": "https://github.com/filamentphp/filament/issues", "source": "https://github.com/filamentphp/filament" }, - "time": "2026-09-07T18:36:33+00:00" + "time": "2026-09-20T18:53:38+00:00" }, { "name": "fruitcake/php-cors", @@ -7844,20 +7843,20 @@ }, { "name": "ramsey/uuid", - "version": "4.9.3", + "version": "4.9.4", "source": { "type": "git", "url": "https://github.com/ramsey/uuid.git", - "reference": "1df15849d00943a67d677dc9cfd80795f038c9f8" + "reference": "75d73f48d02797c2c285a7e9f348fadc0102ffe2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ramsey/uuid/zipball/1df15849d00943a67d677dc9cfd80795f038c9f8", - "reference": "1df15849d00943a67d677dc9cfd80795f038c9f8", + "url": "https://api.github.com/repos/ramsey/uuid/zipball/75d73f48d02797c2c285a7e9f348fadc0102ffe2", + "reference": "75d73f48d02797c2c285a7e9f348fadc0102ffe2", "shasum": "" }, "require": { - "brick/math": ">=0.8.16 <=0.18", + "brick/math": "^0.8.16 || ^0.9 || ^0.10 || ^0.11 || ^0.12 || ^0.13 || ^0.14 || ^0.15 || ^0.16 || ^0.17 || ^0.18 || ^0.19 || ^0.20 || ^1.0", "php": "^8.0", "ramsey/collection": "^1.2 || ^2.0" }, @@ -7916,9 +7915,9 @@ ], "support": { "issues": "https://github.com/ramsey/uuid/issues", - "source": "https://github.com/ramsey/uuid/tree/4.9.3" + "source": "https://github.com/ramsey/uuid/tree/4.9.4" }, - "time": "2026-06-18T03:57:49+00:00" + "time": "2026-09-16T11:39:30+00:00" }, { "name": "ryangjchandler/blade-capture-directive", @@ -8000,35 +7999,33 @@ }, { "name": "sabberworm/php-css-parser", - "version": "v9.4.0", + "version": "v9.5.0", "source": { "type": "git", "url": "https://github.com/MyIntervals/PHP-CSS-Parser.git", - "reference": "fd3bf9fb173e0df649bc4e3e0d088a1b2417c08f" + "reference": "f284e63b6e891e0c28631e54ba06c3ed102a9ef3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/MyIntervals/PHP-CSS-Parser/zipball/fd3bf9fb173e0df649bc4e3e0d088a1b2417c08f", - "reference": "fd3bf9fb173e0df649bc4e3e0d088a1b2417c08f", + "url": "https://api.github.com/repos/MyIntervals/PHP-CSS-Parser/zipball/f284e63b6e891e0c28631e54ba06c3ed102a9ef3", + "reference": "f284e63b6e891e0c28631e54ba06c3ed102a9ef3", "shasum": "" }, "require": { "ext-iconv": "*", - "php": "^7.2.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0", - "thecodingmachine/safe": "^1.3 || ^2.5 || ^3.4" + "php": "^7.2.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0 || ~8.6.0" }, "require-dev": { "php-parallel-lint/php-parallel-lint": "1.4.0", "phpstan/extension-installer": "1.4.3", - "phpstan/phpstan": "1.12.33 || 2.2.2", - "phpstan/phpstan-phpunit": "1.4.2 || 2.0.16", - "phpstan/phpstan-strict-rules": "1.6.2 || 2.0.11", - "phpunit/phpunit": "8.5.52", + "phpstan/phpstan": "1.12.33 || 2.2.9", + "phpstan/phpstan-phpunit": "1.4.2 || 2.0.18", + "phpstan/phpstan-strict-rules": "1.6.2 || 2.0.12", + "phpunit/phpunit": "8.5.54", "rawr/phpunit-data-provider": "3.3.1", - "rector/rector": "1.2.10 || 2.4.6", - "rector/type-perfect": "1.0.0 || 2.1.3", - "squizlabs/php_codesniffer": "4.0.1", - "thecodingmachine/phpstan-safe-rule": "1.2.0 || 1.4.3" + "rector/rector": "1.2.10 || 2.6.2", + "rector/type-perfect": "1.0.0 || 2.1.4", + "squizlabs/php_codesniffer": "4.0.4" }, "suggest": { "ext-mbstring": "for parsing UTF-8 CSS" @@ -8036,7 +8033,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "9.5.x-dev" + "dev-main": "9.6.x-dev" } }, "autoload": { @@ -8074,9 +8071,9 @@ ], "support": { "issues": "https://github.com/MyIntervals/PHP-CSS-Parser/issues", - "source": "https://github.com/MyIntervals/PHP-CSS-Parser/tree/v9.4.0" + "source": "https://github.com/MyIntervals/PHP-CSS-Parser/tree/v9.5.0" }, - "time": "2026-06-18T15:10:53+00:00" + "time": "2026-09-20T15:02:00+00:00" }, { "name": "scrivo/highlight.php", @@ -12603,16 +12600,16 @@ }, { "name": "technikermathe/blade-lucide-icons", - "version": "v3.180.0", + "version": "v3.181.0", "source": { "type": "git", "url": "https://github.com/PascaleBeier/blade-lucide-icons.git", - "reference": "adac9da3a65910fedc271129eea5340093910203" + "reference": "64ccac4ecfe1b833e9a5cf1ebe7216acbe3cac98" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PascaleBeier/blade-lucide-icons/zipball/adac9da3a65910fedc271129eea5340093910203", - "reference": "adac9da3a65910fedc271129eea5340093910203", + "url": "https://api.github.com/repos/PascaleBeier/blade-lucide-icons/zipball/64ccac4ecfe1b833e9a5cf1ebe7216acbe3cac98", + "reference": "64ccac4ecfe1b833e9a5cf1ebe7216acbe3cac98", "shasum": "" }, "require": { @@ -12662,152 +12659,9 @@ ], "support": { "issues": "https://github.com/PascaleBeier/blade-lucide-icons/issues", - "source": "https://github.com/PascaleBeier/blade-lucide-icons/tree/v3.180.0" + "source": "https://github.com/PascaleBeier/blade-lucide-icons/tree/v3.181.0" }, - "time": "2026-09-15T02:25:56+00:00" - }, - { - "name": "thecodingmachine/safe", - "version": "v3.4.0", - "source": { - "type": "git", - "url": "https://github.com/thecodingmachine/safe.git", - "reference": "705683a25bacf0d4860c7dea4d7947bfd09eea19" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/thecodingmachine/safe/zipball/705683a25bacf0d4860c7dea4d7947bfd09eea19", - "reference": "705683a25bacf0d4860c7dea4d7947bfd09eea19", - "shasum": "" - }, - "require": { - "php": "^8.1" - }, - "require-dev": { - "php-parallel-lint/php-parallel-lint": "^1.4", - "phpstan/phpstan": "^2", - "phpunit/phpunit": "^10", - "squizlabs/php_codesniffer": "^3.2" - }, - "type": "library", - "autoload": { - "files": [ - "lib/special_cases.php", - "generated/apache.php", - "generated/apcu.php", - "generated/array.php", - "generated/bzip2.php", - "generated/calendar.php", - "generated/classobj.php", - "generated/com.php", - "generated/cubrid.php", - "generated/curl.php", - "generated/datetime.php", - "generated/dir.php", - "generated/eio.php", - "generated/errorfunc.php", - "generated/exec.php", - "generated/fileinfo.php", - "generated/filesystem.php", - "generated/filter.php", - "generated/fpm.php", - "generated/ftp.php", - "generated/funchand.php", - "generated/gettext.php", - "generated/gmp.php", - "generated/gnupg.php", - "generated/hash.php", - "generated/ibase.php", - "generated/ibmDb2.php", - "generated/iconv.php", - "generated/image.php", - "generated/imap.php", - "generated/info.php", - "generated/inotify.php", - "generated/json.php", - "generated/ldap.php", - "generated/libxml.php", - "generated/lzf.php", - "generated/mailparse.php", - "generated/mbstring.php", - "generated/misc.php", - "generated/mysql.php", - "generated/mysqli.php", - "generated/network.php", - "generated/oci8.php", - "generated/opcache.php", - "generated/openssl.php", - "generated/outcontrol.php", - "generated/pcntl.php", - "generated/pcre.php", - "generated/pgsql.php", - "generated/posix.php", - "generated/ps.php", - "generated/pspell.php", - "generated/readline.php", - "generated/rnp.php", - "generated/rpminfo.php", - "generated/rrd.php", - "generated/sem.php", - "generated/session.php", - "generated/shmop.php", - "generated/sockets.php", - "generated/sodium.php", - "generated/solr.php", - "generated/spl.php", - "generated/sqlsrv.php", - "generated/ssdeep.php", - "generated/ssh2.php", - "generated/stream.php", - "generated/strings.php", - "generated/swoole.php", - "generated/uodbc.php", - "generated/uopz.php", - "generated/url.php", - "generated/var.php", - "generated/xdiff.php", - "generated/xml.php", - "generated/xmlrpc.php", - "generated/yaml.php", - "generated/yaz.php", - "generated/zip.php", - "generated/zlib.php" - ], - "classmap": [ - "lib/DateTime.php", - "lib/DateTimeImmutable.php", - "lib/Exceptions/", - "generated/Exceptions/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "PHP core functions that throw exceptions instead of returning FALSE on error", - "support": { - "issues": "https://github.com/thecodingmachine/safe/issues", - "source": "https://github.com/thecodingmachine/safe/tree/v3.4.0" - }, - "funding": [ - { - "url": "https://github.com/OskarStark", - "type": "github" - }, - { - "url": "https://github.com/shish", - "type": "github" - }, - { - "url": "https://github.com/silasjoisten", - "type": "github" - }, - { - "url": "https://github.com/staabm", - "type": "github" - } - ], - "time": "2026-02-04T18:08:13+00:00" + "time": "2026-09-18T02:09:04+00:00" }, { "name": "tijsverkoyen/css-to-inline-styles", diff --git a/public/css/lunarphp/panel/lunar-panel.css b/public/css/lunarphp/panel/lunar-panel.css old mode 100644 new mode 100755 diff --git a/public/js/app/components/apexcharts.js b/public/js/app/components/apexcharts.js old mode 100644 new mode 100755 diff --git a/resources/js/stimulus/product-form-controller.js b/resources/js/stimulus/product-form-controller.js index c742af5..ca090fd 100644 --- a/resources/js/stimulus/product-form-controller.js +++ b/resources/js/stimulus/product-form-controller.js @@ -16,13 +16,17 @@ export default class extends Controller { } connect() { - const params = new URLSearchParams(window.location.search) - const urlId = parseInt(params.get('variant')) - const defaultId = this.variantsValue[0]?.id + const params = new URLSearchParams(window.location.search) + const urlId = parseInt(params.get('variant')) + const urlVariant = this.variantsValue.find(v => v.id === urlId) + const initial = urlVariant ?? this.variantsValue[0] - this.selectedValue = urlId && this.variantsValue.find(v => v.id === urlId) - ? urlId - : defaultId + // A product can have several independent options (e.g. size + style + // + person-count) — this tracks the currently-picked value id per + // option handle, and selectVariant() below resolves the full + // combination back to one exact variant on every change. + this.selections = { ...initial?.options } + this.selectedValue = initial?.id // Capture phase, on this controller's own root element (an ancestor // of the checkout module's add-to-cart