From 7677d10821124104fe23bf63e64193ba55bdfe4b Mon Sep 17 00:00:00 2001 From: elvira Date: Sat, 8 Aug 2026 15:10:37 +0300 Subject: [PATCH] price function global (needs review) --- app/Support/Price.php | 29 +++++++++++++++++++ .../js/stimulus/product-form-controller.js | 3 +- resources/js/utils/format-price.js | 19 ++++++++++++ resources/views/components/ui/price.blade.php | 9 ++++++ .../components/ui/product-card.blade.php | 2 +- resources/views/home.blade.php | 6 ++-- resources/views/product/show.blade.php | 2 +- resources/views/product/show2.blade.php | 2 +- 8 files changed, 65 insertions(+), 7 deletions(-) create mode 100644 app/Support/Price.php create mode 100644 resources/js/utils/format-price.js create mode 100644 resources/views/components/ui/price.blade.php diff --git a/app/Support/Price.php b/app/Support/Price.php new file mode 100644 index 0000000..e47b956 --- /dev/null +++ b/app/Support/Price.php @@ -0,0 +1,29 @@ + "19", 19.50 -> "19,5", 19.55 -> "19,55"). + */ + public static function format(float|int|string|null $amount, string $currency = '€'): ?string + { + if ($amount === null) { + return null; + } + + $amount = round((float) $amount, 2); + $cents = (int) round($amount * 100); + + $decimals = match (true) { + $cents % 100 === 0 => 0, + $cents % 10 === 0 => 1, + default => 2, + }; + + return $currency.number_format($amount, $decimals, ',', '.'); + } +} diff --git a/resources/js/stimulus/product-form-controller.js b/resources/js/stimulus/product-form-controller.js index 083ab55..80b0159 100644 --- a/resources/js/stimulus/product-form-controller.js +++ b/resources/js/stimulus/product-form-controller.js @@ -1,4 +1,5 @@ import { Controller } from '@hotwired/stimulus' +import { formatPrice } from '../utils/format-price' export default class extends Controller { static targets = ['price', 'image', 'swatch', 'colorName'] @@ -30,7 +31,7 @@ export default class extends Controller { if (!variant) return if (this.hasPriceTarget && variant.price !== null) { - this.priceTarget.textContent = '€' + parseFloat(variant.price).toFixed(2) + this.priceTarget.textContent = formatPrice(variant.price) } if (this.hasImageTarget && variant.image) { diff --git a/resources/js/utils/format-price.js b/resources/js/utils/format-price.js new file mode 100644 index 0000000..8501d2a --- /dev/null +++ b/resources/js/utils/format-price.js @@ -0,0 +1,19 @@ +// Mirrors App\Support\Price::format() — keep both in sync. Greek formatting: +// comma as the decimal separator, dot as the thousands separator, and no +// decimals shown unless the amount actually needs them. +// 19.00 -> "€19", 19.50 -> "€19,5", 19.55 -> "€19,55" +export function formatPrice(amount, currency = '€') { + if (amount === null || amount === undefined) return null + + const value = Math.round(parseFloat(amount) * 100) / 100 + const cents = Math.round(value * 100) + + const decimals = cents % 100 === 0 ? 0 : (cents % 10 === 0 ? 1 : 2) + + const formatted = value.toLocaleString('el-GR', { + minimumFractionDigits: decimals, + maximumFractionDigits: decimals, + }) + + return currency + formatted +} diff --git a/resources/views/components/ui/price.blade.php b/resources/views/components/ui/price.blade.php new file mode 100644 index 0000000..f0b8514 --- /dev/null +++ b/resources/views/components/ui/price.blade.php @@ -0,0 +1,9 @@ +@props([ + 'amount' => null, + 'currency' => '€', +]) + +{{-- No wrapper element on purpose — drop this inside whatever tag/classes + the call site already uses (span, p, etc). Formatting logic lives in + App\Support\Price so it's identical everywhere it's used. --}} +{{ \App\Support\Price::format($amount, $currency) }} diff --git a/resources/views/components/ui/product-card.blade.php b/resources/views/components/ui/product-card.blade.php index b011b74..2d6cf26 100644 --- a/resources/views/components/ui/product-card.blade.php +++ b/resources/views/components/ui/product-card.blade.php @@ -28,7 +28,7 @@ class="w-full h-auto block"
{{ $name }} @if($price !== null) - $ {{ $price }} + @endif
diff --git a/resources/views/home.blade.php b/resources/views/home.blade.php index a103596..d3fa813 100644 --- a/resources/views/home.blade.php +++ b/resources/views/home.blade.php @@ -33,7 +33,7 @@ class="font-display font-semibold text-6xl lg:text-7xl leading-tight" aria-label="Προηγούμενο προϊόν" class="absolute left-4 lg:left-8 top-1/2 -translate-y-1/2 hover:opacity-60 transition-opacity" > - +
@@ -63,7 +63,7 @@ class="w-full h-full object-cover"
{{ $product['name'] }} @if($product['price'] !== null) - €{{ number_format($product['price'], 2) }} + @endif
@@ -76,7 +76,7 @@ class="w-full h-full object-cover" aria-label="Επόμενο προϊόν" class="absolute right-4 lg:right-8 top-1/2 -translate-y-1/2 hover:opacity-60 transition-opacity" > - + @else

Δεν βρέθηκαν προϊόντα.

diff --git a/resources/views/product/show.blade.php b/resources/views/product/show.blade.php index 1eec3e5..7509747 100644 --- a/resources/views/product/show.blade.php +++ b/resources/views/product/show.blade.php @@ -152,7 +152,7 @@ class="absolute bottom-6 right-8 text-white text-sm" @if($product->variants->first()?->prices->isNotEmpty())

- €{{ number_format($product->variants->first()->prices->first()->price->decimal, 2) }} +

@endif diff --git a/resources/views/product/show2.blade.php b/resources/views/product/show2.blade.php index 323280e..5a1ac37 100644 --- a/resources/views/product/show2.blade.php +++ b/resources/views/product/show2.blade.php @@ -152,7 +152,7 @@ class="absolute bottom-6 right-8 text-white text-sm" @if($product->variants->first()?->prices->isNotEmpty())

- €{{ number_format($product->variants->first()->prices->first()->price->decimal, 2) }} +

@endif