diff --git a/resources/css/app.css b/resources/css/app.css
new file mode 100644
index 0000000..61b6935
--- /dev/null
+++ b/resources/css/app.css
@@ -0,0 +1,11 @@
+@import 'tailwindcss';
+
+@source '../../vendor/laravel/framework/src/Illuminate/Pagination/resources/views/*.blade.php';
+@source '../../storage/framework/views/*.php';
+@source '../**/*.blade.php';
+@source '../**/*.js';
+
+@theme {
+ --font-sans: 'Instrument Sans', ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji',
+ 'Segoe UI Symbol', 'Noto Color Emoji';
+}
\ No newline at end of file
diff --git a/resources/js/app.js b/resources/js/app.js
new file mode 100644
index 0000000..e59d6a0
--- /dev/null
+++ b/resources/js/app.js
@@ -0,0 +1 @@
+import './bootstrap';
diff --git a/resources/js/bootstrap.js b/resources/js/bootstrap.js
new file mode 100644
index 0000000..5f1390b
--- /dev/null
+++ b/resources/js/bootstrap.js
@@ -0,0 +1,4 @@
+import axios from 'axios';
+window.axios = axios;
+
+window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
diff --git a/resources/views/admin/carousel/create.blade.php b/resources/views/admin/carousel/create.blade.php
new file mode 100644
index 0000000..5ef3008
--- /dev/null
+++ b/resources/views/admin/carousel/create.blade.php
@@ -0,0 +1,69 @@
+@extends('admin.layout')
+
+@section('title', 'Agregar Slide')
+
+@section('content')
+
+
➕ Agregar Slide
+
+ Volver a la Lista
+
+
+
+
+@endsection
diff --git a/resources/views/admin/carousel/edit.blade.php b/resources/views/admin/carousel/edit.blade.php
new file mode 100644
index 0000000..d604906
--- /dev/null
+++ b/resources/views/admin/carousel/edit.blade.php
@@ -0,0 +1,76 @@
+@extends('admin.layout')
+
+@section('title', 'Editar Slide')
+
+@section('content')
+
+
✏️ Editar Slide
+
+ Volver a la Lista
+
+
+
+
+@endsection
diff --git a/resources/views/admin/carousel/index.blade.php b/resources/views/admin/carousel/index.blade.php
new file mode 100644
index 0000000..212bb36
--- /dev/null
+++ b/resources/views/admin/carousel/index.blade.php
@@ -0,0 +1,83 @@
+@extends('admin.layout')
+
+@section('title', 'Carrusel Principal - Admin OnAPB')
+
+@section('content')
+
+
+ Visual Merchandising
+
+
+
+ AGREGAR SLIDE
+
+
+
+
+ @if($items->isEmpty())
+
+
+
No hay slides en el carrusel.
+
+ @else
+
+
+
+
+ Orden
+ Imagen
+ Título / Subtítulo
+ Botón de Acción
+ Estado
+ Acciones
+
+
+
+ @foreach($items as $item)
+
+ {{ $item->orden }}
+
+
+
+
+
+
+ {{ $item->titulo ?: '(SIN TÍTULO)' }}
+ {{ $item->subtitulo }}
+
+
+ @if($item->boton_texto)
+ {{ $item->boton_texto }}
+ {{ Str::limit($item->boton_enlace, 20) }}
+ @else
+ —
+ @endif
+
+
+ @if($item->activo)
+ ACTIVO
+ @else
+ OCULTO
+ @endif
+
+
+
+
+
+
+
+
+ @endforeach
+
+
+
+ @endif
+
+@endsection
diff --git a/resources/views/admin/categorias/form.blade.php b/resources/views/admin/categorias/form.blade.php
new file mode 100644
index 0000000..c6f3fbb
--- /dev/null
+++ b/resources/views/admin/categorias/form.blade.php
@@ -0,0 +1,76 @@
+@extends('admin.layout')
+
+@section('title', ($categoria ? 'Editar' : 'Nueva') . ' Categoría - Admin OnAPB')
+
+@section('content')
+
+
+
+@endsection
diff --git a/resources/views/admin/categorias/index.blade.php b/resources/views/admin/categorias/index.blade.php
new file mode 100644
index 0000000..a9e76f6
--- /dev/null
+++ b/resources/views/admin/categorias/index.blade.php
@@ -0,0 +1,68 @@
+@extends('admin.layout')
+
+@section('title', 'Categorías - Admin OnAPB')
+
+@section('content')
+
+
+ Estructura de Competencia
+
+
+
+ NUEVA CATEGORÍA
+
+
+
+
+ @if($categorias->isEmpty())
+
+
+
No hay categorías registradas.
+
+ @else
+
+
+
+
+ Categoría
+ Rango de Edad
+ Género
+ Tipo
+ Acciones
+
+
+
+ @foreach($categorias as $cat)
+
+ {{ $cat->nombre }}
+
+ {{ $cat->edad_min }} - {{ $cat->edad_max }} años
+
+ {{ $cat->genero ?? 'Mixto' }}
+
+ @if($cat->es_libre)
+ LIBRE
+ @else
+ Estándar
+ @endif
+
+
+
+
+
+
+
+
+ @endforeach
+
+
+
+ @endif
+
+@endsection
diff --git a/resources/views/admin/clubes/form.blade.php b/resources/views/admin/clubes/form.blade.php
new file mode 100644
index 0000000..c924a83
--- /dev/null
+++ b/resources/views/admin/clubes/form.blade.php
@@ -0,0 +1,170 @@
+@extends('admin.layout')
+
+@section('title', ($club ? 'Editar' : 'Nuevo') . ' Club - Admin OnAPB')
+
+@section('content')
+
+
+
+@endsection
diff --git a/resources/views/admin/clubes/index.blade.php b/resources/views/admin/clubes/index.blade.php
new file mode 100644
index 0000000..e530a02
--- /dev/null
+++ b/resources/views/admin/clubes/index.blade.php
@@ -0,0 +1,139 @@
+@extends('admin.layout')
+
+@section('title', 'Clubes - Admin OnAPB')
+
+@section('content')
+
+
+
+
+ @if($clubes->isEmpty())
+
+
+
{{ !empty($search) ? 'No se encontraron clubes para "' . $search . '"' : 'No hay clubes registrados.' }}
+
+ @else
+
+
+
+
+ ID
+ Club
+ Equipos
+ Jugadores
+ Acciones
+
+
+
+ @foreach($clubes as $club)
+
+ #{{ $club->id_club }}
+
+
+ @if($club->imagen)
+
+ @else
+
+
+
+ @endif
+
{{ $club->nombre }}
+
+
+
+ {{ $club->equipos_count }}
+ Equipos
+
+
+ {{ $club->jugadores_count }}
+ Jugadores
+
+
+
+ Editar
+
+
+
+
+ @endforeach
+
+
+
+ @endif
+
+
+@endsection
+
+@section('scripts')
+
+@endsection
diff --git a/resources/views/admin/dashboard.blade.php b/resources/views/admin/dashboard.blade.php
new file mode 100644
index 0000000..efdcbe7
--- /dev/null
+++ b/resources/views/admin/dashboard.blade.php
@@ -0,0 +1,106 @@
+@extends('admin.layout')
+
+@section('title', 'Dashboard - Admin OnAPB')
+
+@section('content')
+
+ @if($miClub)
+
+ @if($miClub->qr_background)
+
+
+
+ @endif
+
+ Panel de Club
+
+
+
+ @else
+
Resumen General
+
+ @endif
+
+
+
+
+ @if(session('admin_role') == 1)
+
+ @endif
+
+
+
+
+
+ @if(session('admin_role') == 1)
+
+ @endif
+
+
+
+
+
+
+
+
+
+
+
Bienvenido al nuevo panel de control de OnAPB. Desde aquí podés gestionar toda la información de la asociación con una interfaz optimizada para el rendimiento.
+
+
Tip de Administración
+
Recordá que podés escanear los QRs de los aficionados directamente desde el botón en la barra superior o en las acciones rápidas para validar ingresos en tiempo real.
+
+
+
+
+@endsection
diff --git a/resources/views/admin/equipos/form.blade.php b/resources/views/admin/equipos/form.blade.php
new file mode 100644
index 0000000..f5ad966
--- /dev/null
+++ b/resources/views/admin/equipos/form.blade.php
@@ -0,0 +1,80 @@
+@extends('admin.layout')
+
+@section('title', ($equipo ? 'Editar' : 'Nuevo') . ' Equipo - Admin OnAPB')
+
+@section('content')
+
+
+
+@endsection
diff --git a/resources/views/admin/equipos/index.blade.php b/resources/views/admin/equipos/index.blade.php
new file mode 100644
index 0000000..c554cc4
--- /dev/null
+++ b/resources/views/admin/equipos/index.blade.php
@@ -0,0 +1,139 @@
+@extends('admin.layout')
+
+@section('title', 'Equipos - Admin OnAPB')
+
+@section('content')
+
+
+
+
+ @if($equipos->isEmpty())
+
+
+
+ {{ !empty($search) ? 'No se encontraron equipos para "' . $search . '"' : 'No hay equipos registrados.' }}
+
+
+ @else
+
+
+
+
+ ID
+ @if(session('admin_role') == 1)
+ Club
+ @endif
+ Categoría
+ División
+ Plantel
+ Acciones
+
+
+
+ @foreach($equipos as $equipo)
+
+ #{{ $equipo->id_equipo }}
+ @if(session('admin_role') == 1)
+ {{ $equipo->club->nombre ?? '—' }}
+ @endif
+ {{ $equipo->categoria }}
+ {{ $equipo->division ?? '—' }}
+
+
+ {{ $equipo->jugadores_count }}
+ Jugadores registrados
+
+
+
+
+ Editar
+
+
+
+
+ @endforeach
+
+
+
+ @endif
+
+
+@endsection
+
+@section('scripts')
+
+@endsection
diff --git a/resources/views/admin/equipos/jugadores.blade.php b/resources/views/admin/equipos/jugadores.blade.php
new file mode 100644
index 0000000..853ba75
--- /dev/null
+++ b/resources/views/admin/equipos/jugadores.blade.php
@@ -0,0 +1,151 @@
+@extends('admin.layout')
+
+@section('title', 'Gestionar Jugadores - ' . $equipo->categoria . ' - Admin OnAPB')
+
+@section('content')
+
+
+
+
+
+
+
+
+
+
Escribe al menos 3 caracteres para buscar.
+
+
+
+
+
+
+
+
+
+ @if($equipo->jugadores->isEmpty())
+
+
+ No hay jugadores asignados a este equipo todavía.
+
+ @else
+
+
+
+
+ ID
+ Jugador
+ DNI
+ Acción
+
+
+
+ @foreach($equipo->jugadores as $jugador)
+
+ {{ $jugador->id_jugador }}
+ {{ $jugador->apellido }}, {{ $jugador->nombre }}
+ {{ $jugador->documento }}
+
+
+
+
+ @endforeach
+
+
+
+ @endif
+
+
+
+
+
+
+
+
+
+@endsection
diff --git a/resources/views/admin/escanear_qr.blade.php b/resources/views/admin/escanear_qr.blade.php
new file mode 100644
index 0000000..a6c3c33
--- /dev/null
+++ b/resources/views/admin/escanear_qr.blade.php
@@ -0,0 +1,391 @@
+@extends('admin.layout')
+
+@section('title', 'Escanear QR - Admin OnAPB')
+
+@section('styles')
+
+@endsection
+
+@section('content')
+
+
+
+
+
+
+ {{-- 1. Selector de Evento --}}
+
+
+ Seleccionar evento:
+
+
+ -- Seleccioná un evento --
+ @foreach($eventos as $ev)
+
+ {{ $ev->nombre_evento }} ({{ $ev->fecha_evento ? \Carbon\Carbon::parse($ev->fecha_evento)->format('d/m/Y') : '' }} {{ substr($ev->hora_inicio, 0, 5) }})
+
+ @endforeach
+
+
+
+ {{-- Badge del evento seleccionado --}}
+
+
+
Apuntá con la cámara al código QR o ingresalo manualmente.
+
+ {{-- 2. Botones de cámara --}}
+
+
+ Iniciar escaneo
+
+
+ Detener
+
+
+
+ {{-- 3. Visor de cámara --}}
+
+
+ {{-- 4. Input manual (fallback) --}}
+
+
O ingresá el código manualmente:
+
+
+
+ Validar
+
+
+
+
+ {{-- 5. Resultado --}}
+
+
+
+
+
+
+{{-- Sonidos de feedback --}}
+
+
+@endsection
+
+@section('scripts')
+{{-- Librería html5-qrcode --}}
+
+
+@endsection
diff --git a/resources/views/admin/eventos/form.blade.php b/resources/views/admin/eventos/form.blade.php
new file mode 100644
index 0000000..7367b87
--- /dev/null
+++ b/resources/views/admin/eventos/form.blade.php
@@ -0,0 +1,288 @@
+@extends('admin.layout')
+
+@section('title', ($evento ? 'Editar' : 'Nuevo') . ' Evento - Admin OnAPB')
+
+@section('content')
+
+
+
+@endsection
+
+@section('scripts')
+
+@endsection
diff --git a/resources/views/admin/eventos/index.blade.php b/resources/views/admin/eventos/index.blade.php
new file mode 100644
index 0000000..dfd880c
--- /dev/null
+++ b/resources/views/admin/eventos/index.blade.php
@@ -0,0 +1,125 @@
+@extends('admin.layout')
+
+@section('title', 'Partidos - Admin OnAPB')
+
+@section('content')
+
+
+ Calendario de Juego
+
+
+ @if(session('admin_role') == 1)
+
+ NUEVO EVENTO
+
+ @endif
+
+
+
+
+
+ @if($eventos->isEmpty())
+
+
+
No hay eventos registrados.
+
+ @else
+
+
+
+
+ Estado
+ Partido
+ Fecha / Hora
+ Sede
+ Acciones
+
+
+
+ @foreach($eventos as $e)
+
+
+ @php
+ $ahoraStr = \Carbon\Carbon::now()->toDateTimeString();
+
+ // Extraer fecha y hora de forma segura (soportando tanto strings como objetos Carbon)
+ $f = $e->fecha_evento instanceof \Carbon\Carbon ? $e->fecha_evento->format('Y-m-d') : substr((string)$e->fecha_evento, 0, 10);
+ $h = $e->hora_fin instanceof \Carbon\Carbon ? $e->hora_fin->format('H:i:s') : (string)$e->hora_fin;
+ if (strlen($h) == 5) $h .= ':00'; // Asegurar formato H:i:s
+
+ $momentoFin = "$f $h";
+
+ // Un evento esta finalizado si tiene marcadores Y el tiempo de fin ya paso
+ $tieneMarcadores = !is_null($e->marcador_local) && !is_null($e->marcador_visitante);
+ $finalizado = $tieneMarcadores && ($ahoraStr >= $momentoFin);
+ @endphp
+
+ @if($finalizado)
+ FINALIZADO
+
+ {{ $e->marcador_local }} - {{ $e->marcador_visitante }}
+
+ @else
+ PENDIENTE
+ @endif
+
+
+
+
+ {{ $e->equipoLocal->club->nombre ?? 'Local' }}
+ {{ $e->equipoLocal->categoria ?? '' }} {{ $e->equipoLocal->division ?? '' }}
+
+
VS
+
+ {{ $e->equipoVisitante->club->nombre ?? 'Visitante' }}
+ {{ $e->equipoVisitante->categoria ?? '' }} {{ $e->equipoVisitante->division ?? '' }}
+
+
+
+
+ {{ $e->fecha_evento ? \Carbon\Carbon::parse($e->fecha_evento)->format('d/m/Y') : '—' }}
+ {{ $e->hora_inicio }} - {{ $e->hora_fin }}
+
+ {{ $e->sede ?? 'TBD' }}
+
+ @if(session('admin_role') == 1)
+
+
+
+ @endif
+ @if($e->id_equipo_local && $e->id_equipo_visitante)
+
+
+
+ @endif
+ @if(session('admin_role') == 1)
+
+ @endif
+
+
+ @endforeach
+
+
+
+ @endif
+
+@endsection
diff --git a/resources/views/admin/eventos/stats.blade.php b/resources/views/admin/eventos/stats.blade.php
new file mode 100644
index 0000000..be4f57c
--- /dev/null
+++ b/resources/views/admin/eventos/stats.blade.php
@@ -0,0 +1,121 @@
+@extends('admin.layout')
+
+@section('title', 'Cargar Resultados - ' . $evento->nombre_evento)
+
+@section('content')
+
+
+
+@section('styles')
+
+@endsection
+@endsection
diff --git a/resources/views/admin/jugadores/form.blade.php b/resources/views/admin/jugadores/form.blade.php
new file mode 100644
index 0000000..c78b3f7
--- /dev/null
+++ b/resources/views/admin/jugadores/form.blade.php
@@ -0,0 +1,154 @@
+@extends('admin.layout')
+
+@section('title', ($jugador ? 'Editar' : 'Nuevo') . ' Jugador - Admin OnAPB')
+
+@section('content')
+
+
+
+@endsection
+
+@section('scripts')
+
+@endsection
diff --git a/resources/views/admin/jugadores/index.blade.php b/resources/views/admin/jugadores/index.blade.php
new file mode 100644
index 0000000..e5266a1
--- /dev/null
+++ b/resources/views/admin/jugadores/index.blade.php
@@ -0,0 +1,180 @@
+@extends('admin.layout')
+
+@section('title', 'Jugadores - Admin OnAPB')
+
+@section('content')
+
+
+
+ Base de Datos Deportiva
+
+
+
+ NUEVO JUGADOR
+
+
+
+
+
+
+
+
+
+ @if(session('admin_role') == 1 || session('admin_role') == 2)
+
+
+ Herramientas CSV
+
+
+
+ @endif
+
+
+
+
+
+
+ @if($jugadores->isEmpty())
+
+
+
{{ $search ? 'No se encontraron resultados para "' . $search . '"' : 'No hay jugadores registrados.' }}
+
+ @else
+
+
+
+
+ Jugador
+ Documento
+ Categoría
+ Club Actual
+ Estado
+ Acciones
+
+
+
+ @foreach($jugadores as $j)
+
+
+ {{ $j->apellido }}, {{ $j->nombre }}
+
+ {{ $j->documento }}
+ {{ $j->categoria_calculada }}
+ {{ $j->clubActual->nombre ?? '—' }}
+
+ @if($j->activo)
+ Activo
+ @else
+ Inactivo
+ @endif
+
+
+
+
+
+
+
+
+ @endforeach
+
+
+
+
+
+ {{ $jugadores->appends(['q' => $search])->links('pagination::bootstrap-5') }}
+
+ @endif
+
+
+@endsection
+
+@section('scripts')
+
+@endsection
diff --git a/resources/views/admin/layout.blade.php b/resources/views/admin/layout.blade.php
new file mode 100644
index 0000000..6ca81f5
--- /dev/null
+++ b/resources/views/admin/layout.blade.php
@@ -0,0 +1,335 @@
+
+
+
+
+
+ @yield('title', 'Admin - OnAPB')
+
+
+
+
+
+
+
+
+ @yield('styles')
+
+
+
+
+
+
+
+
+
+
+
+
+
+ @yield('content')
+
+
+
+
+
+
+
+
+
+
+ {{-- Kinetic FX: capa de innovación visual también en admin --}}
+
+ @yield('scripts')
+
+
diff --git a/resources/views/admin/noticias/form.blade.php b/resources/views/admin/noticias/form.blade.php
new file mode 100644
index 0000000..96dd5d2
--- /dev/null
+++ b/resources/views/admin/noticias/form.blade.php
@@ -0,0 +1,83 @@
+@extends('admin.layout')
+
+@section('title', ($noticia ? 'Editar' : 'Nueva') . ' Noticia - Admin OnAPB')
+
+@section('content')
+
+
+
+@endsection
diff --git a/resources/views/admin/noticias/index.blade.php b/resources/views/admin/noticias/index.blade.php
new file mode 100644
index 0000000..09b8476
--- /dev/null
+++ b/resources/views/admin/noticias/index.blade.php
@@ -0,0 +1,77 @@
+@extends('admin.layout')
+
+@section('title', 'Noticias - Admin OnAPB')
+
+@section('content')
+
+
+ Comunicación Oficial
+
+
+
+ NUEVA NOTICIA
+
+
+
+
+ @if($noticias->isEmpty())
+
+
+
No hay noticias publicadas.
+
+ @else
+
+
+
+
+ ID
+ Imagen
+ Título / Categoría
+ Publicación
+ Acciones
+
+
+
+ @foreach($noticias as $n)
+
+ #{{ $n->id }}
+
+ @if($n->imagen)
+
+ @else
+
+
+
+ @endif
+
+
+ @if($n->categoria)
+ {{ strtoupper($n->categoria) }}
+ @endif
+ {{ $n->titulo }}
+
+
+
+ {{ $n->fecha ? \Carbon\Carbon::parse($n->fecha)->format('d/m/Y H:i') : '—' }}
+
+
+
+
+
+
+
+ @csrf
+ @method('DELETE')
+
+
+
+
+
+
+ @endforeach
+
+
+
+ @endif
+
+@endsection
diff --git a/resources/views/admin/pases/create.blade.php b/resources/views/admin/pases/create.blade.php
new file mode 100644
index 0000000..e1fe8de
--- /dev/null
+++ b/resources/views/admin/pases/create.blade.php
@@ -0,0 +1,59 @@
+@extends('admin.layout')
+
+@section('title', 'Solicitar Pase - Admin OnAPB')
+
+@section('content')
+
+
+
+
+
+ @csrf
+
+
+ Ingrese el DNI del jugador que desea solicitar para su club.
+
+
+
+
+
+
DNI del Jugador *
+
+ @error('documento')
+
{{ $message }}
+ @enderror
+
+
+
+ @if(session('admin_role') == 1)
+
+
+
Club Destino (Como Superadmin, ¿para qué club solicita?)
+
+ Seleccione club
+ @foreach(\App\Models\Club::orderBy('nombre')->get() as $club)
+ {{ $club->nombre }}
+ @endforeach
+
+ @error('id_club_destino')
+
{{ $message }}
+ @enderror
+
+
+ @endif
+
+
+
+
+ Enviar Solicitud
+
+
+
+
+
+@endsection
diff --git a/resources/views/admin/pases/index.blade.php b/resources/views/admin/pases/index.blade.php
new file mode 100644
index 0000000..0dca2ad
--- /dev/null
+++ b/resources/views/admin/pases/index.blade.php
@@ -0,0 +1,83 @@
+@extends('admin.layout')
+
+@section('title', 'Pases - Admin OnAPB')
+
+@section('content')
+
+
+ Mercado de Jugadores
+
+
+
+ SOLICITAR PASE
+
+
+
+
+ @if($pases->isEmpty())
+
+
+
No hay solicitudes de pase registradas.
+
+ @else
+
+
+
+
+ Jugador
+ Origen
+ Destino
+ Estado
+ Fecha Solicitud
+ @if(session('admin_role') == 1)
+ Acciones
+ @endif
+
+
+
+ @foreach($pases as $pase)
+
+
+ {{ $pase->jugador->apellido ?? '—' }}, {{ $pase->jugador->nombre ?? '—' }}
+ DNI: {{ $pase->jugador->documento ?? '—' }}
+
+ {{ $pase->clubOrigen->nombre ?? 'Libre' }}
+ {{ $pase->clubDestino->nombre ?? '—' }}
+
+ @if($pase->estado === 'Pendiente')
+ Pendiente
+ @elseif($pase->estado === 'Aprobado')
+ Aprobado
+ @else
+ Rechazado
+ @endif
+
+ {{ $pase->created_at->format('d/m/Y') }}
+ @if(session('admin_role') == 1)
+
+ @if($pase->estado === 'Pendiente')
+
+
+ @csrf @method('PUT')
+ Aprobar
+
+
+ @csrf @method('PUT')
+ Rechazar
+
+
+ @endif
+
+ @endif
+
+ @endforeach
+
+
+
+
+
+ {{ $pases->links() }}
+
+ @endif
+
+@endsection
diff --git a/resources/views/admin/promociones/form.blade.php b/resources/views/admin/promociones/form.blade.php
new file mode 100644
index 0000000..e09c127
--- /dev/null
+++ b/resources/views/admin/promociones/form.blade.php
@@ -0,0 +1,103 @@
+@extends('admin.layout')
+
+@section('title', ($promocion ? 'Editar' : 'Nueva') . ' Promoción - Admin OnAPB')
+
+@section('content')
+
+
+
+
+
+ @csrf
+ @if($promocion) @method('PUT') @endif
+
+
+
+
+
Nombre *
+
+ @error('nombre')
+
{{ $message }}
+ @enderror
+
+
+
+
+
Dirección *
+
+ @error('direccion')
+
{{ $message }}
+ @enderror
+
+
+
+
+
+
+
+
+
+ Descripción del beneficio
+ {{ old('descripcion', $promocion->descripcion ?? '') }}
+
+
+
+
+ Descripción del lugar
+ {{ old('descripcion_lugar', $promocion->descripcion_lugar ?? '') }}
+
+
+
+
+
+
+
+
Imagen
+
+ @if($promocion && $promocion->imagen)
+
+
+
Imagen actual: {{ $promocion->imagen }}
+
+ @endif
+
+
+
+
+
+ {{ $promocion ? 'Actualizar' : 'Crear Promoción' }}
+
+
+
+
+@endsection
diff --git a/resources/views/admin/promociones/index.blade.php b/resources/views/admin/promociones/index.blade.php
new file mode 100644
index 0000000..be70d6a
--- /dev/null
+++ b/resources/views/admin/promociones/index.blade.php
@@ -0,0 +1,70 @@
+@extends('admin.layout')
+
+@section('title', 'Promociones - Admin OnAPB')
+
+@section('content')
+
+
+
+
+ @if($promociones->isEmpty())
+
+
+
No hay promociones registradas.
+
+ @else
+
+
+
+
+ ID
+ Nombre
+ Dirección
+ Categoría
+ QRs
+ Acciones
+
+
+
+ @foreach($promociones as $p)
+
+ {{ $p->id }}
+
+ {{ $p->nombre }}
+ @if($p->imagen)
+
+ @endif
+
+ {{ $p->direccion }}
+
+ {{ $p->categoria ?? 'Sin categoría' }}
+
+
+ {{ $p->promo_qrs_count }}
+
+
+
+ Editar
+
+
+ @csrf
+ @method('DELETE')
+
+
+
+
+
+
+ @endforeach
+
+
+
+ @endif
+
+
+@endsection
diff --git a/resources/views/admin/settings.blade.php b/resources/views/admin/settings.blade.php
new file mode 100644
index 0000000..726b8d4
--- /dev/null
+++ b/resources/views/admin/settings.blade.php
@@ -0,0 +1,131 @@
+@extends('admin.layout')
+
+@section('title', 'Configuración del Sistema')
+
+@section('content')
+
+
+
+
+
+
+ @csrf
+
+
+
Días para expiración de eventos
+
+
+ Días
+
+
+
+ Los eventos cuya fecha sea anterior a esta cantidad de días serán eliminados automáticamente junto con sus QRs asociados.
+
+
+
+
+
Frecuencia del Backup Automático
+
+ Diario (Cada noche)
+ Semanal (Cada lunes)
+ Mensual (Día 1 de cada mes)
+
+
+
+ Define con qué frecuencia el sistema generará un respaldo completo de la base de datos y archivos multimedia.
+
+
+
+
+
Email para Reportes Semanales
+
+
+
+ Dirección donde se enviará el resumen de actividad de la liga todos los lunes.
+
+
+
+
+
+
+
+
+ Tarea programada: app:cleanup-old-events (Ejecución diaria)
+
+
+ Guardar Cambios
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Última ejecución del Programador
+ {{ $lastRun }}
+
+
+
+
+
+ Hora actual del servidor
+ {{ now()->format('d/m/Y H:i:s') }}
+
+
+
+
+
+
+ Si el "Última ejecución" no coincide con el minuto actual, es posible que el Cron Job de Hostinger no esté configurado correctamente.
+
+
+
+
+
EJECUCIÓN MANUAL DE TAREAS
+
+
+ @csrf
+
+
+ Limpiar QRs Antiguos
+
+
+
+
+ @csrf
+
+
+ Forzar Backup
+
+
+
+
+ @csrf
+
+
+ Enviar Informe Semanal
+
+
+
+
+
+
+
+@endsection
diff --git a/resources/views/admin/sponsors/form.blade.php b/resources/views/admin/sponsors/form.blade.php
new file mode 100644
index 0000000..fc5ed06
--- /dev/null
+++ b/resources/views/admin/sponsors/form.blade.php
@@ -0,0 +1,98 @@
+@extends('admin.layout')
+
+@section('title', (isset($sponsor) ? 'Editar' : 'Nuevo') . ' Sponsor - Admin OnAPB')
+
+@section('content')
+
+
+
+
+
+ @csrf
+ @if(isset($sponsor))
+ @method('PUT')
+ @endif
+
+
+
+
+ Nombre del Sponsor *
+
+
+
+
+ URL del sitio (opcional)
+
+
+
+
+
+
+ Orden de aparición
+
+ Menor número aparece primero.
+
+
+
+
+ activo ?? true) ? 'checked' : '' }}>
+ Sponsor Activo
+
+
+
+
+
+
+
+
Logo / Imagen *
+
+
+ @if(isset($sponsor) && $sponsor->imagen)
+
+ @else
+
+
+ Vista previa
+
+
+ @endif
+
+
Formato recomendado: PNG transparente o fondo blanco.
+
+
+
+
+
+
+
+ {{ isset($sponsor) ? 'Actualizar' : 'Guardar' }} Sponsor
+
+
+
+
+
+
+@section('scripts')
+
+@endsection
+@endsection
diff --git a/resources/views/admin/sponsors/index.blade.php b/resources/views/admin/sponsors/index.blade.php
new file mode 100644
index 0000000..3273899
--- /dev/null
+++ b/resources/views/admin/sponsors/index.blade.php
@@ -0,0 +1,78 @@
+@extends('admin.layout')
+
+@section('title', 'Sponsors - Admin OnAPB')
+
+@section('content')
+
+
+ Alianzas Estratégicas
+
+
+
+ NUEVO SPONSOR
+
+
+
+
+ @if($sponsors->isEmpty())
+
+
+
No hay sponsors registrados.
+
+ @else
+
+
+
+
+ Orden
+ Imagen
+ Nombre
+ Enlace
+ Estado
+ Acciones
+
+
+
+ @foreach($sponsors as $s)
+
+ {{ $s->orden }}
+
+
+
+
+
+ {{ $s->nombre }}
+
+ @if($s->url)
+ {{ Str::limit($s->url, 30) }}
+ @else
+ SIN ENLACE
+ @endif
+
+
+ @if($s->activo)
+ ACTIVO
+ @else
+ OCULTO
+ @endif
+
+
+
+
+
+
+ @csrf
+ @method('DELETE')
+
+
+
+
+
+
+ @endforeach
+
+
+
+ @endif
+
+@endsection
diff --git a/resources/views/admin/torneos/fixture_preview.blade.php b/resources/views/admin/torneos/fixture_preview.blade.php
new file mode 100644
index 0000000..36637f5
--- /dev/null
+++ b/resources/views/admin/torneos/fixture_preview.blade.php
@@ -0,0 +1,88 @@
+@extends('admin.layout')
+
+@section('title', 'Preview Fixture — ' . $torneo->nombre)
+
+@section('content')
+
+
+
+
+
+
+ {{-- Agrupar por jornada --}}
+ @php
+ $jornadas = collect($partidosEnriquecidos)->groupBy('jornada');
+ @endphp
+
+ @foreach($jornadas as $numJornada => $partidos)
+
+
+ Jornada {{ $numJornada }}
+ {{ \Carbon\Carbon::parse($partidos->first()['fecha_evento'])->format('d/m/Y') }}
+
+
+
+
+
+ Local
+ vs
+ Visitante
+ Fecha
+ Hora
+ Sede
+
+
+
+ @foreach($partidos as $p)
+
+ {{ $p['nombre_local'] }}
+ 🆚
+ {{ $p['nombre_visitante'] }}
+ {{ \Carbon\Carbon::parse($p['fecha_evento'])->format('d/m/Y') }}
+ {{ substr($p['hora_inicio'], 0, 5) }}
+ {{ $p['sede'] ?: '—' }}
+
+ @endforeach
+
+
+
+
+ @endforeach
+
+ {{-- Botón de confirmación --}}
+
+
+ Cancelar
+
+
+ @csrf
+
+
+
+
+
+ Confirmar y Generar Fixture
+
+
+
+
+
+
+
+@endsection
diff --git a/resources/views/admin/torneos/form.blade.php b/resources/views/admin/torneos/form.blade.php
new file mode 100644
index 0000000..a745a4f
--- /dev/null
+++ b/resources/views/admin/torneos/form.blade.php
@@ -0,0 +1,237 @@
+@extends('admin.layout')
+
+@section('title', ($torneo ? 'Editar' : 'Nuevo') . ' Torneo - Admin OnAPB')
+
+@section('content')
+
+
+
+
+
+
+
+
+ @csrf
+ @if($torneo) @method('PUT') @endif
+
+
+ Nombre del Torneo *
+
+
+
+
+
+
+ Fecha de Inicio
+
+
+
+
+
+
+
+ {{ $torneo ? 'Actualizar Torneo' : 'Crear Torneo' }}
+
+
+
+
+
+
+ @if($torneo)
+
+
+
+
+
+
+ @csrf
+
+ Asignar Equipo al Torneo
+
+ Buscar equipo por club / categoría...
+ @foreach($clubes as $club)
+
+ @foreach($club->equipos as $eq)
+
+ {{ $eq->categoria }} {{ $eq->division ? '('.$eq->division.')' : '' }}
+
+ @endforeach
+
+ @endforeach
+
+
+
+ Grupo / División (Opcional)
+
+
+
+
+ Agregar
+
+
+
+
+
+
+
+
+ Club
+ Categoría Base
+ Grupo en Torneo
+ Acciones
+
+
+
+ @forelse($torneo->equipos as $te)
+
+
+ {{ $te->club->nombre }}
+
+
+ {{ $te->categoria }} {{ $te->division }}
+
+
+ @if($te->pivot->grupo)
+ {{ $te->pivot->grupo }}
+ @else
+ Usar Base
+ @endif
+
+
+
+ @csrf @method('DELETE')
+
+
+
+
+
+
+ @empty
+
+ No hay equipos asignados a este torneo.
+
+ @endforelse
+
+
+
+
+
+
+ @endif
+
+
+@if($torneo && $torneo->equipos->count() >= 2)
+
+
+
+
+
+
+
+
+ @csrf
+
+
+ Grupo / Categoría
+
+ Seleccione grupo...
+ @php
+ $grupos = \DB::table('torneo_equipo')->where('id_torneo', $torneo->id)->distinct()->pluck('grupo')->filter();
+ @endphp
+ @foreach($grupos as $g)
+ {{ $g }}
+ @endforeach
+
+
+
+ Formato de Serie
+
+ Partido Único
+ Mejor de 3
+ Mejor de 5
+
+
+
+
+ Los 8 mejores del grupo iniciarán en Cuartos.
+
+
+
+
+
+
+
+
+@elseif($torneo)
+
+
+ Necesitás al menos 2 equipos asignados al torneo para generar el fixture.
+
+@endif
+
+@endsection
+
diff --git a/resources/views/admin/torneos/importar.blade.php b/resources/views/admin/torneos/importar.blade.php
new file mode 100644
index 0000000..00e0138
--- /dev/null
+++ b/resources/views/admin/torneos/importar.blade.php
@@ -0,0 +1,46 @@
+@extends('layouts.app')
+
+@section('content')
+
+
+
Importar Fixture Histórico
+
+ Volver
+
+
+
+
+
+
Instrucciones
+
+ Pega aquí los partidos ya jugados para cargarlos masivamente.
+ El formato debe ser CSV con las siguientes 9 columnas :
+
+
+ Fecha(AAAA-MM-DD), Club Local, Cat Local, Club Visitante, Cat Visitante, Marcador L, Marcador V, Sede(opc), Grupo(opc)
+
+
+
+ Manejo de Equipos: El sistema busca por Club Y Categoría. Esto permite diferenciar, por ejemplo, los equipos de "San Martin" en "Primera A" de los de "Primera B" en el mismo torneo.
+
+
+
+ @csrf
+
+ Datos a importar (CSV)
+
+
+
+
+
+ Esta acción creará nuevos registros de eventos. Evita duplicar partidos que ya existan en el sistema.
+
+
+
+ Procesar e Importar
+
+
+
+
+
+@endsection
diff --git a/resources/views/admin/torneos/index.blade.php b/resources/views/admin/torneos/index.blade.php
new file mode 100644
index 0000000..cbeadec
--- /dev/null
+++ b/resources/views/admin/torneos/index.blade.php
@@ -0,0 +1,57 @@
+@extends('admin.layout')
+
+@section('title', 'Gestión de Torneos - Admin OnAPB')
+
+@section('content')
+
+
+
+
+
+
+
+ Nombre
+ Inicio
+ Fin
+ Equipos
+ Acciones
+
+
+
+ @forelse($torneos as $torneo)
+
+ {{ $torneo->nombre }}
+ {{ $torneo->fecha_inicio ? $torneo->fecha_inicio->format('d/m/Y') : '—' }}
+ {{ $torneo->fecha_fin ? $torneo->fecha_fin->format('d/m/Y') : '—' }}
+
+ {{ $torneo->equipos_count }}
+
+
+
+
+
+
+
+ @csrf @method('DELETE')
+
+
+
+
+
+
+
+ @empty
+
+ No hay torneos creados.
+
+ @endforelse
+
+
+
+
+@endsection
diff --git a/resources/views/admin/torneos/playoff_manage.blade.php b/resources/views/admin/torneos/playoff_manage.blade.php
new file mode 100644
index 0000000..c38b4b9
--- /dev/null
+++ b/resources/views/admin/torneos/playoff_manage.blade.php
@@ -0,0 +1,142 @@
+@extends('admin.layout')
+
+@section('title', 'Gestión de Playoffs - ' . $torneo->nombre)
+
+@section('content')
+
+
+
+
+
+
+
{{ $torneo->nombre }}
+
Control de llaves y avance manual de ganadores por serie.
+
+
+
+ Actualizar Estado
+
+
+
+
+
+
+@php
+ $fases = [
+ \App\Models\Evento::FASE_CUARTOS => 'Cuartos de Final',
+ \App\Models\Evento::FASE_SEMIS => 'Semifinales',
+ \App\Models\Evento::FASE_FINAL => 'Gran Final'
+ ];
+@endphp
+
+@foreach($fases as $faseId => $faseNombre)
+
+
+ {{ $faseNombre }}
+
+
+
+ @php $hayPartidos = isset($bracket[$faseId]) && count($bracket[$faseId]) > 0; @endphp
+
+ @if($hayPartidos)
+ @foreach($bracket[$faseId] as $nroBracket => $serie)
+
+
+
+
+
+
+ @if($serie['equipo_local'])
+
+
+ {{ $serie['equipo_local']->club->nombre }}
+
+ @else
+
Por definir
+ @endif
+
+
{{ $serie['wins_local'] }}
+
+
+
+
+ @if($serie['equipo_visitante'])
+
+
+ {{ $serie['equipo_visitante']->club->nombre }}
+
+ @else
+
Por definir
+ @endif
+
+
{{ $serie['wins_visitante'] }}
+
+
+
+
+
+
+ @php
+ $needed = floor($serie['total_partidos'] / 2) + 1;
+ $readyToAdvance = ($serie['wins_local'] >= $needed || $serie['wins_visitante'] >= $needed);
+ $winnerId = $serie['wins_local'] > $serie['wins_visitante'] ? ($serie['equipo_local']->id_equipo ?? null) : ($serie['equipo_visitante']->id_equipo ?? null);
+ @endphp
+
+ @if($readyToAdvance && $faseId < \App\Models\Evento::FASE_FINAL)
+
+ @csrf
+
+
+
+
+ PROMOCIONAR GANADOR
+
+
+ @endif
+
+
+ Ver Partidos ({{ $serie['total_partidos'] }})
+
+
+
+
+
+ @foreach($serie['matches'] as $idx => $m)
+
+ G{{ $idx+1 }} - {{ $m->fecha_evento->format('d/m') }}
+
+
{{ $m->marcador_local ?? '-' }} : {{ $m->marcador_visitante ?? '-' }}
+
+
+
+
+
+ @endforeach
+
+
+
+
+
+ @endforeach
+ @else
+
+
+ No hay llaves generadas para esta fase.
+
+
+ @endif
+
+
+@endforeach
+
+@endsection
diff --git a/resources/views/admin/usuarios/form.blade.php b/resources/views/admin/usuarios/form.blade.php
new file mode 100644
index 0000000..bf425ea
--- /dev/null
+++ b/resources/views/admin/usuarios/form.blade.php
@@ -0,0 +1,95 @@
+@extends('admin.layout')
+
+@section('title', ($usuario ? 'Editar' : 'Nuevo') . ' Administrador - Admin OnAPB')
+
+@section('content')
+
+
+
+
+
+ @csrf
+ @if($usuario) @method('PUT') @endif
+
+
+
+
+
Nombre de Usuario *
+
+ @error('username')
{{ $message }}
@enderror
+
+
+
+
+
+
Contraseña {{ $usuario ? '(Dejar en blanco para no cambiarla)' : '*' }}
+
+ @error('password')
{{ $message }}
@enderror
+
+
+
+
+
+
+
+
Rol del Administrador *
+
+ role ?? '') == 1 ? 'selected' : '' }}>Super Administrador (Acceso total)
+ role ?? '') == 2 || (!old('role') && !$usuario) ? 'selected' : '' }}>Administrador de Club
+
+ @error('role')
{{ $message }}
@enderror
+
+
+
+
+
+
Club Asociado (Solo para Admin de Club)
+
+ Seleccione el Club...
+ @foreach($clubes as $club)
+ id_club ?? '') == $club->id_club ? 'selected' : '' }}>
+ {{ $club->nombre }}
+
+ @endforeach
+
+ @error('id_club')
{{ $message }}
@enderror
+
+
+
+
+
+ {{ $usuario ? 'Guardar Cambios' : 'Crear Administrador' }}
+
+
+
+
+@endsection
+
+@section('scripts')
+
+@endsection
diff --git a/resources/views/admin/usuarios/index.blade.php b/resources/views/admin/usuarios/index.blade.php
new file mode 100644
index 0000000..5bcdd1d
--- /dev/null
+++ b/resources/views/admin/usuarios/index.blade.php
@@ -0,0 +1,74 @@
+@extends('admin.layout')
+
+@section('title', 'Administradores - Admin OnAPB')
+
+@section('content')
+
+
+ Control de Accesos
+
+
+
+ NUEVO USUARIO
+
+
+
+
+ @if($usuarios->isEmpty())
+
+
+
No hay otros administradores registrados.
+
+ @else
+
+
+
+
+ Usuario
+ Nivel de Acceso
+ Club Responsable
+ Acciones
+
+
+
+ @foreach($usuarios as $user)
+
+
+ {{ $user->username }}
+
+
+ @if($user->role == 1)
+ Súper Admin
+ @else
+ Admin Club
+ @endif
+
+
+ {{ $user->club->nombre ?? 'SISTEMA INTEGRAL' }}
+
+
+
+
+
+ @if($user->id != session('admin_id'))
+
+ @csrf
+ @method('DELETE')
+
+
+
+
+ @endif
+
+
+ @endforeach
+
+
+
+
+
+ {{ $usuarios->links('pagination::bootstrap-5') }}
+
+ @endif
+
+@endsection
diff --git a/resources/views/auth/asociate.blade.php b/resources/views/auth/asociate.blade.php
new file mode 100644
index 0000000..bd6b18a
--- /dev/null
+++ b/resources/views/auth/asociate.blade.php
@@ -0,0 +1,244 @@
+@extends('layouts.app')
+
+@section('title', 'Unite - OnAPB')
+
+@section('styles')
+
+@endsection
+
+@section('content')
+
+
+
+
Comunidad OnAPB
+
Unite al Juego.
+
Formá parte de la comunidad del básquet entrerriano y accedé a beneficios exclusivos.
+
+
+
+
+
+
+
+
+ Aficionado
+
+
+ Jugador
+
+
+
+
+
+
+
+
+
+
+
Registro de Aficionado
+
Como aficionado, podés seguir tus equipos favoritos y acceder a descuentos en clubes y comercios adheridos.
+
+
Beneficios
+
+ QRs de acceso
+ Mapa de beneficios
+ Noticias exclusivas
+
+
+
+
+ @if($errors->any())
+
+
+ @foreach($errors->all() as $error)
+ {{ $error }}
+ @endforeach
+
+
+ @endif
+
+
+ @csrf
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Portal de Jugador
+
Si estás fichado en un club de la APB, activá tu cuenta para gestionar tus datos y acceder a beneficios únicos para deportistas.
+
+
Verificación
+
Usamos tu DNI para validar tu ficha técnica actual en el sistema de la asociación.
+
+
+
+ @if(isset($jugador_encontrado))
+
+
¡Jugador Encontrado!
+
Validamos tus datos en {{ $jugador_encontrado['club'] }}. Completá tu perfil abajo.
+
+
+
+ @csrf
+
+
+
+
Nombre
+
{{ $jugador_encontrado['nombre'] }}
+
+
+
Apellido
+
{{ $jugador_encontrado['apellido'] }}
+
+
+ Email de Contacto *
+
+
+
+ Contraseña *
+
+
+
+ Confirmar Contraseña *
+
+
+
+
+
+ ACEPTO LOS TÉRMINOS Y CONDICIONES
+
+
+
+
+ FINALIZAR ACTIVACIÓN
+
+
+
+ @else
+
+ @csrf
+ Buscá tus datos
+
+
+ Nombre *
+
+
+
+ Apellido *
+
+
+
+ DNI *
+
+
+
+
+
+ ACEPTO LA VALIDACIÓN DE DATOS ASOCIATIVOS
+
+
+
+ BUSCAR MI FICHA
+
+
+
+ @endif
+
+
+
+
+
+
+
+
+
+@section('scripts')
+
+@endsection
+@endsection
diff --git a/resources/views/auth/recuperar.blade.php b/resources/views/auth/recuperar.blade.php
new file mode 100644
index 0000000..7550cf5
--- /dev/null
+++ b/resources/views/auth/recuperar.blade.php
@@ -0,0 +1,58 @@
+@extends('layouts.app')
+
+@section('title', 'Recuperar contraseña - OnAPB')
+
+@section('content')
+
+
+
RECUPERAR CONTRASEÑA
+
Ingresá tu DNI y tu correo electrónico. Te enviaremos un enlace para restablecerla de forma segura.
+
+ @if(session('mensaje'))
+
+
+
+ {!! session('mensaje') !!}
+
+
+ @endif
+
+ @if($errors->any())
+
+
+
+ @foreach($errors->all() as $error)
+ {{ $error }}
+ @endforeach
+
+
+ @endif
+
+
+ @csrf
+
+
+
+ DNI *
+
+
+
+
+ Correo Electrónico *
+
+
+
+
+ Enviar enlace de recuperación
+
+
+
+
+
+@endsection
diff --git a/resources/views/auth/reset_password.blade.php b/resources/views/auth/reset_password.blade.php
new file mode 100644
index 0000000..a150fa2
--- /dev/null
+++ b/resources/views/auth/reset_password.blade.php
@@ -0,0 +1,55 @@
+@extends('layouts.app')
+
+@section('title', 'Restablecer contraseña - OnAPB')
+
+@section('content')
+
+
+
RESTABLECER CONTRASEÑA
+
+ @if(session('mensaje'))
+
+ {!! session('mensaje') !!}
+
+ @endif
+
+ @if($errors->any())
+
+ @foreach($errors->all() as $error)
+
{{ $error }}
+ @endforeach
+
+ @endif
+
+
+ @csrf
+
+
+
+
Nueva contraseña
+
+
+
+
+
+
+
+
+
Confirmar nueva contraseña
+
+
+
+
+
+
+
+ Cambiar contraseña
+
+
+
+
+@endsection
diff --git a/resources/views/components/genius-chat.blade.php b/resources/views/components/genius-chat.blade.php
new file mode 100644
index 0000000..ad5360a
--- /dev/null
+++ b/resources/views/components/genius-chat.blade.php
@@ -0,0 +1,380 @@
+{{-- OnAPB Genius Agent — Chat Bubble --}}
+
+
+
+
+
+
+
+
+
+
+ ¡Hola! Soy OnAPB Genius. ¿En qué puedo ayudarte hoy?
+
+
Escribiendo...
+
+
+ @csrf
+
+
+
+
+
+
diff --git a/resources/views/documentacion/index.blade.php b/resources/views/documentacion/index.blade.php
new file mode 100644
index 0000000..b7ac10a
--- /dev/null
+++ b/resources/views/documentacion/index.blade.php
@@ -0,0 +1,75 @@
+@extends('layouts.app')
+
+@section('title', 'Manual de Usuario - OnAPB')
+
+@section('content')
+
+
+
+
+
+ Centro de Ayuda
+
Manual de Usuario.
+
+
+
+
+
+
+
+
+
+
+
+
+
¿Necesitás más ayuda?
+
Si tenés dudas técnicas o problemas con el sistema, contactá con el administrador de tu club o con la mesa de ayuda de la APB.
+
+
+
+
+
+
+
+
+@endsection
diff --git a/resources/views/documentacion/pdf.blade.php b/resources/views/documentacion/pdf.blade.php
new file mode 100644
index 0000000..3d38f21
--- /dev/null
+++ b/resources/views/documentacion/pdf.blade.php
@@ -0,0 +1,147 @@
+
+
+
+
+ Manual de Usuario - OnAPB
+
+
+
+
+
+
+ © {{ date('Y') }} OnAPB - Kinetic Arena Experience | Página
+
+
+
+ {!! $content !!}
+
+
+
diff --git a/resources/views/emails/qrcodes.blade.php b/resources/views/emails/qrcodes.blade.php
new file mode 100644
index 0000000..724c4fc
--- /dev/null
+++ b/resources/views/emails/qrcodes.blade.php
@@ -0,0 +1,53 @@
+
+
+
+
+
+ Tus QRs para el Evento - OnAPB
+
+
+
+
+
+
+
¡Hola, {{ $user->nombre }} !
+
Se han generado exitosamente tus QRs para el siguiente evento:
+
+
+
{{ $evento->nombre_evento }}
+
+ Fecha: {{ \Carbon\Carbon::parse($evento->fecha_evento)->format('d/m/Y') }}
+ Sede: {{ $evento->sede ?? 'A confirmar' }}
+
+
{{ $cantidad }}
+
QRs Generados
+
+
+
Ya podés verlos y descargarlos desde la sección "Mis QRs" en tu panel personal:
+
+ VER MIS ENTRADAS
+
+
+
Recordá presentar estos QRs en la entrada del estadio para su escaneo.
+
+
+
+
+
diff --git a/resources/views/emails/reporte_semanal.blade.php b/resources/views/emails/reporte_semanal.blade.php
new file mode 100644
index 0000000..0418fc4
--- /dev/null
+++ b/resources/views/emails/reporte_semanal.blade.php
@@ -0,0 +1,150 @@
+
+
+
+
+
+ Reporte Semanal ONAPB
+
+
+
+
+
+
+ {{-- Estadísticas rápidas --}}
+
+
Resumen
+
+
+
{{ $jugados->count() }}
+
Partidos jugados
+
+
+
{{ $proximos->count() }}
+
Próximos partidos
+
+
+
{{ $qrsSemana }}
+
QRs generados
+
+
+
{{ $qrsValidados }}
+
QRs validados
+
+
+
+
+ {{-- Resultados de la semana --}}
+
+
Resultados de la Semana
+ @if($jugados->isEmpty())
+
No hubo partidos con resultado cargado esta semana.
+ @else
+
+
+
+ Fecha
+ Local
+ Resultado
+ Visitante
+
+
+
+ @foreach($jugados as $e)
+ @php
+ $ml = $e->marcador_local;
+ $mv = $e->marcador_visitante;
+ $badgeLocal = $ml > $mv ? 'badge-win' : ($ml < $mv ? 'badge-lose' : 'badge-draw');
+ $badgeVisitante= $mv > $ml ? 'badge-win' : ($mv < $ml ? 'badge-lose' : 'badge-draw');
+ @endphp
+
+ {{ $e->fecha_evento->format('d/m') }}
+ {{ $e->equipoLocal->club->nombre ?? '?' }}
+ {{ $ml }} — {{ $mv }}
+ {{ $e->equipoVisitante->club->nombre ?? '?' }}
+
+ @endforeach
+
+
+ @endif
+
+
+ {{-- Próximos partidos --}}
+
+
Próximos Partidos (7 días)
+ @if($proximos->isEmpty())
+
No hay partidos programados para los próximos 7 días.
+ @else
+
+
+ Fecha Hora Partido Sede
+
+
+ @foreach($proximos as $e)
+
+ {{ $e->fecha_evento->format('d/m') }}
+ {{ $e->hora_inicio ? \Carbon\Carbon::parse($e->hora_inicio)->format('H:i') : '—' }}
+ {{ $e->equipoLocal->club->nombre ?? '?' }} vs {{ $e->equipoVisitante->club->nombre ?? '?' }}
+ {{ $e->sede ?: '—' }}
+
+ @endforeach
+
+
+ @endif
+
+
+ {{-- Top goleadores --}}
+
+
🏆 Top Goleadores
+ @if($topGoleadores->isEmpty())
+
Sin estadísticas de puntos cargadas aún.
+ @else
+
+
+ # Jugador Pts totales Partidos
+
+
+ @foreach($topGoleadores as $i => $g)
+
+ {{ $i + 1 }}
+ {{ $g->apellido }}, {{ $g->nombre }}
+ {{ $g->total_puntos }}
+ {{ $g->partidos }}
+
+ @endforeach
+
+
+ @endif
+
+
+
+
+
+
diff --git a/resources/views/emails/reset_password.blade.php b/resources/views/emails/reset_password.blade.php
new file mode 100644
index 0000000..291e4f1
--- /dev/null
+++ b/resources/views/emails/reset_password.blade.php
@@ -0,0 +1,50 @@
+
+
+
+
+
+ Recuperar Contraseña - OnAPB
+
+
+
+
+
+
+
Hola, {{ $user->nombre }}
+
Hemos recibido una solicitud para restablecer la contraseña de tu cuenta en OnAPB .
+
+
Para continuar con el proceso, hacé clic en el siguiente botón:
+
+
+ RESTABLECER CONTRASEÑA
+
+
+
+ Importante: Este enlace vencerá en 1 hora por razones de seguridad. Si vos no solicitaste este cambio, podés ignorar este correo; tu contraseña seguirá siendo la misma.
+
+
+
Si tenés problemas con el botón, copiá y pegá el siguiente enlace en tu navegador:
+
+ {{ url('/reset-password/' . $token) }}
+
+
+
+
+
+
diff --git a/resources/views/emails/welcome.blade.php b/resources/views/emails/welcome.blade.php
new file mode 100644
index 0000000..7886e9f
--- /dev/null
+++ b/resources/views/emails/welcome.blade.php
@@ -0,0 +1,49 @@
+
+
+
+
+
+ Bienvenido a OnAPB
+
+
+
+
+
+
+
¡Hola, {{ $user->nombre }}!
+
Es un gusto darte la bienvenida a OnAPB , la plataforma oficial de la Asociación Paranaense de Básquetbol.
+
+
Te has registrado correctamente como {{ ucfirst($tipo) }} . Ya podés acceder a tu panel para ver tus QRs, noticias y beneficios exclusivos.
+
+
+ Tus datos registrados:
+ Nombre: {{ $user->nombre }} {{ $user->apellido }}
+ DNI: {{ $user->dni ?? $user->documento }}
+ Email: {{ $user->email }}
+
+
+
Para ingresar al sistema, hacé clic en el siguiente botón:
+
+ INGRESAR AL PANEL
+
+
+
+
+
+
diff --git a/resources/views/equipos/show.blade.php b/resources/views/equipos/show.blade.php
new file mode 100644
index 0000000..8fb298d
--- /dev/null
+++ b/resources/views/equipos/show.blade.php
@@ -0,0 +1,208 @@
+@extends('layouts.app')
+
+@section('title', 'Plantilla - ' . ($equipo->club->nombre ?? 'Equipo'))
+
+@section('content')
+
+
+
+
+
+
+
+ @if($equipo->club && $equipo->club->imagen)
+
+ @else
+
+
+
+ @endif
+
+
+
Ficha Oficial de Equipo
+
+ {{ $equipo->club->nombre ?? 'Equipo' }}
+
+
+ {{ $equipo->categoria }} {{ $equipo->division }}
+
+
+
+
+
+ {{ $equipo->jugadores->count() }} Jugadores
+
+
+
+ {{ $equipo->club->nombre ?? 'Sede Oficial' }}
+
+
+ {{-- Botón Seguir (solo para usuarios logueados) --}}
+ @if(session('user_logged_in'))
+
+
+ Cargando...
+
+ @else
+
+ Seguir equipo
+
+ @endif
+
+
+
+
+
+
+
+
+
+
+
+
+
Plantilla Actual
+
Temporada {{ date('Y') }}
+
+
+ Volver
+
+
+
+
+
+
+
+
+ Jugador
+ Categoría
+ Estado
+
+
+
+ @forelse($equipo->jugadores as $j)
+
+
+
+
+ {{ substr($j->nombre, 0, 1) }}{{ substr($j->apellido, 0, 1) }}
+
+
+
{{ $j->apellido }}, {{ $j->nombre }}
+
{{ $j->categoria }}
+
+
+
+
+ {{ $j->categoria }}
+
+
+ @if($j->activo)
+
+
+ Habilitado
+
+ @else
+
+
+ Pendiente
+
+ @endif
+
+
+ @empty
+
+
+ No hay jugadores registrados en este equipo todavía.
+
+
+ @endforelse
+
+
+
+
+
+
+
+
+
+
+
+@if(session('user_logged_in'))
+
+@endif
+@endsection
diff --git a/resources/views/eventos/index.blade.php b/resources/views/eventos/index.blade.php
new file mode 100644
index 0000000..9a113fc
--- /dev/null
+++ b/resources/views/eventos/index.blade.php
@@ -0,0 +1,105 @@
+@extends('layouts.app')
+
+@section('title', 'Partidos - OnAPB')
+
+@section('styles')
+
+@endsection
+
+@section('content')
+
+
+
Calendario ONAPB
+
+
+
+
+
+
+ @if($eventos->isEmpty())
+
+
+
+
No hay partidos programados para esta fecha.
+
+
+ @else
+ @foreach($eventos as $e)
+ @php
+ $localClub = $e->equipoLocal?->club;
+ $visitanteClub = $e->equipoVisitante?->club;
+ $isLive = $e->estado === 'Activo';
+ @endphp
+
+ @endforeach
+ @endif
+
+
+
+
+@endsection
diff --git a/resources/views/eventos/show.blade.php b/resources/views/eventos/show.blade.php
new file mode 100644
index 0000000..6013645
--- /dev/null
+++ b/resources/views/eventos/show.blade.php
@@ -0,0 +1,119 @@
+@extends('layouts.app')
+
+@section('title', 'Detalle Partido - OnAPB')
+
+@section('content')
+@section('content')
+
+
+ nombre_evento ?? (
+ ($evento->equipoLocal?->club?->nombre ?? 'Local') . ' vs ' . ($evento->equipoVisitante?->club?->nombre ?? 'Visitante')
+ );
+ $localClub = $evento->equipoLocal?->club;
+ $visitanteClub = $evento->equipoVisitante?->club;
+ ?>
+
+
+
+
+
+
Match Profile
+
{{ $nombreEvento }}
+
+
+
+
+
+
+
+ @if($localClub && $localClub->imagen)
+
+ @endif
+
{{ $localClub?->nombre ?? 'Local' }}
+
{{ $evento->equipoLocal?->categoria }}
+
+
+ VS
+
+
+ @if($visitanteClub && $visitanteClub->imagen)
+
+ @endif
+
{{ $visitanteClub?->nombre ?? 'Visitante' }}
+
{{ $evento->equipoVisitante?->categoria }}
+
+
+
+
+
+
+
+
+ Fecha
+ {{ \Carbon\Carbon::parse($evento->fecha_evento)->translatedFormat('d F Y') }}
+
+
+
+
+ Horario
+ {{ \Carbon\Carbon::parse($evento->hora_inicio)->format('H:i') }} hs
+
+
+
+
+ Estado
+ {{ $evento->estado }}
+
+
+
+
+
+
+
UBICACIÓN
+
{{ $evento->sede ?? 'Sede a confirmar' }}
+
+
+
+
+
+
+
+
ENTRADAS
+
+ @if($evento->precio > 0)
+ ${{ number_format($evento->precio, 0, ',', '.') }} / entrada
+ @else
+ FREE / asociados
+ @endif
+
+
+ @if($evento->estado !== 'Finalizado')
+ @if($isUser)
+
+ @csrf
+
+ SOLICITAR QR
+
+
VER MIS REGISTROS
+ @elseif(!$isAdmin)
+
INICIAR SESIÓN
+ @endif
+ @endif
+
+ @if($isAdmin)
+
+ @endif
+
+
+
+
+
+
+
+
+@endsection
diff --git a/resources/views/layouts/app.blade.php b/resources/views/layouts/app.blade.php
new file mode 100644
index 0000000..7da4b1c
--- /dev/null
+++ b/resources/views/layouts/app.blade.php
@@ -0,0 +1,740 @@
+
+
+
+
+
+ @yield('title', 'OnAPB')
+
+
+ {{-- PWA --}}
+
+
+
+
+
+
+
+
+
+
+
+ {{-- Preload del logo del navbar (LCP-critical) --}}
+
+
+ {{-- CSS critico (bloqueante, requerido para el layout/navbar) --}}
+
+ {{-- Tipografía: Antonio (display) + DM Sans (body) — cargadas en kinetic-arena.css --}}
+
+
+
+
+ {{-- CSS no critico: cargar async via preload-swap (no bloquea el primer paint) --}}
+
+
+
+
+
+
+
+ @yield('styles')
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ @yield('content')
+
+
+
+
+
+
+
+
+
+
Instalá OnAPB en tu celular
+
Accedé rápido a partidos, tu QR y notificaciones
+
+
+
+
+ Instalar
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Jugador / Aficionado
+
+
+ Admin
+
+
+
+
+
+
+
+
+
+
+
+
+ @yield('scripts')
+
+ {{-- PWA: Registro del Service Worker y banner de instalación --}}
+
+
+ {{-- Kinetic FX: capa de innovación visual (reveal, magnetic, ripple, parallax, cursor, contadores) --}}
+
+ @include('components.genius-chat')
+
+
+
diff --git a/resources/views/noticias/index.blade.php b/resources/views/noticias/index.blade.php
new file mode 100644
index 0000000..dd4996f
--- /dev/null
+++ b/resources/views/noticias/index.blade.php
@@ -0,0 +1,107 @@
+@extends('layouts.app')
+
+@section('title', 'Noticias - OnAPB Media Hub')
+
+@section('content')
+
+
+
+
Comunidad & Actualidad
+
Noticias.
+
El pulso del básquet entrerriano. Crónicas, resultados y las efemérides que marcan nuestra historia.
+
+
+ @if($noticias->isEmpty())
+
+
+
Silencio en la cancha
+
No hay noticias publicadas por el momento. Volvé pronto.
+
+ @else
+ @php $featured = $noticias->first(); $rest = $noticias->skip(1); @endphp
+
+
+
+
+
+
+ @if($featured->imagen)
+
+ @else
+
+
+
+ @endif
+
+
+
+ @if($featured->categoria)
+ {{ $featured->categoria }}
+ @else
+ Destacado
+ @endif
+ {{ $featured->fecha->translatedFormat('d M Y') }}
+
+
+
+ {{ Str::limit(strip_tags($featured->contenido), 200) }}
+
+
LEER CRÓNICA COMPLETA
+
+
+
+
+
+
+
+ @foreach($rest as $noticia)
+
+
+ @if($noticia->imagen)
+
+
+
+ @else
+
+
+
+ @endif
+
+
+ {{ $noticia->categoria ?? 'Actualidad' }}
+ {{ $noticia->fecha->translatedFormat('d/m/Y') }}
+
+
+
+ {{ Str::limit(strip_tags($noticia->contenido), 120) }}
+
+
+ Continuar leyendo
+
+
+
+
+ @endforeach
+
+ @endif
+
+ @if(session('admin_logged_in') && session('admin_role') == 1)
+
+
+
+
+
Añadí nueva información al Media Hub de la OnAPB.
+
+
➕ NUEVA NOTICIA
+
+
+ @endif
+
+
+
+
+@endsection
diff --git a/resources/views/noticias/show.blade.php b/resources/views/noticias/show.blade.php
new file mode 100644
index 0000000..b09865a
--- /dev/null
+++ b/resources/views/noticias/show.blade.php
@@ -0,0 +1,103 @@
+@extends('layouts.app')
+
+@section('title', $noticia->titulo . ' - OnAPB Media Hub')
+
+@section('content')
+
+
+
+ @if($noticia->imagen)
+
+ @endif
+
+
+
+
+ @if($noticia->categoria)
+
+ {{ $noticia->categoria }}
+
+ @else
+
+ Comunicado
+
+ @endif
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {!! nl2br(e($noticia->contenido)) !!}
+
+
+
+
+
+
+
+
+
+
Sumate a la comunidad OnAPB y compartí tus comentarios sobre esta cobertura en nuestras redes sociales oficiales.
+
+
+
+
+
+
+
+
+
+
+
+@endsection
diff --git a/resources/views/notificaciones/index.blade.php b/resources/views/notificaciones/index.blade.php
new file mode 100644
index 0000000..7c5d4f8
--- /dev/null
+++ b/resources/views/notificaciones/index.blade.php
@@ -0,0 +1,197 @@
+@extends('layouts.app')
+
+@section('title', 'Mis Notificaciones — OnAPB')
+
+@section('content')
+
+
+
+
+ Mis Notificaciones
+ @if($totalNoLeidas > 0)
+ {{ $totalNoLeidas }} nuevas
+ @endif
+
+
+
+ @if($totalNoLeidas > 0)
+
+ MARCAR LEÍDAS
+
+ @endif
+ @if(!$notificaciones->isEmpty())
+
+ BORRAR TODAS
+
+ @endif
+
+
+
+ @if($notificaciones->isEmpty())
+
+
+
No tenés notificaciones todavía.
+
Ir a mi panel
+
+ @else
+
+ @foreach($notificaciones as $notif)
+
+ {{-- Ícono según tipo --}}
+
+ @php
+ $iconos = [
+ 'partido' => ['class' => 'bi-calendar-event', 'color' => 'text-primary'],
+ 'resultado' => ['class' => 'bi-trophy-fill', 'color' => 'text-warning'],
+ 'sistema' => ['class' => 'bi-info-circle-fill','color' => 'text-secondary'],
+ 'seguimiento' => ['class' => 'bi-star-fill', 'color' => 'text-success'],
+ ];
+ $icono = $iconos[$notif->tipo] ?? ['class' => 'bi-bell-fill', 'color' => 'text-muted'];
+ @endphp
+
+
+
+ {{-- Contenido --}}
+
+
+
{{ $notif->titulo }}
+ {{ $notif->creada_en->diffForHumans() }}
+
+
{{ $notif->mensaje }}
+
+ @if($notif->url_accion)
+
+ Ver detalle
+
+ @endif
+ @if(!$notif->leida)
+
+ Marcar leída
+
+ @endif
+
+
+
+
+
+
+ @endforeach
+
+
+ {{-- Paginación --}}
+
+ {{ $notificaciones->links() }}
+
+ @endif
+
+@endsection
+
+@section('scripts')
+
+@endsection
diff --git a/resources/views/offline.blade.php b/resources/views/offline.blade.php
new file mode 100644
index 0000000..5db0c2d
--- /dev/null
+++ b/resources/views/offline.blade.php
@@ -0,0 +1,27 @@
+@extends('layouts.app')
+
+@section('title', 'Sin conexión — OnAPB')
+
+@section('content')
+
+
+
🏀
+
Sin conexión
+
+ Parece que no tenés internet en este momento.
+ Algunas páginas pueden estar disponibles en caché.
+
+
+
+ Reintentar
+
+
+ Inicio
+
+
+
+ Si venías a ver resultados o tu QR, probá volviendo cuando tengas conexión.
+
+
+
+@endsection
diff --git a/resources/views/panel/index.blade.php b/resources/views/panel/index.blade.php
new file mode 100644
index 0000000..de66fee
--- /dev/null
+++ b/resources/views/panel/index.blade.php
@@ -0,0 +1,323 @@
+@extends('layouts.app')
+
+@section('title', 'Mi Panel - OnAPB')
+
+@section('content')
+
+
+
+
+
+ Mi Perfil
+
{{ $user->nombre }}.
+
+
+ {{ $userTipo }}
+
+
+
+ @if(session('panel_msg'))
+
+
{{ session('panel_msg') }}
+
+ @endif
+
+
+
+
+
+
Datos Personales
+
+ @csrf
+
+
Nombre Completo
+
{{ $user->nombre }} {{ $user->apellido }}
+
+
+
DNI / Documento
+
{{ $userTipo === 'jugador' ? $user->documento : $user->dni }}
+
+ @if($userTipo === 'jugador')
+
+
Categoría
+
{{ $user->categoria_calculada }}
+
+ @endif
+
+
+ Email
+
+
+
+ Teléfono
+
+
+ ACTUALIZAR DATOS
+
+
+
+
+
+
+
+
+ @if($userTipo === 'jugador')
+
+
Mi Club
+
+
+ @if($user->clubActual && $user->clubActual->imagen)
+
+ @else
+
+
+
+ @endif
+
+
+
{{ $user->clubActual->nombre ?? 'Sin Club Asignado' }}
+ @if($user->equipos && $user->equipos->count() > 0)
+
{{ $user->equipos->count() }} equipos registrados
+ @endif
+
+
+
+ @endif
+
+
+
+
+
Mis Entradas (QRs)
+
VER TODAS
+
+
+ @if($qrCodes->isEmpty())
+
+
No tenés entradas activas.
+
BUSCAR EVENTOS
+
+ @else
+
+ @foreach($qrCodes->take(4) as $qr)
+
+
+
+
{{ $qr->evento ? $qr->evento->nombre_evento : 'Evento' }}
+
+ {{ $qr->escaneos_restantes > 0 ? 'Disponible' : 'Usado' }}
+
+
+
VER QR
+
+
+ @endforeach
+
+ @endif
+
+
+
+
+
+
Mis Beneficios
+
BUSCAR MÁS
+
+
+ @if($promoQrs->isEmpty())
+
+
No reclamaste beneficios aún.
+
+ @else
+
+
+
+
+ Promoción
+ Estado
+ Acciones
+
+
+
+ @foreach($promoQrs->take(5) as $pq)
+
+
+ {{ $pq->promocion ? $pq->promocion->nombre : 'Beneficio' }}
+ {{ $pq->promocion->direccion ?? '' }}
+
+
+
+ {{ $pq->usado ? 'Usado' : 'Disponible' }}
+
+
+
+ @if(!$pq->usado)
+ Ver QR
+ @else
+ —
+ @endif
+
+
+ @endforeach
+
+
+
+ @endif
+
+
+
+
+ {{-- ═══════════════════════════════════════════ --}}
+ {{-- SECCIÓN: MIS EQUIPOS SEGUIDOS --}}
+ {{-- ═══════════════════════════════════════════ --}}
+
+
+
+ Equipos Seguidos
+
+
+ Ver todos los partidos
+
+
+
+
+
+ {{-- Si es jugador, mostrar sus equipos propios --}}
+ @if($userTipo === 'jugador' && $user->equipos && $user->equipos->count() > 0)
+
+
Mis Equipos (asignados)
+
+ @foreach($user->equipos as $eq)
+
+
+
+
+
+
+
{{ $eq->club->nombre ?? '?' }}
+
{{ $eq->categoria }} {{ $eq->division }}
+
+
Ver
+
+
+ @endforeach
+
+
+ @endif
+
+ {{-- Buscar más equipos para seguir --}}
+
+
¿Querés seguir más equipos?
+
+ Ver torneos y equipos
+
+
+
+
+
+@endsection
+
+@section('scripts')
+
+@endsection
+
diff --git a/resources/views/panel/mis_qrs.blade.php b/resources/views/panel/mis_qrs.blade.php
new file mode 100644
index 0000000..627566f
--- /dev/null
+++ b/resources/views/panel/mis_qrs.blade.php
@@ -0,0 +1,137 @@
+@extends('layouts.app')
+
+@section('title', 'Mis QRs - OnAPB')
+
+@section('content')
+
+
+
+
Mi Panel
+
Mis QRs.
+ @if($evento)
{{ $evento->nombre_evento }}
@endif
+
+
+ Volver
+
+
+
+
+ @if($evento)
+
+
{{ $evento->nombre_evento }}
+
+ {{ $evento->fecha_evento ? \Carbon\Carbon::parse($evento->fecha_evento)->format('d/m/Y') : '—' }}
+ ·
+ {{ $evento->hora_inicio ? substr($evento->hora_inicio, 0, 5) : '' }} - {{ $evento->hora_fin ? substr($evento->hora_fin, 0, 5) : '' }}
+ @if($evento->sede)
+ · {{ $evento->sede }}
+ @endif
+
+
+ @endif
+
+ @if($qrs->isEmpty())
+
+
+
No tenés QRs{{ $evento ? ' para este evento' : '' }}.
+
Ver eventos disponibles
+
+ @else
+
+ @foreach($qrs as $qr)
+ @php
+ $agotado = (int)$qr->escaneos_restantes <= 0;
+ $club = ($qr->evento && $qr->evento->equipoLocal && $qr->evento->equipoLocal->club) ? $qr->evento->equipoLocal->club : null;
+ $bgPath = ($club && $club->qr_background) ? asset($club->qr_background) : null;
+ $textColor = ($club && $club->qr_color_texto) ? $club->qr_color_texto : '#333';
+ @endphp
+
+
+
+ {{-- Overlay semi-transparente si hay fondo para legibilidad --}}
+ @if($bgPath)
+
+ @endif
+
+
+
+ {{-- Logo Cabecera --}}
+
+
+ @if($userTipo === 'jugador' && $user->clubActual && $user->clubActual->imagen)
+
+
+
+ @endif
+
+
+ {{-- Datos Jugador / Evento --}}
+
+
+ {{ $user->nombre }} {{ $user->apellido }}
+
+
{{ $qr->evento->nombre_evento ?? 'Partido - OnAPB' }}
+ @if($qr->evento && $qr->evento->equipoLocal)
+
+ CATEGORIA: {{ $qr->evento->grupo_nombre ?? ($qr->evento->equipoLocal->categoria . ($qr->evento->equipoLocal->division ? ' ' . $qr->evento->equipoLocal->division : '')) }}
+
+ @endif
+ @if($qr->tipo_qr === 'libre_50')
+
+ 50% DESCUENTO
+
+ @endif
+
+
+ {{-- QR visual --}}
+
+ @if($agotado)
+
+ 🚫
+
+ @endif
+
+
+
+ {{-- Footer Ticket --}}
+
+ @if($agotado)
+
❌ QR YA UTILIZADO
+ @else
+
✅ QR VÁLIDO
+
Escaneos: {{ $qr->escaneos_restantes }} de 1
+ @endif
+ @if($qr->evento && $qr->evento->equipoLocal)
+
+ CATEGORIA: {{ $qr->evento->grupo_nombre ?? ($qr->evento->equipoLocal->categoria . ($qr->evento->equipoLocal->division ? ' ' . $qr->evento->equipoLocal->division : '')) }}
+
+ @endif
+
{{ $qr->id_qr }}
+
+ @if(!$agotado)
+
+ @endif
+
+
+
+
+
+ @endforeach
+
+
+
+
+ Estos QRs ya están registrados en el sistema. Mostralos en la entrada para ingresar al partido.
+
+ @endif
+
+@endsection
diff --git a/resources/views/panel/promo_qr.blade.php b/resources/views/panel/promo_qr.blade.php
new file mode 100644
index 0000000..fc3e943
--- /dev/null
+++ b/resources/views/panel/promo_qr.blade.php
@@ -0,0 +1,83 @@
+@extends('layouts.app')
+
+@section('title', 'QR de Beneficio - OnAPB')
+
+@section('content')
+
+
+
🎟️ QR de beneficio
+
+ @if(session('panel_msg'))
+
+ {{ session('panel_msg') }}
+
+
+ @endif
+
+ @php
+ $club = ($userTipo === 'jugador' && $user->clubActual) ? $user->clubActual : null;
+ $bgPath = ($club && $club->qr_background) ? asset($club->qr_background) : null;
+ $textColor = ($club && $club->qr_color_texto) ? $club->qr_color_texto : '#333';
+ @endphp
+
+
+
+ @if($bgPath)
+
+ @endif
+
+
+
+
+
+ @if($userTipo === 'jugador' && $user->clubActual && $user->clubActual->imagen)
+
+
+
+ @endif
+
+
CÓDIGO DE BENEFICIO
+
+
+
+
+
+
+
{{ $user->nombre }} {{ $user->apellido }}
+
Válido en: {{ $promoQr->promocion->nombre ?? 'Comercio adherido' }}
+
+
+ ⚠️ IMPORTANTE: Presentalo únicamente en el local. Si se escanea por error, se pierde.
+
+
{{ $promoQr->id_qr }}
+
+
+
+
+ @if($promoQr->promocion)
+
+
+
{{ $promoQr->promocion->nombre }}
+ @if($promoQr->promocion->descripcion)
+
Beneficio: {{ $promoQr->promocion->descripcion }}
+ @endif
+ @if($promoQr->promocion->direccion)
+
{{ $promoQr->promocion->direccion }}
+ @endif
+
+
+ @endif
+
+
+
+
+@endsection
diff --git a/resources/views/pdf/qr_ticket.blade.php b/resources/views/pdf/qr_ticket.blade.php
new file mode 100644
index 0000000..8faaf01
--- /dev/null
+++ b/resources/views/pdf/qr_ticket.blade.php
@@ -0,0 +1,145 @@
+
+
+
+
+
+
+
+
+ @if($backgroundBase64)
+
+ @endif
+
+
+
+
+
+
+
+ @if($qrImageBase64)
+
+ @else
+
Error QR
+ @endif
+
+
+
+ @if($qr->tipo_qr === 'libre_50')
+
50% DESCUENTO - CAT. LIBRE
+ @endif
+
+
{{ $user->nombre }} {{ $user->apellido }}
+
+
+
+ {{ $qr->evento->nombre_evento ?? 'EVENTO ONAPB' }}
+
+ FECHA: {{ $qr->evento->fecha_evento ? $qr->evento->fecha_evento->format('d/m/Y') : '—' }}
+ HORA: {{ $qr->evento->hora_inicio ? $qr->evento->hora_inicio->format('H:i') : '—' }} - {{ $qr->evento->hora_fin ? $qr->evento->hora_fin->format('H:i') : '—' }}
+ @if($qr->evento->sede)SEDE: {{ $qr->evento->sede }}
@endif
+ @if($qr->evento && $qr->evento->equipoLocal)
+ CATEGORÍA: {{ $qr->evento->equipoLocal->categoria }} {{ $qr->evento->equipoLocal->division }}
+ @endif
+
+
+
+
+
+
+
+
+
+
diff --git a/resources/views/promos/index.blade.php b/resources/views/promos/index.blade.php
new file mode 100644
index 0000000..bf9d1df
--- /dev/null
+++ b/resources/views/promos/index.blade.php
@@ -0,0 +1,275 @@
+@extends('layouts.app')
+
+@section('title', 'Lugares - OnAPB')
+
+@section('styles')
+
+@endsection
+
+@section('content')
+
+
+
+
Comunidad
+
Lugares de Interés
+
+
+
+
+
+
+
+ Búsqueda
+
+
+
+ Categoría
+
+ Todas
+ @foreach($categorias as $cat)
+ {{ ucfirst($cat) }}
+ @endforeach
+
+
+
+ FILTRAR
+
+
+
+
+
+
+
+
+
+
+ @if(session('admin_logged_in'))
+
+ @endif
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+@endsection
diff --git a/resources/views/torneos/playoffs.blade.php b/resources/views/torneos/playoffs.blade.php
new file mode 100644
index 0000000..274da38
--- /dev/null
+++ b/resources/views/torneos/playoffs.blade.php
@@ -0,0 +1,207 @@
+@extends('layouts.app')
+
+@section('title', 'Playoffs - ' . $torneo->nombre)
+
+@section('content')
+
+
+
+
+
+ Media Hub
+ {{ $torneo->nombre }}
+
+
+
Fase Eliminatoria
+
Brackets de Playoffs.
+
{{ $torneo->nombre }}
+
+
+
+
+ @if(count($grupos) > 0)
+
+ @endif
+
+
+ @if($bracket['cuartos']->isEmpty() && $bracket['semis']->isEmpty() && $bracket['final']->isEmpty())
+
+
+
Aún no hay llaves generadas
+
Los playoffs se habilitarán al finalizar la fase regular.
+
+ @else
+
+
+
+
+
+
Cuartos de Final
+ @forelse($bracket['cuartos'] as $nro => $serie)
+
+
+ Serie
+ {{ $serie['wins_local'] }} - {{ $serie['wins_visitante'] }}
+
+
+
+ @if($serie['equipo_local'])
+
+
{{ $serie['equipo_local']->club->nombre }}
+ @else
+
Por definir
+ @endif
+
+
{{ $serie['wins_local'] }}
+
+
+
+ @if($serie['equipo_visitante'])
+
+
{{ $serie['equipo_visitante']->club->nombre }}
+ @else
+
Por definir
+ @endif
+
+
{{ $serie['wins_visitante'] }}
+
+
+ @empty
+
Pendiente
+ @endforelse
+
+
+
+
+
+
+
Semifinales
+ @for($i = 1; $i <= 2; $i++)
+ @php $serie = $bracket['semis']->get($i); @endphp
+
+ @if($serie)
+
+ Serie
+ {{ $serie['wins_local'] }} - {{ $serie['wins_visitante'] }}
+
+
+
+ @if($serie['equipo_local'])
+
+
{{ $serie['equipo_local']->club->nombre }}
+ @else
+
TBD
+ @endif
+
+
{{ $serie['wins_local'] }}
+
+
+
+ @if($serie['equipo_visitante'])
+
+
{{ $serie['equipo_visitante']->club->nombre }}
+ @else
+
TBD
+ @endif
+
+
{{ $serie['wins_visitante'] }}
+
+ @else
+
TBD
+ @endif
+
+ @endfor
+
+
+
+
+
+
+
Gran Final
+ @php $serie = $bracket['final']->get(1); @endphp
+
+ @if($serie)
+
+ Serie: {{ $serie['wins_local'] }} - {{ $serie['wins_visitante'] }}
+
+
+
+ @if($serie['equipo_local'])
+
+
{{ $serie['equipo_local']->club->nombre }}
+ @else
+
TBD
+ @endif
+
+
{{ $serie['wins_local'] }}
+
+
+
+ @if($serie['equipo_visitante'])
+
+
{{ $serie['equipo_visitante']->club->nombre }}
+ @else
+
TBD
+ @endif
+
+
{{ $serie['wins_visitante'] }}
+
+ @else
+
Por definir
+ @endif
+
+
+
+
+
+ @endif
+
+
+
+
+@endsection
diff --git a/resources/views/torneos/scorers.blade.php b/resources/views/torneos/scorers.blade.php
new file mode 100644
index 0000000..f724717
--- /dev/null
+++ b/resources/views/torneos/scorers.blade.php
@@ -0,0 +1,116 @@
+@extends('layouts.app')
+
+@section('title', 'Goleadores - ' . $torneo->nombre)
+
+@section('content')
+
+
+
+
Estadísticas Individuales
+
TABLA DE GOLEADORES
+
{{ $torneo->nombre }}
+
+
+
+
+ @if(count($grupos) > 0)
+
+
+ Todos los Grupos
+
+ @foreach($grupos as $g)
+
+ {{ $g }}
+
+ @endforeach
+
+ @endif
+
+
+
+
+
+
+
+
+
+
+ #
+ Jugador
+ Club
+ PJ
+ PTS
+ PROM
+
+
+
+ @forelse($scorers as $index => $s)
+
+
+ @if($index == 0) 🥇
+ @elseif($index == 1) 🥈
+ @elseif($index == 2) 🥉
+ @else #{{ $index + 1 }}
+ @endif
+
+
+ {{ $s->jugador->apellido }}, {{ $s->jugador->nombre }}
+
+
+ {{ $s->jugador->clubActual->nombre ?? 'N/A' }}
+
+ {{ $s->partidos_jugados }}
+
+ {{ $s->total_puntos }}
+
+
+ {{ number_format($s->total_puntos / max(1, $s->partidos_jugados), 1) }}
+
+
+ @empty
+
+
+ No hay estadísticas registradas para este torneo todavía.
+
+
+ @endforelse
+
+
+
+
+
+
+
+ Actualizado el {{ date('d/m/Y H:i') }}
+
+
+
+
+
+
+
+@endsection
diff --git a/resources/views/torneos/standings.blade.php b/resources/views/torneos/standings.blade.php
new file mode 100644
index 0000000..30330b6
--- /dev/null
+++ b/resources/views/torneos/standings.blade.php
@@ -0,0 +1,166 @@
+@extends('layouts.app')
+
+@section('title', 'Tabla de Posiciones - ' . $torneo->nombre)
+
+@section('content')
+
+
+
+
+
+ Media Hub
+ {{ $torneo->nombre }}
+
+
+
Competición Oficial
+
Tabla de Posiciones.
+
{{ $torneo->nombre }} ({{ $torneo->fecha_inicio->format('Y') }})
+
+
+
+
+ @if(count($grupos) > 0)
+
+ @endif
+
+
+
+
+ @foreach($stats as $groupName => $teams)
+
+
+ {{ $groupName }}
+
+
+
+
+ #
+ Equipo
+ PJ
+ PG
+ PP
+ TF
+ TC
+ DIF
+ PTS
+
+
+
+ @foreach($teams as $index => $s)
+
+ {{ $index + 1 }}
+
+
+ @if(session('user_logged_in'))
+ @php $isFollowing = in_array($s['id'], $followedTeamIds); @endphp
+
+
+
+ @endif
+
+
+
+
+ {{-- Only show base category if different from group name --}}
+ @if($s['categoria'] != $groupName)
+
{{ $s['categoria'] }}
+ @endif
+
+
+ {{ $s['pj'] }}
+ {{ $s['pg'] }}
+ {{ $s['pp'] }}
+ {{ $s['tf'] }}
+ {{ $s['tc'] }}
+
+ {{ ($s['tf'] - $s['tc']) > 0 ? '+' : '' }}{{ $s['tf'] - $s['tc'] }}
+
+
+ {{ $s['pts'] }}
+
+
+ @endforeach
+
+
+
+ @endforeach
+
+ @if(empty($stats))
+
+
+
Aún no se han registrado resultados en este torneo.
+
+ @endif
+
+
+
+
Sistema de Puntuación
+
+
+
+
+
+ 0 PTS
+ W.O. / Incomparecencia
+
+
+
+
+
+
+
+
+@endsection
diff --git a/resources/views/welcome.blade.php b/resources/views/welcome.blade.php
new file mode 100644
index 0000000..31efebe
--- /dev/null
+++ b/resources/views/welcome.blade.php
@@ -0,0 +1,307 @@
+@extends('layouts.app')
+
+@section('title', 'OnAPB - Inicio')
+
+@section('styles')
+
+@endsection
+
+@section('content')
+
+
+
+
+ @foreach($carouselItems as $index => $item)
+
+
+
+
+
ONAPB Exclusivo · En vivo
+
{{ $item->titulo }}
+
{{ $item->subtitulo }}
+ @if($item->boton_texto && $item->boton_enlace)
+
{{ $item->boton_texto }} →
+ @endif
+
+
+
+
+
+
+
+ @endforeach
+
+
+
+
+
+
+
+
+
+
+
+ Últimas Noticias
+
Cobertura Exclusiva.
+
+
VER TODO
+
+
+ @foreach($noticias as $n)
+
+
+
+
+
+
+
+
+
{{ $n->categoria ?? 'Media' }}
+
+
{{ Str::limit(strip_tags($n->contenido), 120) }}
+
+
+
+ @endforeach
+ @if($noticias->isEmpty())
+
No hay noticias recientes.
+ @endif
+
+
+
+
+
+
+
Tablas Live
+
+
+
+
+
+ @php $slideIdx = 0; @endphp
+ @foreach($standingsData as $torneoId => $grupos)
+ @foreach($grupos as $nombreGrupo => $equipos)
+
+ @php $slideIdx++; @endphp
+ @endforeach
+ @endforeach
+
+
+
+ @php $isFirst = true; $totalSlides = 0; @endphp
+ @foreach($standingsData as $torneoId => $grupos)
+ @php $torneoObj = $torneos->firstWhere('id', $torneoId); @endphp
+ @foreach($grupos as $nombreGrupo => $equipos)
+ @php $totalSlides++; @endphp
+
+
+
+
+ {{ $torneoObj->nombre }}
+
{{ $nombreGrupo }}
+
+
+
+
+
+
+
+
+
+
+
+ #
+ EQUIPO
+ PJ
+ PTS
+
+
+
+ @foreach(array_slice($equipos, 0, 8) as $index => $e)
+
+ {{ $index + 1 }}
+
+
+
+ {{ $e['pj'] }}
+ {{ $e['pts'] }}
+
+ @endforeach
+
+
+
+
+
+
+ @php $isFirst = false; @endphp
+ @endforeach
+ @endforeach
+
+ @if($totalSlides === 0)
+
+
+
No hay posiciones registradas para este torneo.
+
+ @endif
+
+
+ @if($totalSlides > 1)
+
+
+
+
+
+
+
+
+ @endif
+
+
+
+
CENTRO DE ESTADÍSTICAS
+
Datos actualizados en tiempo real según los últimos informes arbitrales.
+
+
+
+
+
+
+
+
+
+
+
Agenda
+
Próximos Partidos
+
+
+
VER CALENDARIO COMPLETO
+
+
+ @if(count($eventos) === 0)
+
+
No hay eventos activos.
+
+ @else
+
+ @php
+ $eventosList = is_array($eventos) ? $eventos : $eventos->toArray();
+ @endphp
+ @foreach(array_slice($eventosList, 0, 6) as $e)
+
+
+
+
+ @if($e['estado'] === 'Activo')
+ En Vivo
+ @else
+ {{ $e['estado'] }}
+ @endif
+ {{ \Carbon\Carbon::parse($e['fecha_evento'])->translatedFormat('d M') }}
+
+
{{ $e['nombre_evento'] ?? ($e['clubLocal']['nombre'] . ' vs ' . $e['clubVisitante']['nombre']) }}
+
{{ $e['sede'] ?? 'TBD' }}
+
+
VER FICHA TÉCNICA
+
+
+ @endforeach
+
+ @endif
+
+
+
+
+
+
+ Beneficios para Socios
+
Beneficios Premium
+
+ @if($promociones->isEmpty())
+
+
Sin promociones activas.
+
+ @else
+
+ @foreach($promociones->take(3) as $p)
+
+ @endforeach
+
+ @endif
+
+
+
+
+
+
+@endsection