phase 8 and 9
This commit is contained in:
@@ -0,0 +1,120 @@
|
||||
<x-analytics-layout :website="$website" :from="$from" :to="$to" title="Custom Dashboard">
|
||||
<x-slot name="headerActions">
|
||||
<a href="{{ route('custom-dashboard.manage', $website) }}" class="inline-flex items-center gap-2 px-3 py-2 rounded-lg border border-gray-300 text-sm font-medium text-gray-700 bg-white hover:bg-gray-50 transition">
|
||||
<svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M9.594 3.94c.09-.542.56-.94 1.11-.94h2.593c.55 0 1.02.398 1.11.94l.213 1.281c.063.374.313.686.645.87.074.04.147.083.22.127.325.196.72.257 1.075.124l1.217-.456a1.125 1.125 0 0 1 1.37.49l1.296 2.247a1.125 1.125 0 0 1-.26 1.431l-1.003.827c-.293.241-.438.613-.43.992a7.723 7.723 0 0 1 0 .255c-.008.378.137.75.43.991l1.004.827c.424.35.534.955.26 1.43l-1.298 2.247a1.125 1.125 0 0 1-1.369.491l-1.217-.456c-.355-.133-.75-.072-1.076.124a6.47 6.47 0 0 1-.22.128c-.331.183-.581.495-.644.869l-.213 1.281c-.09.543-.56.94-1.11.94h-2.594c-.55 0-1.019-.398-1.11-.94l-.213-1.281c-.062-.374-.312-.686-.644-.87a6.52 6.52 0 0 1-.22-.127c-.325-.196-.72-.257-1.076-.124l-1.217.456a1.125 1.125 0 0 1-1.369-.49l-1.297-2.247a1.125 1.125 0 0 1 .26-1.431l1.004-.827c.292-.24.437-.613.43-.991a6.932 6.932 0 0 1 0-.255c.007-.38-.138-.751-.43-.992l-1.004-.827a1.125 1.125 0 0 1-.26-1.43l1.297-2.247a1.125 1.125 0 0 1 1.37-.491l1.216.456c.356.133.751.072 1.076-.124.072-.044.146-.086.22-.128.332-.183.582-.495.644-.869l.214-1.28Z" /><path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z" /></svg>
|
||||
Manage Widgets
|
||||
</a>
|
||||
</x-slot>
|
||||
|
||||
@if ($widgets->isEmpty())
|
||||
<x-empty-state
|
||||
icon='<svg class="w-10 h-10" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M3.75 6A2.25 2.25 0 0 1 6 3.75h2.25A2.25 2.25 0 0 1 10.5 6v2.25a2.25 2.25 0 0 1-2.25 2.25H6a2.25 2.25 0 0 1-2.25-2.25V6ZM3.75 15.75A2.25 2.25 0 0 1 6 13.5h2.25a2.25 2.25 0 0 1 2.25 2.25V18a2.25 2.25 0 0 1-2.25 2.25H6A2.25 2.25 0 0 1 3.75 18v-2.25ZM13.5 6a2.25 2.25 0 0 1 2.25-2.25H18A2.25 2.25 0 0 1 20.25 6v2.25A2.25 2.25 0 0 1 18 10.5h-2.25a2.25 2.25 0 0 1-2.25-2.25V6ZM13.5 15.75a2.25 2.25 0 0 1 2.25-2.25H18a2.25 2.25 0 0 1 2.25 2.25V18A2.25 2.25 0 0 1 18 20.25h-2.25a2.25 2.25 0 0 1-2.25-2.25v-2.25Z" /></svg>'
|
||||
title="No widgets yet"
|
||||
message="Add widgets to build your custom dashboard."
|
||||
>
|
||||
<a href="{{ route('custom-dashboard.manage', $website) }}" class="mt-4 inline-flex items-center gap-2 px-4 py-2 bg-indigo-600 rounded-lg text-sm font-medium text-white hover:bg-indigo-500 transition">
|
||||
Manage Widgets
|
||||
</a>
|
||||
</x-empty-state>
|
||||
@else
|
||||
<div class="grid gap-4 grid-cols-1 sm:grid-cols-2 lg:grid-cols-3">
|
||||
@foreach ($widgets as $widget)
|
||||
@php
|
||||
$colSpan = match($widget->size) {
|
||||
'full' => 'sm:col-span-2 lg:col-span-3',
|
||||
'half' => 'sm:col-span-1 lg:col-span-2' ,
|
||||
default => '',
|
||||
};
|
||||
$data = $widgetData[$widget->id] ?? null;
|
||||
@endphp
|
||||
<div class="bg-white rounded-xl border border-gray-200 p-5 {{ $colSpan }}">
|
||||
<h3 class="text-sm font-semibold text-gray-900 mb-3">{{ $widget->title }}</h3>
|
||||
|
||||
@if ($widget->widget_type === 'metric')
|
||||
@php $metricLabel = \App\Models\DashboardWidget::$metrics[$widget->config['metric'] ?? 'page_views'] ?? 'Metric'; @endphp
|
||||
<p class="text-3xl font-bold text-gray-900 tabular-nums">
|
||||
@if (($widget->config['metric'] ?? '') === 'bounce_rate')
|
||||
{{ $data }}%
|
||||
@elseif (($widget->config['metric'] ?? '') === 'avg_duration')
|
||||
{{ gmdate('i:s', (int) $data) }}
|
||||
@else
|
||||
{{ number_format($data) }}
|
||||
@endif
|
||||
</p>
|
||||
<p class="text-xs text-gray-500 mt-1">{{ $metricLabel }}</p>
|
||||
|
||||
@elseif ($widget->widget_type === 'chart')
|
||||
<div style="height: 200px">
|
||||
<canvas id="widget-chart-{{ $widget->id }}"></canvas>
|
||||
</div>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const ctx = document.getElementById('widget-chart-{{ $widget->id }}');
|
||||
new Chart(ctx, {
|
||||
type: 'line',
|
||||
data: {
|
||||
labels: @json($data->pluck('date')),
|
||||
datasets: [{
|
||||
label: 'Visitors',
|
||||
data: @json($data->pluck('visitors')),
|
||||
borderColor: '#6366f1',
|
||||
backgroundColor: 'rgba(99,102,241,0.1)',
|
||||
fill: true,
|
||||
tension: 0.3,
|
||||
pointRadius: 0,
|
||||
}]
|
||||
},
|
||||
options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { display: false } }, scales: { x: { display: false }, y: { beginAtZero: true } } }
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
@elseif (in_array($widget->widget_type, ['top_pages', 'top_sources', 'browsers', 'countries', 'events']))
|
||||
@if ($data && $data->isNotEmpty())
|
||||
<div class="space-y-2">
|
||||
@foreach ($data->take(5) as $row)
|
||||
<div class="flex items-center justify-between text-sm">
|
||||
<span class="text-gray-600 truncate mr-2">
|
||||
{{ $row->path ?? $row->source ?? $row->browser ?? $row->country ?? $row->name ?? '—' }}
|
||||
</span>
|
||||
<span class="font-medium text-gray-900 tabular-nums shrink-0">
|
||||
{{ number_format($row->views ?? $row->sessions ?? $row->visitors ?? $row->total ?? 0) }}
|
||||
</span>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
@else
|
||||
<p class="text-sm text-gray-400">No data for this period.</p>
|
||||
@endif
|
||||
|
||||
@elseif ($widget->widget_type === 'new_vs_returning')
|
||||
<div class="flex items-center gap-6">
|
||||
<div>
|
||||
<p class="text-2xl font-bold text-indigo-600 tabular-nums">{{ $data['new_pct'] ?? 0 }}%</p>
|
||||
<p class="text-xs text-gray-500">New</p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-2xl font-bold text-emerald-600 tabular-nums">{{ $data['returning_pct'] ?? 0 }}%</p>
|
||||
<p class="text-xs text-gray-500">Returning</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@elseif ($widget->widget_type === 'conversions')
|
||||
@if ($data && $data->isNotEmpty())
|
||||
<div class="space-y-2">
|
||||
@foreach ($data->take(5) as $goal)
|
||||
<div class="flex items-center justify-between text-sm">
|
||||
<span class="text-gray-600 truncate mr-2">{{ $goal->name }}</span>
|
||||
<span class="font-medium text-gray-900 tabular-nums shrink-0">{{ number_format($goal->conversions) }}</span>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
@else
|
||||
<p class="text-sm text-gray-400">No conversions for this period.</p>
|
||||
@endif
|
||||
@endif
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
</x-analytics-layout>
|
||||
Reference in New Issue
Block a user