Fix búsqueda en tiempo real, paginación, OneSignal, bancos/categorías y vistas auth

- ajaxcrud.js: fix race condition en búsqueda, abort de requests en vuelo
- Layout: mover @yield('js') después de app.js para corregir orden de carga
- Paginación: useBootstrapFour() + eliminar wrappers <ul> duplicados en 17 vistas
- OneSignal: migrar de UserTag iChamba_ID a ExternalId en controladores
- API: agregar endpoint GET /api/banks y campos rfc/bank/bank_account/fee en hero()
- Seeders: BanksSeeder (239 bancos) y CategoriesSeeder (100 categorías)
- Auth views: corregir padding/scroll en register, login, password reset

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-16 21:21:44 -06:00
parent fb5caeab6e
commit b34622b289
71 changed files with 3303 additions and 1576 deletions

View File

@@ -7,10 +7,7 @@
<!-- CSRF Token -->
<meta name="csrf-token" content="{{ csrf_token() }}">
<title>{{ config('app.name', 'iChamba') }}</title>
<!-- Scripts -->
<script src="{{ asset('js/app.js') }}"></script>
<title>{{ config('app.name', 'JobHero') }}</title>
<!-- Fonts -->
<link rel="dns-prefetch" href="//fonts.gstatic.com">
@@ -22,69 +19,136 @@
<link href="{{ asset('css/bootstrap-tagsinput.css') }}" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
@stack('styles')
<style>
html, body {
height: 100%;
overflow: hidden;
}
.navbar-fixed {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 1030;
height: 56px;
}
.app-body {
position: fixed;
top: 56px;
left: 0;
right: 0;
bottom: 0;
display: flex;
}
.sidebar-wrapper {
background-color: #1e3a5f;
flex-shrink: 0;
overflow-y: auto;
height: 100%;
}
.sidebar-nav {
display: flex;
flex-direction: column;
padding: 0.5rem 0;
}
.sidebar-link {
color: rgba(255,255,255,0.75);
padding: 0.65rem 1.25rem;
text-decoration: none;
display: flex;
align-items: center;
gap: 10px;
transition: background 0.15s, color 0.15s;
font-size: 0.875rem;
white-space: nowrap;
}
.sidebar-link:hover {
background: rgba(255,255,255,0.08);
color: #fff;
text-decoration: none;
}
.sidebar-link.active {
background: rgba(255,255,255,0.15);
color: #fff;
border-left: 3px solid #5ba8ff;
padding-left: calc(1.25rem - 3px);
}
.sidebar-link i {
width: 18px;
text-align: center;
opacity: 0.85;
}
.main-content {
flex: 1;
min-width: 0;
overflow-y: auto;
height: 100%;
padding: 2rem 0.5rem 0.5rem 0.5rem;
}
.loading { display: none; }
</style>
</head>
<body>
<div id="app" style="height: 100%">
<nav class="navbar navbar-expand-md navbar-dark bg-primary shadow-sm">
<div class="container" style="padding-top: 0px">
<!--
<a class="navbar-brand" href="{{ url('/home') }}">
<img id='logo' src="{{asset('/img/ichamba.svg')}}">
</a>
-->
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="{{ __('Toggle navigation') }}">
<span class="navbar-toggler-icon"></span>
</button>
<nav class="navbar navbar-fixed navbar-expand-md navbar-dark bg-primary shadow-sm">
<div class="container-fluid">
<a class="navbar-brand" href="{{ url('/home') }}">
<img id='logo' src="{{ asset('/img/jobhero.svg') }}" style="height:32px;">
</a>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<!-- Left Side Of Navbar -->
<ul class="navbar-nav mr-auto">
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="{{ __('Toggle navigation') }}">
<span class="navbar-toggler-icon"></span>
</button>
</ul>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav mr-auto"></ul>
<!-- Right Side Of Navbar -->
<ul class="navbar-nav ml-auto">
<!-- Authentication Links -->
@guest
<li class="nav-item">
<a class="nav-link" href="{{ route('login') }}">{{ __('Iniciar sesión') }}</a>
</li>
@else
<li class="nav-item dropdown">
<a id="navbarDropdown" class="nav-link dropdown-toggle" href="#" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" v-pre style="padding-left:55px;">
<img src="{{ isset(Auth::user()->profile_photo) ? asset('img/users/' . Auth::user()->id . '/' . Auth::user()->profile_photo):asset('img/users/default.png') }}" style="width:48px; height:auto; position:absolute; top:-5px; left:-1px; border-radius:50%"/>
{{ Auth::user()->name }} <span class="caret"></span>
<ul class="navbar-nav ml-auto">
@guest
<li class="nav-item">
<a class="nav-link" href="{{ route('login') }}">{{ __('Iniciar sesión') }}</a>
</li>
@else
<li class="nav-item dropdown">
<a id="navbarDropdown" class="nav-link dropdown-toggle" href="#" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" v-pre style="padding-left:55px;">
<img src="{{ isset(Auth::user()->profile_photo) ? asset('img/users/' . Auth::user()->id . '/' . Auth::user()->profile_photo) : asset('img/users/default.png') }}" style="width:48px; height:auto; position:absolute; top:-5px; left:-1px; border-radius:50%"/>
{{ Auth::user()->name }} <span class="caret"></span>
</a>
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="navbarDropdown">
<a class="dropdown-item" href="{{ route('logout') }}"
onclick="event.preventDefault(); document.getElementById('logout-form').submit();">
{{ __('Cerrar sesión') }}
</a>
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="navbarDropdown">
<a class="dropdown-item" href="{{ route('logout') }}"
onclick="event.preventDefault();
document.getElementById('logout-form').submit();">
{{ __('Cerrar sesión') }}
</a>
<form id="logout-form" action="{{ route('logout') }}" method="POST" style="display: none;">
@csrf
</form>
</div>
</li>
@endguest
</ul>
</div>
<form id="logout-form" action="{{ route('logout') }}" method="POST" style="display: none;">
@csrf
</form>
</div>
</li>
@endguest
</ul>
</div>
</nav>
</div>
</nav>
<main class="py-4">
<div class="app-body">
@auth
@if(Auth::user()->role_id >= 5)
@include('sidebar')
@endif
@endauth
<main class="main-content">
@yield('content')
{!! GoogleReCaptchaV3::init() !!}
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.11.4/jquery-ui.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
<script src="https://twitter.github.io/typeahead.js/releases/latest/typeahead.bundle.js"></script>
<script src="{{ asset('js/bootstrap-tagsinput.min.js') }}"></script>
@yield('js')
{!! GoogleReCaptchaV3::init() !!}
</main>
</div>
@mapscripts
<script src="{{ asset('js/app.js') }}"></script>
<script src="https://code.jquery.com/ui/1.13.2/jquery-ui.min.js"></script>
<script src="https://twitter.github.io/typeahead.js/releases/latest/typeahead.bundle.js"></script>
<script src="{{ asset('js/bootstrap-tagsinput.min.js') }}"></script>
@yield('js')
</body>
</html>