@extends('layouts.app') @push('head') @endpush @php $attraction = $coaster->attraction; $park = $attraction->park; $translation = $attraction->translations->firstWhere('locale', app()->getLocale()) ?? $attraction->translations->firstWhere('locale', 'en'); $coasterName = $translation?->name ?: $attraction->official_name; $parkTranslation = $park->translations->firstWhere('locale', app()->getLocale()) ?? $park->translations->firstWhere('locale', 'en'); $parkName = $parkTranslation?->name ?: $park->official_name; $live = $attraction->liveStatus; $liveFresh = (bool) ($liveInsight['is_fresh'] ?? false); $liveStatus = $liveInsight['status'] ?? 'unknown'; $displayWait = $liveInsight['display_wait_minutes'] ?? null; $waitKind = $liveInsight['wait_kind'] ?? 'unavailable'; $waitTrend = $liveInsight['trend'] ?? 'unknown'; $waitTrendDelta = $liveInsight['trend_delta_minutes'] ?? null; $singleRiderWait = $liveInsight['single_rider_wait_minutes'] ?? null; $liveObservedAt = $liveInsight['source_observed_at'] ?? $live?->fetched_at; $liveOpen = in_array($liveStatus, ['open', 'operating'], true); $liveClosed = in_array($liveStatus, ['down', 'closed', 'refurbishment'], true); $liveStatusLabel = match ($liveStatus) { 'open', 'operating' => __('ui.live_status_open'), 'down' => __('ui.live_status_down'), 'closed' => __('ui.live_status_closed'), 'refurbishment' => __('ui.live_status_refurbishment'), default => __('ui.live_status_unknown'), }; $catalogStatusLabel = ucfirst(str_replace('_', ' ', $attraction->status ?: __('ui.coaster_unknown'))); $parkLocation = collect([$park->city, $park->country?->official_name])->filter()->join(' · '); $modelName = $coaster->rideModel?->name; $modelDisplayName = $modelName; if ($modelDisplayName && $coaster->length_m !== null) { // Use a non-slash regex delimiter because '/' is one of the accepted // separators in model names such as "Family Thrill Launch / 670m". // The previous slash-delimited pattern treated that character as the // end of the regex and could raise an ErrorException on public pages. $cleanModelDisplayName = preg_replace('~\s*[/|·-]\s*\d+(?:[.,]\d+)?\s*m\s*$~iu', '', $modelDisplayName); if (is_string($cleanModelDisplayName) && trim($cleanModelDisplayName) !== '') { $modelDisplayName = $cleanModelDisplayName; } } $duration = $coaster->duration_seconds ? sprintf('%d:%02d', intdiv($coaster->duration_seconds, 60), $coaster->duration_seconds % 60) : null; $knownSpecs = collect([ $coaster->height_m, $coaster->drop_m, $coaster->length_m, $coaster->speed_kmh, $coaster->inversions, $coaster->launches, $coaster->trains, $coaster->duration_seconds, ])->filter(fn ($value) => $value !== null)->count(); @endphp @section('title', $coasterName.' — Coaster World') @if($bannerUrl) @push('head') @endpush @endif @section('content')
{{ __('ui.coaster_kicker') }}

{{ $coasterName }}

{{ $parkName }} @if($coaster->manufacturer){{ $coaster->manufacturer->name }}@endif @if($modelDisplayName){{ $modelDisplayName }}@endif @if($attraction->opened_on){{ $attraction->opened_on->format('Y') }}@endif
@auth
@csrf
@csrf
@if(!$isRidden)
user()->is_admin) data-gps-required data-gps-kind="ride" data-gps-loading="{{ __('ui.gps_validating_ride') }}" data-gps-unavailable="{{ __('ui.gps_unavailable') }}" data-gps-denied="{{ __('ui.gps_permission_denied') }}" data-gps-timeout="{{ __('ui.gps_timeout') }}" data-gps-error="{{ __('ui.gps_error') }}" @endif>@csrf
@else ✓ {{ __('ui.collection_done_short') }} @endif {{ __('ui.contribution_propose') }} @include('pages.partials.community-photo-upload', ['photoType' => 'coaster', 'photoId' => $coaster->id]) @if(auth()->user()->is_admin) {{ __('ui.public_admin_coaster') }} @endif
@endauth
{{ __('ui.coaster_live') }} {{ $live ? $liveStatusLabel : __('ui.live_status_unknown') }} single_rider_available)) hidden @endif> {{ __('ui.live_single_rider') }} · {{ $singleRiderWait !== null ? $singleRiderWait.' min' : __('ui.special_queue_available') }} fetched_at) hidden @endif> {{ __('ui.live_checked_prefix') }}
@if(session('community_photo_status') === 'submitted')
{{ __('ui.community_photo_submitted') }}
@endif
{{ __('ui.coaster_speed') }} {{ $coaster->speed_kmh !== null ? rtrim(rtrim(number_format((float)$coaster->speed_kmh, 1, '.', ''), '0'), '.') : '—' }}km/h
{{ __('ui.coaster_height') }} {{ $coaster->height_m !== null ? rtrim(rtrim(number_format((float)$coaster->height_m, 1, '.', ''), '0'), '.') : '—' }}m
{{ __('ui.coaster_length') }} {{ $coaster->length_m !== null ? rtrim(rtrim(number_format((float)$coaster->length_m, 1, '.', ''), '0'), '.') : '—' }}m
{{ __('ui.coaster_inversions') }} {{ $coaster->inversions ?? '—' }}
@if(auth()->check() && auth()->user()->is_admin) @endif {{ __('ui.coaster_profile_kicker') }}

