@php
$seo = $seo ?? app(\App\Services\Seo\SeoResolver::class)->resolve(request(), 'listing', [
'title' => $seoTitle ?? '',
'description' => $seoDescription ?? '',
'jsonld' => $schemaJson ?? null,
'og_image' => isset($featuredPhoto) && $featuredPhoto ? $featuredPhoto->path : null,
]);
$tracking = app(\App\Services\TrackingSettingsService::class)->frontendConfig();
@endphp
@include('front.partials.seo-meta', ['seo' => $seo])
@php
$mgUrl = $seo['canonical'] ?? route('mariachi.public.show', ['slug' => $profile->slug]);
$mgCityLabel = $profile->publicCityLabel();
$mgImage = $featuredPhoto ? asset('storage/'.$featuredPhoto->path) : null;
$mgPrice = $profile->base_price
? 'Desde $'.number_format((float) $profile->base_price, 0, ',', '.').' COP'
: null;
$mgSchema = [
'@context' => 'https://schema.org',
'@type' => 'MusicGroup',
'name' => $listingName,
'description' => $seoDescription,
'url' => $mgUrl,
'address' => ['@type' => 'PostalAddress', 'addressLocality' => $mgCityLabel, 'addressCountry' => 'CO'],
];
if ($mgImage) $mgSchema['image'] = $mgImage;
if ($mgPrice) $mgSchema['priceRange'] = $mgPrice;
if (!empty($publicSameAs)) $mgSchema['sameAs'] = $publicSameAs;
if ($reviewsTotal > 0) {
$mgSchema['aggregateRating'] = [
'@type' => 'AggregateRating',
'ratingValue' => number_format((float) $averageRating, 1),
'reviewCount' => $reviewsTotal,
'bestRating' => '5',
'worstRating' => '1',
];
$mgSchema['review'] = $publicReviews->map(fn ($review): array => array_filter([
'@type' => 'Review',
'reviewRating' => [
'@type' => 'Rating',
'ratingValue' => (string) $review->rating,
'bestRating' => '5',
'worstRating' => '1',
],
'author' => [
'@type' => 'Person',
'name' => $review->clientUser?->display_name ?: 'Cliente',
],
'datePublished' => $review->created_at?->toDateString(),
'name' => $review->title ?: null,
'reviewBody' => $review->comment ?: null,
]))->values()->all();
}
$bcCountrySlug = \Illuminate\Support\Str::slug(config('seo.default_country_name', 'Colombia'));
@endphp
@include('front.partials.tracking-loader', ['tracking' => $tracking])
@include('partials.favicon-meta')
@include('front.partials.site-header-fixed-style')
@include('front.partials.marketplace-style-head', [
'includeTailwind' => true,
'themeHref' => 'assets/theme.min.css?v=20260319-theme-min-v32',
])
@if (($tracking['mode'] ?? 'none') === 'gtm')
@endif
@include('front.partials.site-header')
@php
$resolveVideoThumb = static function (string $url): ?string {
if (preg_match('/embed\/([^?&"\'#\/]+)/', $url, $matches) === 1 && ! empty($matches[1])) {
return 'https://i.ytimg.com/vi/'.$matches[1].'/hqdefault.jpg';
}
return null;
};
$mainPhoto = $featuredPhoto;
$fallbackListingImage = asset('marketplace/assets/logo-wordmark-390.webp');
$mainPhotoUrl = $mainPhoto?->urlForVariant('large') ?: $fallbackListingImage;
$cityLandingUrl = route('seo.landing.slug', ['slug' => $citySlug]);
$defaultCountrySlug = collect(config('seo.country_pages', ['colombia' => 'Colombia']))->keys()->first() ?: 'colombia';
$marketplaceLandingUrl = route('seo.landing.slug', ['slug' => $defaultCountrySlug]);
$serviceTypeNames = $profile->serviceTypes->pluck('name');
$groupSizeNames = $profile->groupSizeOptions->pluck('name');
$budgetNames = $profile->budgetRanges->pluck('name');
$photoGalleryItems = collect();
if ($mainPhoto) {
$photoGalleryItems->push([
'type' => 'image',
'src' => $mainPhotoUrl,
'thumb' => $mainPhoto?->urlForVariant('thumb') ?: $mainPhotoUrl,
'title' => $mainPhoto->title ?: $h1,
'width' => $mainPhoto->width ?: 1600,
'height' => $mainPhoto->height ?: 900,
]);
}
foreach ($secondaryPhotos as $photo) {
$photoGalleryItems->push([
'type' => 'image',
'src' => $photo->urlForVariant('large') ?: $fallbackListingImage,
'thumb' => $photo->urlForVariant('thumb') ?: $photo->urlForVariant('large') ?: $fallbackListingImage,
'title' => $photo->title ?: $h1,
'width' => $photo->width ?: 1600,
'height' => $photo->height ?: 900,
]);
}
if ($photoGalleryItems->isEmpty()) {
$photoGalleryItems->push([
'type' => 'image',
'src' => $mainPhotoUrl,
'thumb' => $mainPhotoUrl,
'title' => $h1,
'width' => 1600,
'height' => 900,
]);
}
$videoGalleryItems = $youtubeEmbeds
->values()
->map(fn (string $url, int $index): array => [
'type' => 'video',
'src' => $url,
'thumb' => $resolveVideoThumb($url),
'title' => 'Video '.($index + 1).' de '.$h1,
]);
$galleryItems = $photoGalleryItems
->concat($videoGalleryItems)
->filter()
->unique(fn (array $item): string => $item['type'].'|'.$item['src'])
->values();
$heroGalleryItems = $galleryItems->take(4)->values();
$hasGalleryOverflow = $galleryItems->count() > $heroGalleryItems->count();
$heroRailItems = $heroGalleryItems->slice(1)->take(3)->values();
$heroRailOverflowPreview = $hasGalleryOverflow
? ($galleryItems->get($heroGalleryItems->count()) ?? $heroGalleryItems->last())
: null;
$primaryGalleryItem = $heroGalleryItems->first();
$galleryPhotosCount = $photoGalleryItems->count();
$galleryVideosCount = $videoGalleryItems->count();
$basePriceLabel = $profile->base_price ? '$'.number_format((float) $profile->base_price, 0, ',', '.') : 'Cotizar';
$providerProfile = $profile->mariachiProfile;
$responsibleName = $profile->responsible_name ?: $profile->user?->display_name ?: $h1;
$heroSummary = $profile->short_description ?: 'Servicio activo para serenatas, celebraciones y eventos privados.';
$providerPublicProfileUrl = $providerProfile?->slug
? route('mariachi.provider.public.show', ['handle' => $providerProfile->slug])
: null;
$verifiedProfileLabel = $isVerifiedProfile ? 'Perfil verificado' : null;
$listingDescriptionHtml = app(\App\Support\ListingDescriptionSanitizer::class)->sanitize($profile->description)
?? 'Este mariachi tiene su perfil activo y disponible para cotizaciones y eventos en su ciudad principal.
';
$coveragePreview = $coverageAreas->take(5)->values();
$listingCityLabel = $profile->publicCityLabel();
$listingCategoryItems = $profile->eventTypes->pluck('name')->filter()->take(2)->values();
if ($listingCategoryItems->isEmpty()) {
$listingCategoryItems = $serviceTypeNames->filter()->take(2)->values();
}
if ($listingCategoryItems->isEmpty()) {
$listingCategoryItems = collect(['Evento por cotizar']);
}
$listingRatingLabel = $reviewsTotal > 0 ? number_format($averageRating, 1) : 'Sin rating';
$listingOpinionsLabel = $reviewsTotal === 1 ? '1 opinión' : $reviewsTotal.' opiniones';
$listingMetaItems = collect([
['label' => $listingRatingLabel, 'kind' => 'rating'],
['label' => $listingOpinionsLabel, 'kind' => 'reviews'],
])
->merge($listingCategoryItems->map(fn (string $label): array => [
'label' => $label,
'kind' => 'category',
]))
->push([
'label' => $listingCityLabel,
'kind' => 'city',
])
->values();
$favoriteKey = 'listing-'.$profile->id;
$favoriteStoreUrl = auth()->user()?->role === \App\Models\User::ROLE_CLIENT
? route('client.favorites.store', ['slug' => $profile->slug])
: null;
$favoriteDestroyUrl = auth()->user()?->role === \App\Models\User::ROLE_CLIENT
? route('client.favorites.destroy', ['slug' => $profile->slug])
: null;
$shareEmailSubject = 'Mira este mariachi en Mariachis.co';
$shareEmailBody = 'He encontrado este mariachi en Mariachis.co y he pensado que te podria interesar: '.$h1."\r\n\r\n".'Echale un vistazo: '.url()->current();
$shareEmailHref = 'mailto:?subject='.rawurlencode($shareEmailSubject).'&body='.rawurlencode($shareEmailBody);
$currentListingPayload = [
'id' => $profile->id,
'slug' => $profile->slug,
'city' => $listingCityLabel,
'title' => $h1,
'image_url' => $mainPhotoUrl,
'price_label' => $basePriceLabel,
'contact_phone' => $publicPhoneDisplay,
'contact_whatsapp' => $publicWhatsappDisplay,
];
$reviewVerificationMap = [
'basic' => 'Opinion basica',
'manual_validated' => 'Validada manualmente',
'evidence_attached' => 'Con foto/prueba',
];
@endphp
@if($heroRailItems->isNotEmpty() || $hasGalleryOverflow)
@foreach($heroRailItems as $index => $media)
@endforeach
@if($hasGalleryOverflow && $heroRailOverflowPreview)
@endif
@endif
{{ $galleryPhotosCount }} foto(s)
@if($galleryVideosCount > 0)
{{ $galleryVideosCount }} video(s)
@endif
1 / {{ $heroGalleryItems->count() }}
Informacion
Resumen del anuncio
{{ $profile->short_description ?: 'Este mariachi tiene su perfil activo y disponible para cotizaciones.' }}
{!! $listingDescriptionHtml !!}
Ideal para
@if($profile->eventTypes->isNotEmpty())
@foreach($profile->eventTypes as $eventType)
{{ $eventType->name }}
@endforeach
@else
Se agregaran pronto los tipos de evento para este anuncio.
@endif
Cobertura principal
{{ $profile->address ? 'Referencia: '.$profile->address.'. ' : '' }}
Cobertura principal en {{ $listingCityLabel ?: 'su ciudad principal' }}.
@if($coveragePreview->isNotEmpty())
@foreach($coveragePreview as $area)
{{ $area }}
@endforeach
@endif
Detalles del anuncio
Tipo de servicio
Como suele presentarse
@if($serviceTypeNames->isNotEmpty())
@foreach($serviceTypeNames as $serviceTypeName)
{{ $serviceTypeName }}
@endforeach
@else
Sin especificar por ahora.
@endif
Tamaño del grupo
Formatos disponibles
@if($groupSizeNames->isNotEmpty())
@foreach($groupSizeNames as $groupSizeName)
{{ $groupSizeName }}
@endforeach
@else
Sin especificar por ahora.
@endif
Rango de presupuesto
Niveles de contratación
@if($budgetNames->isNotEmpty())
@foreach($budgetNames as $budgetName)
{{ $budgetName }}
@endforeach
@else
Sin especificar por ahora.
@endif
Precio desde
Referencia para cotizar
{{ $profile->base_price ? '$'.number_format((float) $profile->base_price, 0, ',', '.') : 'Se cotiza' }}
Este valor sirve como punto de partida. El total final puede variar según ciudad, duración y formato del evento.
@if($socialLinks->isNotEmpty())
@endif
Opiniones
Experiencias reales de clientes que conversaron con este mariachi.
@if($reviewsTotal > 0)
{{ number_format($averageRating, 1) }} / 5 · {{ $reviewsTotal }} reseña(s)
@endif
@if($reviewsTotal === 0)
Este anuncio aun no tiene opiniones publicas
Cuando una reseña sea aprobada por moderacion, aparecera aqui.
@else
@foreach($publicReviews as $review)
@php
$reviewClientName = $review->clientUser?->display_name ?: 'Cliente';
$reviewerInitial = strtoupper(mb_substr($reviewClientName, 0, 1));
$verificationLabel = $reviewVerificationMap[$review->verification_status] ?? $review->verification_status;
@endphp
{{ $reviewerInitial }}
{{ $reviewClientName }}
{{ $review->created_at->format('d M, Y') }}
@for($i = 1; $i <= 5; $i++)
★
@endfor
{{ $verificationLabel }}
@if($review->title)
{{ $review->title }}
@endif
{{ $review->comment }}
@if($review->event_type || $review->event_date)
{{ $review->event_type ?: 'Evento' }}
@if($review->event_date) · {{ $review->event_date->format('d M, Y') }} @endif
@endif
@if($review->photos->isNotEmpty())
@foreach($review->photos as $photo)
@endforeach
@endif
@if($review->mariachi_reply && $review->mariachi_reply_visible)
Respuesta del mariachi
{{ $review->mariachi_reply }}
@endif
@endforeach
@endif
Ubicacion
{{ $profile->address ? 'Referencia: '.$profile->address.'. ' : '' }}
Cobertura principal en {{ $listingCityLabel ?: 'su ciudad principal' }}.
Preguntas frecuentes
@php
$renderedFaqs = $profile->renderedFaqRows();
@endphp
@foreach($renderedFaqs as $index => $faq)
{{ $faq['answer'] }}
@endforeach
@if($relatedProfiles->isNotEmpty())
@else
Pronto habrá más opciones en esta ciudad
Cuando se publiquen nuevos perfiles, aparecerán aquí automáticamente.
@endif
@if($seoHelpfulLinkGroups->isNotEmpty())
Categorías
Sigue explorando en {{ $listingCityLabel }}
Compara zonas, ocasiones y anuncios parecidos sin salirte de esta búsqueda.
@foreach($seoHelpfulLinkGroups as $group)
@endforeach
@foreach($seoHelpfulLinkGroups as $group)
@endforeach
@endif
Vistos recientemente
Recupera los anuncios que estabas comparando para no perder el hilo.
Abrir historial
@if($recentlyViewedListings->isNotEmpty())
Aun no hay historial reciente en este navegador
Cuando visites otros anuncios activos, apareceran aqui automaticamente.
@else
Aun no hay historial reciente en este navegador
Cuando visites otros anuncios activos, apareceran aqui automaticamente.
@endif
@if($whatsappUrl)
WhatsApp
@endif
@if($phoneUrl)
Llamar
@endif
Contacto directo
Quiero más información
Déjanos tus datos y te ayudamos a validar disponibilidad y detalles del servicio.
@include('front.partials.site-footer')
@include('front.partials.auth-state-script')