@php /** * Product card partial. * Expects: * - $p : product object/array with productid, productname, mainprice, offerprice, * thumbnail, hover_thumbnail, is_in_wishlist, stock, rating, cartURL, producturl, * sale_tag, sale_tag_color, sale_tag_text_color, product_type, variantid, symbol, position * - $lang : current language code */ $p = is_object($p) ? $p : (object) $p; $pname = $p->productname ?? null; $name = is_array($pname) ? ($pname[$lang] ?? reset($pname)) : ($pname ?? $p->name ?? ''); // Price: prefer the offer price ONLY when it is a real positive value AND lower than the // main price. A formatted "$ 0.00" string is non-empty in PHP, so plain ?? is unsafe. $_offerNum = (float) preg_replace('/[^0-9.]/', '', (string) ($p->offerprice ?? '')); $_mainNum = (float) preg_replace('/[^0-9.]/', '', (string) ($p->mainprice ?? '')); $hasOffer = $_offerNum > 0 && $_offerNum < $_mainNum; $price = $hasOffer ? $p->offerprice : ($p->mainprice ?? $p->offerprice ?? ''); $compare = $hasOffer ? $p->mainprice : null; $rating = isset($p->rating) ? (float) $p->rating : 0; $img = $p->thumbnail ?? null; $hoverImg = $p->hover_thumbnail ?? $img; $url = $p->producturl ?? '#'; $cartUrl = $p->cartURL ?? null; $proid = $p->productid ?? $p->id ?? null; $type = $p->product_type ?? 'simple'; $varid = $p->variantid ?? null; $inWish = isset($p->is_in_wishlist) && $p->is_in_wishlist == 1; $stock = $p->stock ?? 0; // Compare state from session: ['proid'=>id,'type'=>'simple|variant'] $inCompare = false; $cmpType = ($p->product_type ?? 'simple') === 'simple' ? 'simple' : 'variant'; $cmpId = $p->productid ?? $p->id ?? null; if ($cmpId) { foreach ((array) session('comparison', []) as $cmp) { if (($cmp['proid'] ?? null) == $cmpId && (($cmp['type'] ?? 'variant') === $cmpType)) { $inCompare = true; break; } } } $saleTag = is_array($p->sale_tag ?? null) ? ($p->sale_tag[$lang] ?? (array_values($p->sale_tag)[0] ?? null)) : ($p->sale_tag ?? null); $saleTag = is_string($saleTag) ? trim($saleTag) : $saleTag; $saleColor = ($p->sale_tag_color ?? null) ?: '#3b6df0'; $saleTextColor = ($p->sale_tag_text_color ?? null) ?: '#ffffff'; // Contrast guard: if bg and text are the same / too close, flip text to white or deep based on bg luminance $rgb = function($hex){ $hex = ltrim((string) $hex, '#'); if (strlen($hex) === 3) $hex = $hex[0].$hex[0].$hex[1].$hex[1].$hex[2].$hex[2]; if (strlen($hex) !== 6) return null; return [hexdec(substr($hex,0,2)), hexdec(substr($hex,2,2)), hexdec(substr($hex,4,2))]; }; $luma = function($rgb) { if (!$rgb) return 1; return (0.299 * $rgb[0] + 0.587 * $rgb[1] + 0.114 * $rgb[2]) / 255; }; $bgRgb = $rgb($saleColor); $txtRgb = $rgb($saleTextColor); if ($bgRgb && $txtRgb) { $diff = abs($luma($bgRgb) - $luma($txtRgb)); if ($diff < 0.35) { // Pick a readable text color based on bg $saleTextColor = $luma($bgRgb) > 0.6 ? '#0a1430' : '#ffffff'; } } // Discount percentage calc $disPct = 0; if ($compare) { $cv = (float) preg_replace('/[^0-9.]/', '', (string) $compare); $pv = (float) preg_replace('/[^0-9.]/', '', (string) $price); if ($cv > 0 && $cv > $pv) $disPct = round((1 - $pv / $cv) * 100); } @endphp
@if($img) {{ $name }} @if($hoverImg && $hoverImg !== $img) @endif @else @endif {{-- Tags stacked top-left so they never collide with the action buttons on the right --}}
@if($saleTag) {{ $saleTag }} @endif @if($disPct > 0) −{{ $disPct }}% @endif
@if($stock <= 0)
{{ __('Out of stock') }}
@endif
{{-- Action buttons: revealed on hover --}}
@if($type === 'simple' && $proid) @elseif($varid) @endif @if($proid) @endif
@if($cartUrl && $stock > 0) @if($type === 'simple' && $proid)
@csrf
@elseif($varid)
@csrf
@endif @endif

{{ $name }}

@if($rating > 0)
{{ number_format($rating, 1) }}
@endif @php $hidePrice = (App\Genral::first()->login ?? 0) == 1 && !auth()->check(); @endphp
@if($hidePrice) {{ __('Login to view price') }} @else {!! $price !!} @if($compare && $disPct > 0) {!! $compare !!} @endif @endif