{{ __('ui.coaster_profile_title') }}

{{ $translation?->description ?: $translation?->summary ?: __('ui.coaster_description_empty') }}

@if($knownSpecs === 0)
{{ __('ui.coaster_data_pending_title') }}

{{ __('ui.coaster_data_pending_text') }}

@endif
{{ __('ui.coaster_park') }}{{ $parkName }}
{{ __('ui.coaster_manufacturer') }}{{ $coaster->manufacturer?->name ?: __('ui.coaster_unknown') }}
{{ __('ui.coaster_model') }}{{ $modelDisplayName ?: __('ui.coaster_unknown') }}
{{ __('ui.coaster_type') }}{{ $coaster->coaster_type ?: __('ui.coaster_unknown') }}
{{ __('ui.coaster_track') }}{{ $coaster->track_material ?: __('ui.coaster_unknown') }}
{{ __('ui.coaster_propulsion') }}{{ $coaster->propulsion_type ?: __('ui.coaster_unknown') }}
{{ __('ui.coaster_length') }}{{ $coaster->length_m !== null ? rtrim(rtrim(number_format((float) $coaster->length_m, 1, '.', ''), '0'), '.') .' m' : '—' }}
{{ __('ui.coaster_duration') }}{{ $duration ?: '—' }}
{{ __('ui.coaster_estimated_budget') }}{{ $attraction->estimated_budget ?: '—' }}
{{ __('ui.public_catalog_status') }}{{ $catalogStatusLabel }}
{{ __('ui.public_opened_on') }}{{ $attraction->opened_on?->translatedFormat('d F Y') ?: '—' }}
@if($attraction->closed_on)
{{ __('ui.public_closed_on') }}{{ $attraction->closed_on->translatedFormat('d F Y') }}
@endif
@include('pages.partials.coaster-inline-admin-dialogs') @include('pages.partials.wait-forecast', ['waitForecast' => $waitForecast]) @include('pages.partials.wait-history', ['waitHistory' => $waitHistory]) @include('pages.partials.park-context-card', ['parkCard' => $parkCard]) @if($gallery->isNotEmpty())
{{ __('ui.coaster_gallery_kicker') }}

{{ __('ui.coaster_gallery_title') }}

@if($communityPhotoCount > 0) @endif
@endif @if($related->isNotEmpty())
{{ __('ui.coaster_related_kicker') }}

{{ __('ui.coaster_related_title', ['park' => $parkName]) }}

@endif @include('pages.partials.community-reviews', ['community' => $community]) @endsection