{{ $r->summary }}
@endif{{ $r->review ?? '' }}
@extends('front.layout.master') @section('title', $product->product_name . ' | ') @section('meta_tags') @if($product->thumbnail && file_exists(public_path('images/simple_products/' . $product->thumbnail))) @endif @endsection @section('stylesheet') @endsection @section('body') @php $lang = session()->get('changed_language') ?? 'en'; $isAuth = auth()->check(); // Price + discount. // Schema note: admin enters `actual_selling_price` and `actual_offer_price` (pre-tax). // `price` and `offer_price` are the same values WITH tax computed and stored, which is what // the customer should see. Treat the offer as real ONLY when admin actually set a non-zero // `actual_offer_price` AND the resulting `offer_price` is strictly less than `price`. Without // this check the page can show a phantom "offer" because tax is sometimes baked into // `offer_price` even when the admin meant "no offer". $basePrice = (float) ($product->price ?? 0); $proOffer = (float) ($product->offer_price ?? 0); $actualOffer = (float) ($product->actual_offer_price ?? 0); $hasOffer = $actualOffer > 0 && $proOffer > 0 && $proOffer < $basePrice; $variantPrice = $hasOffer ? $proOffer : $basePrice; $variantCompare = $hasOffer ? $basePrice : null; $disPct = ($variantCompare && $variantPrice > 0) ? round((1 - $variantPrice / $variantCompare) * 100) : 0; // Reviews aggregate (uses real review rows like the variant page) $allReviews = $product->reviews()->where('status', '1')->get(); $review_count = $allReviews->count(); $sub_total = 0; $denom = 0; foreach ($allReviews as $r) { $sub_total += ($r->qty * 5) + ($r->price * 5) + ($r->value * 5); } $denom = ($review_count * 3) * 5; $overallrating = $denom > 0 ? round(($sub_total / $denom) * 5, 1) : 0; // Per-product policy facts $hasFreeShip = $product->free_shipping == 1; $hasReturn = $product->return_avbl == 1; $hasCancel = $product->cancel_avbl == 1; $hasCOD = $product->cod_avbl == 1; $returnDays = optional(\App\Genral::first())->return_in_days ?? 30; // Simple products don't carry a warranty column in this schema; surface only when something is set. $warrantyLabel = trim(implode(' ', array_filter([ $product->w_d ?? '', $product->w_my ?? '', $product->w_type ?? '', ]))); $hasWarranty = $warrantyLabel !== ''; $tiles = []; if ($hasFreeShip) { $tiles[] = ['label' => __('Free Delivery'), 'sub' => __('On this product'), 'svg' => '', 'tone' => 'emerald']; } if ($hasReturn) { $tiles[] = ['label' => __('Easy Returns'), 'sub' => $returnDays . ' ' . __('day policy'), 'svg' => '', 'tone' => 'amber']; } if ($hasWarranty) { $tiles[] = ['label' => __('Warranty'), 'sub' => $warrantyLabel, 'svg' => '', 'tone' => 'brand']; } if ($hasCOD) { $tiles[] = ['label' => __('Cash on Delivery'), 'sub' => __('Available'), 'svg' => '', 'tone' => 'sky']; } if ($hasCancel) { $tiles[] = ['label' => __('Cancellable'), 'sub' => __('Order can be cancelled'), 'svg' => '', 'tone' => 'rose']; } $toneMap = [ 'emerald' => ['icon' => 'text-emerald-600', 'bg' => 'bg-emerald-50'], 'amber' => ['icon' => 'text-amber-600', 'bg' => 'bg-amber-50'], 'brand' => ['icon' => 'text-brand-600', 'bg' => 'bg-brand-50'], 'sky' => ['icon' => 'text-sky-600', 'bg' => 'bg-sky-50'], 'rose' => ['icon' => 'text-rose-500', 'bg' => 'bg-rose-50'], ]; // Wishlist + compare state $detailInWish = false; if ($isAuth) { $detailInWish = \App\Wishlist::where('user_id', auth()->id())->where('simple_pro_id', $product->id)->exists(); } $detailInCompare = false; foreach ((array) session('comparison', []) as $cmp) { if (($cmp['proid'] ?? null) == $product->id && (($cmp['type'] ?? 'variant') === 'simple')) { $detailInCompare = true; break; } } // Gallery URLs $imgs = []; if ($product->thumbnail && file_exists(public_path('images/simple_products/' . $product->thumbnail))) { $imgs[] = url('images/simple_products/' . $product->thumbnail); } foreach ($product->productGallery as $g) { if (!empty($g->image) && file_exists(public_path('images/simple_products/gallery/' . $g->image))) { $imgs[] = url('images/simple_products/gallery/' . $g->image); } } $imgs = array_values(array_unique($imgs)); $mainSrc = $imgs[0] ?? url('images/no-image.png'); // Sale tag — guard against admin-entered black-on-black or invalid hexes. $saleTag = is_array($product->sale_tag ?? null) ? ($product->sale_tag[$lang] ?? (array_values($product->sale_tag)[0] ?? null)) : ($product->sale_tag ?? null); $saleTag = is_string($saleTag) ? trim($saleTag) : $saleTag; $saleColor = $product->sale_tag_color ?: '#3b6df0'; $saleTextColor = $product->sale_tag_text_color ?: '#ffffff'; $_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) { return $rgb ? (0.299*$rgb[0] + 0.587*$rgb[1] + 0.114*$rgb[2]) / 255 : 1; }; $_bg = $_rgb($saleColor); $_tx = $_rgb($saleTextColor); if ($_bg && $_tx && abs($_luma($_bg) - $_luma($_tx)) < 0.35) { $saleTextColor = $_luma($_bg) > 0.6 ? '#0a1430' : '#ffffff'; } // Real rating distribution for the bars $ratingBuckets = [5=>0, 4=>0, 3=>0, 2=>0, 1=>0]; foreach ($allReviews as $rv) { $avg = (int) round((($rv->qty + $rv->price + $rv->value) / 3)); $avg = max(1, min(5, $avg)); $ratingBuckets[$avg]++; } $ratingTotal = array_sum($ratingBuckets); $ratingPct = []; foreach ($ratingBuckets as $k => $v) { $ratingPct[$k] = $ratingTotal > 0 ? round($v / $ratingTotal * 100) : 0; } @endphp {{-- Breadcrumbs --}}
{{ __('Inclusive of all taxes') }}
@if(($product->pre_order ?? 0) == 1){{ __('Standard shipping rates apply.') }}
@endif @if(isset($product->store) && $product->store) @php $sLogoFile = $product->store->store_logo ?? null; $sLogoUrl = $sLogoFile && file_exists(public_path('images/store/logo/' . $sLogoFile)) ? url('images/store/logo/' . $sLogoFile) : null; @endphp{{ $r->review ?? '' }}
{{ __('No reviews yet. Be the first to review!') }}