Add empleado, borrado del seeder, cambios esteticos y middleware.
This commit is contained in:
@@ -0,0 +1,88 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Admin;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Hash;
|
||||||
|
use Illuminate\Validation\Rules;
|
||||||
|
|
||||||
|
class EmployeeController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Listar empleados
|
||||||
|
*/
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
$employees = User::where('role', 'employee')->orderBy('name')->get();
|
||||||
|
return view('admin.employees.index', compact('employees'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Crear un nuevo empleado
|
||||||
|
*/
|
||||||
|
public function store(Request $request)
|
||||||
|
{
|
||||||
|
$request->validate([
|
||||||
|
'name' => ['required', 'string', 'max:255'],
|
||||||
|
'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
|
||||||
|
'password' => ['required', 'string', 'min:8', 'confirmed'],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$user = new User();
|
||||||
|
$user->name = $request->name;
|
||||||
|
$user->email = $request->email;
|
||||||
|
$user->password = Hash::make($request->password);
|
||||||
|
$user->role = 'employee';
|
||||||
|
$user->save();
|
||||||
|
|
||||||
|
return redirect()->route('admin.employees.index')->with('success', 'Empleado creado correctamente.');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Eliminar un empleado
|
||||||
|
*/
|
||||||
|
public function destroy(User $user)
|
||||||
|
{
|
||||||
|
// Evitar que se elimine a sí mismo o a otro administrador (seguridad adicional)
|
||||||
|
if ($user->role !== 'employee') {
|
||||||
|
return redirect()->route('admin.employees.index')->with('error', 'Solo se pueden eliminar empleados.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($user->id === auth()->id()) {
|
||||||
|
return redirect()->route('admin.employees.index')->with('error', 'No puedes eliminar tu propia cuenta.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$user->delete();
|
||||||
|
|
||||||
|
return redirect()->route('admin.employees.index')->with('success', 'Empleado eliminado correctamente.');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Actualizar datos de un empleado
|
||||||
|
*/
|
||||||
|
public function update(Request $request, User $user)
|
||||||
|
{
|
||||||
|
if ($user->role !== 'employee') {
|
||||||
|
return redirect()->route('admin.employees.index')->with('error', 'Solo se pueden editar empleados.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$request->validate([
|
||||||
|
'name' => ['required', 'string', 'max:255'],
|
||||||
|
'email' => ['required', 'string', 'email', 'max:255', 'unique:users,email,' . $user->id],
|
||||||
|
'password' => ['nullable', 'string', 'min:8', 'confirmed'],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$user->name = $request->name;
|
||||||
|
$user->email = $request->email;
|
||||||
|
|
||||||
|
if ($request->filled('password')) {
|
||||||
|
$user->password = Hash::make($request->password);
|
||||||
|
}
|
||||||
|
|
||||||
|
$user->save();
|
||||||
|
|
||||||
|
return redirect()->route('admin.employees.index')->with('success', 'Empleado actualizado correctamente.');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,8 +19,14 @@ class AgendaController extends Controller
|
|||||||
'title' => $appointment->scheduled_at->format('H:i') . ' - ' . $appointment->client->name,
|
'title' => $appointment->scheduled_at->format('H:i') . ' - ' . $appointment->client->name,
|
||||||
'start' => $appointment->scheduled_at->format('Y-m-d\TH:i:s'),
|
'start' => $appointment->scheduled_at->format('Y-m-d\TH:i:s'),
|
||||||
'extendedProps' => [
|
'extendedProps' => [
|
||||||
'description' => $appointment->problem_description,
|
'client_name' => $appointment->client->name,
|
||||||
'status' => $appointment->status,
|
'client_phone' => $appointment->contact_phone,
|
||||||
|
'bike_model' => $appointment->bike_model,
|
||||||
|
'description' => $appointment->problem_description,
|
||||||
|
'parts_needed' => $appointment->parts_needed,
|
||||||
|
'estimated_cost'=> $appointment->estimated_cost,
|
||||||
|
'status' => $appointment->status,
|
||||||
|
'notes' => $appointment->notes,
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,13 @@ use App\Models\Client;
|
|||||||
|
|
||||||
class ClientController extends Controller
|
class ClientController extends Controller
|
||||||
{
|
{
|
||||||
|
private function checkAdmin()
|
||||||
|
{
|
||||||
|
if (auth()->check() && auth()->user()->role !== 'admin') {
|
||||||
|
abort(403, 'Solo los administradores pueden realizar esta acción.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Display a listing of the resource.
|
* Display a listing of the resource.
|
||||||
*/
|
*/
|
||||||
@@ -31,6 +38,7 @@ class ClientController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function create()
|
public function create()
|
||||||
{
|
{
|
||||||
|
$this->checkAdmin();
|
||||||
return view('clients.create');
|
return view('clients.create');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,6 +47,7 @@ class ClientController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function store(Request $request)
|
public function store(Request $request)
|
||||||
{
|
{
|
||||||
|
$this->checkAdmin();
|
||||||
$validated = $request->validate([
|
$validated = $request->validate([
|
||||||
'name' => ['required', 'string', 'max:255', 'not_regex:/[0-9]/'],
|
'name' => ['required', 'string', 'max:255', 'not_regex:/[0-9]/'],
|
||||||
'phone' => 'nullable|string|max:50',
|
'phone' => 'nullable|string|max:50',
|
||||||
@@ -76,19 +85,21 @@ class ClientController extends Controller
|
|||||||
/**
|
/**
|
||||||
* Display the specified resource.
|
* Display the specified resource.
|
||||||
*/
|
*/
|
||||||
public function show(string $id)
|
public function show(Client $client)
|
||||||
{
|
{
|
||||||
//
|
return view('clients.show', compact('client'));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function edit(Client $client)
|
public function edit(Client $client)
|
||||||
{
|
{
|
||||||
|
$this->checkAdmin();
|
||||||
// Reutilizamos la vista de create, o creamos una edit.blade.php similar
|
// Reutilizamos la vista de create, o creamos una edit.blade.php similar
|
||||||
return view('clients.edit', compact('client'));
|
return view('clients.edit', compact('client'));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function update(Request $request, Client $client)
|
public function update(Request $request, Client $client)
|
||||||
{
|
{
|
||||||
|
$this->checkAdmin();
|
||||||
$validated = $request->validate([
|
$validated = $request->validate([
|
||||||
'name' => ['required', 'string', 'max:255', 'not_regex:/[0-9]/'],
|
'name' => ['required', 'string', 'max:255', 'not_regex:/[0-9]/'],
|
||||||
'phone' => 'nullable|string|max:50',
|
'phone' => 'nullable|string|max:50',
|
||||||
@@ -109,6 +120,7 @@ class ClientController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function destroy(Client $client)
|
public function destroy(Client $client)
|
||||||
{
|
{
|
||||||
|
$this->checkAdmin();
|
||||||
try {
|
try {
|
||||||
$client->delete();
|
$client->delete();
|
||||||
return redirect()->route('clients.index')->with('success', 'Cliente eliminado correctamente.');
|
return redirect()->route('clients.index')->with('success', 'Cliente eliminado correctamente.');
|
||||||
|
|||||||
@@ -8,6 +8,13 @@ use App\Models\Supplier;
|
|||||||
|
|
||||||
class ExpenseController extends Controller
|
class ExpenseController extends Controller
|
||||||
{
|
{
|
||||||
|
private function checkAdmin()
|
||||||
|
{
|
||||||
|
if (auth()->check() && auth()->user()->role !== 'admin') {
|
||||||
|
abort(403, 'Solo los administradores pueden realizar esta acción.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function index(Request $request)
|
public function index(Request $request)
|
||||||
{
|
{
|
||||||
$query = $request->input('search');
|
$query = $request->input('search');
|
||||||
@@ -33,12 +40,14 @@ class ExpenseController extends Controller
|
|||||||
|
|
||||||
public function create()
|
public function create()
|
||||||
{
|
{
|
||||||
|
$this->checkAdmin();
|
||||||
$suppliers = Supplier::orderBy('name')->get();
|
$suppliers = Supplier::orderBy('name')->get();
|
||||||
return view('expenses.create', compact('suppliers'));
|
return view('expenses.create', compact('suppliers'));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function store(Request $request)
|
public function store(Request $request)
|
||||||
{
|
{
|
||||||
|
$this->checkAdmin();
|
||||||
$validated = $request->validate([
|
$validated = $request->validate([
|
||||||
'supplier_id' => 'nullable|exists:suppliers,id',
|
'supplier_id' => 'nullable|exists:suppliers,id',
|
||||||
'description' => 'required|string|max:255',
|
'description' => 'required|string|max:255',
|
||||||
@@ -66,12 +75,14 @@ class ExpenseController extends Controller
|
|||||||
|
|
||||||
public function edit(Expense $expense)
|
public function edit(Expense $expense)
|
||||||
{
|
{
|
||||||
|
$this->checkAdmin();
|
||||||
$suppliers = Supplier::orderBy('name')->get();
|
$suppliers = Supplier::orderBy('name')->get();
|
||||||
return view('expenses.edit', compact('expense', 'suppliers'));
|
return view('expenses.edit', compact('expense', 'suppliers'));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function update(Request $request, Expense $expense)
|
public function update(Request $request, Expense $expense)
|
||||||
{
|
{
|
||||||
|
$this->checkAdmin();
|
||||||
$validated = $request->validate([
|
$validated = $request->validate([
|
||||||
'supplier_id' => 'nullable|exists:suppliers,id',
|
'supplier_id' => 'nullable|exists:suppliers,id',
|
||||||
'description' => 'required|string|max:255',
|
'description' => 'required|string|max:255',
|
||||||
@@ -90,6 +101,7 @@ class ExpenseController extends Controller
|
|||||||
|
|
||||||
public function destroy(Expense $expense)
|
public function destroy(Expense $expense)
|
||||||
{
|
{
|
||||||
|
$this->checkAdmin();
|
||||||
$expense->delete();
|
$expense->delete();
|
||||||
return redirect()->route('expenses.index')->with('success', 'Gasto eliminado correctamente.');
|
return redirect()->route('expenses.index')->with('success', 'Gasto eliminado correctamente.');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,13 @@ use Illuminate\Support\Facades\Storage;
|
|||||||
|
|
||||||
class ProductosController extends Controller
|
class ProductosController extends Controller
|
||||||
{
|
{
|
||||||
|
private function checkAdmin()
|
||||||
|
{
|
||||||
|
if (auth()->check() && auth()->user()->role !== 'admin') {
|
||||||
|
abort(403, 'Solo los administradores pueden realizar esta acción.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*public function index(Request $request)
|
/*public function index(Request $request)
|
||||||
{
|
{
|
||||||
$query = $request->input('search');
|
$query = $request->input('search');
|
||||||
@@ -55,6 +62,7 @@ class ProductosController extends Controller
|
|||||||
|
|
||||||
public function create()
|
public function create()
|
||||||
{
|
{
|
||||||
|
$this->checkAdmin();
|
||||||
$suppliers = Supplier::orderBy('name')->get();
|
$suppliers = Supplier::orderBy('name')->get();
|
||||||
$tags = Tag::orderBy('name')->get();
|
$tags = Tag::orderBy('name')->get();
|
||||||
return view('productos.create', compact('suppliers', 'tags'));
|
return view('productos.create', compact('suppliers', 'tags'));
|
||||||
@@ -62,6 +70,7 @@ class ProductosController extends Controller
|
|||||||
|
|
||||||
public function store(Request $request)
|
public function store(Request $request)
|
||||||
{
|
{
|
||||||
|
$this->checkAdmin();
|
||||||
$validated = $request->validate([
|
$validated = $request->validate([
|
||||||
'name' => 'required|string|max:255',
|
'name' => 'required|string|max:255',
|
||||||
'price' => 'required|numeric|min:0',
|
'price' => 'required|numeric|min:0',
|
||||||
@@ -124,6 +133,7 @@ class ProductosController extends Controller
|
|||||||
|
|
||||||
public function edit(Product $product)
|
public function edit(Product $product)
|
||||||
{
|
{
|
||||||
|
$this->checkAdmin();
|
||||||
$suppliers = Supplier::orderBy('name')->get();
|
$suppliers = Supplier::orderBy('name')->get();
|
||||||
$tags = Tag::orderBy('name')->get();
|
$tags = Tag::orderBy('name')->get();
|
||||||
return view('productos.edit', compact('product', 'suppliers', 'tags'));
|
return view('productos.edit', compact('product', 'suppliers', 'tags'));
|
||||||
@@ -131,6 +141,7 @@ class ProductosController extends Controller
|
|||||||
|
|
||||||
public function update(Request $request, Product $product)
|
public function update(Request $request, Product $product)
|
||||||
{
|
{
|
||||||
|
$this->checkAdmin();
|
||||||
$validated = $request->validate([
|
$validated = $request->validate([
|
||||||
'name' => 'required|string|max:255',
|
'name' => 'required|string|max:255',
|
||||||
'type' => 'required|in:bike,accessory,clothing,spare,service,children,skate,rollers,other',
|
'type' => 'required|in:bike,accessory,clothing,spare,service,children,skate,rollers,other',
|
||||||
@@ -194,6 +205,7 @@ class ProductosController extends Controller
|
|||||||
|
|
||||||
public function destroy(Product $product)
|
public function destroy(Product $product)
|
||||||
{
|
{
|
||||||
|
$this->checkAdmin();
|
||||||
if ($product->image_path) {
|
if ($product->image_path) {
|
||||||
Storage::disk('public')->delete($product->image_path);
|
Storage::disk('public')->delete($product->image_path);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,13 @@ use Illuminate\Http\Request;
|
|||||||
use App\Models\Supplier;
|
use App\Models\Supplier;
|
||||||
class SupplierController extends Controller
|
class SupplierController extends Controller
|
||||||
{
|
{
|
||||||
|
private function checkAdmin()
|
||||||
|
{
|
||||||
|
if (auth()->check() && auth()->user()->role !== 'admin') {
|
||||||
|
abort(403, 'Solo los administradores pueden realizar esta acción.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* grilla de proveedores con buscador
|
* grilla de proveedores con buscador
|
||||||
*/
|
*/
|
||||||
@@ -27,12 +34,14 @@ class SupplierController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function create()
|
public function create()
|
||||||
{
|
{
|
||||||
|
$this->checkAdmin();
|
||||||
return view('suppliers.create');
|
return view('suppliers.create');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function store(Request $request)
|
public function store(Request $request)
|
||||||
{
|
{
|
||||||
|
$this->checkAdmin();
|
||||||
$validated = $request->validate([
|
$validated = $request->validate([
|
||||||
'name' => 'required|string|max:255',
|
'name' => 'required|string|max:255',
|
||||||
'phone' => 'nullable|string|max:50',
|
'phone' => 'nullable|string|max:50',
|
||||||
@@ -56,11 +65,13 @@ class SupplierController extends Controller
|
|||||||
|
|
||||||
public function edit(Supplier $supplier)
|
public function edit(Supplier $supplier)
|
||||||
{
|
{
|
||||||
|
$this->checkAdmin();
|
||||||
return view('suppliers.edit', compact('supplier'));
|
return view('suppliers.edit', compact('supplier'));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function update(Request $request, Supplier $supplier)
|
public function update(Request $request, Supplier $supplier)
|
||||||
{
|
{
|
||||||
|
$this->checkAdmin();
|
||||||
$validated = $request->validate([
|
$validated = $request->validate([
|
||||||
'name' => 'required|string|max:255',
|
'name' => 'required|string|max:255',
|
||||||
'phone' => 'nullable|string|max:50',
|
'phone' => 'nullable|string|max:50',
|
||||||
@@ -79,6 +90,7 @@ class SupplierController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function destroy(Supplier $supplier)
|
public function destroy(Supplier $supplier)
|
||||||
{
|
{
|
||||||
|
$this->checkAdmin();
|
||||||
try {
|
try {
|
||||||
$supplier->delete();
|
$supplier->delete();
|
||||||
return redirect()->route('suppliers.index')
|
return redirect()->route('suppliers.index')
|
||||||
|
|||||||
@@ -21,14 +21,5 @@ class DatabaseSeeder extends Seeder
|
|||||||
'password' => bcrypt('password'), // Cambiar en producción
|
'password' => bcrypt('password'), // Cambiar en producción
|
||||||
'role' => 'admin',
|
'role' => 'admin',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
//Crear un Empleado de prueba
|
|
||||||
User::factory()->create([
|
|
||||||
'name' => 'Empleado Test',
|
|
||||||
'email' => 'taller@lauck.com',
|
|
||||||
'password' => bcrypt('password'),
|
|
||||||
'role' => 'employee',
|
|
||||||
]);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+54
-36
@@ -45,43 +45,53 @@ document.addEventListener('DOMContentLoaded', function () {
|
|||||||
window.location.href = `/agenda/dia/${fecha}`
|
window.location.href = `/agenda/dia/${fecha}`
|
||||||
},
|
},
|
||||||
*/
|
*/
|
||||||
|
|
||||||
eventClick: function (info) {
|
eventClick: function (info) {
|
||||||
|
const evento = info.event;
|
||||||
|
const modal = document.getElementById("eventModal");
|
||||||
|
if (!modal) return;
|
||||||
|
|
||||||
const evento = info.event
|
modal.classList.remove("hidden");
|
||||||
|
document.body.style.overflow = "hidden";
|
||||||
|
|
||||||
const modal = document.getElementById("eventModal")
|
// Llenar campos dinámicos
|
||||||
if (!modal) return
|
document.getElementById("modalClientName").innerText = evento.extendedProps.client_name ?? 'Sin asignar';
|
||||||
|
document.getElementById("modalBikeModel").innerText = evento.extendedProps.bike_model ?? 'Sin modelo';
|
||||||
|
|
||||||
modal.classList.remove("hidden")
|
// Formatear Fecha y Hora
|
||||||
|
const fecha = evento.start;
|
||||||
const statusMap = {
|
const dateStr = fecha.toLocaleDateString("es-AR", {
|
||||||
pending: 'Pendiente',
|
weekday: 'long',
|
||||||
confirmed: 'Confirmado',
|
day: 'numeric',
|
||||||
in_progress: 'En progreso',
|
month: 'long',
|
||||||
ready: 'Listo',
|
year: 'numeric'
|
||||||
delivered: 'Entregado'
|
});
|
||||||
}
|
const timeStr = fecha.toLocaleTimeString("es-AR", {
|
||||||
|
hour: '2-digit',
|
||||||
const estado = statusMap[evento.extendedProps.status] ?? 'desconocido'
|
minute: '2-digit',
|
||||||
|
|
||||||
document.getElementById("modalTitle").innerText =
|
|
||||||
evento.extendedProps.description + " - " + estado
|
|
||||||
|
|
||||||
const fecha = evento.start
|
|
||||||
|
|
||||||
const hora = fecha.toLocaleTimeString("es-AR", {
|
|
||||||
hour: "2-digit",
|
|
||||||
minute: "2-digit",
|
|
||||||
hour12: false
|
hour12: false
|
||||||
})
|
});
|
||||||
|
const formattedDateTime = dateStr.charAt(0).toUpperCase() + dateStr.slice(1) + " a las " + timeStr;
|
||||||
|
document.getElementById("modalDateTime").innerText = formattedDateTime;
|
||||||
|
|
||||||
document.getElementById("modalDate").innerText =
|
const url = window.appointmentShowTemplate.replace(':id', evento.id);
|
||||||
"Hora: " + hora
|
document.getElementById("viewEventBtn").href = url;
|
||||||
|
|
||||||
const url = window.appointmentShowTemplate.replace(':id', evento.id)
|
// Mapear Badge de Estado y clases correspondientes (estilo pastel idéntico a pendiente)
|
||||||
|
const statusMap = {
|
||||||
|
pending: { label: 'Pendiente', classes: ['bg-red-100', 'text-red-800', 'border-red-200', 'dark:bg-red-900/30', 'dark:text-red-400', 'dark:border-red-800'] },
|
||||||
|
confirmed: { label: 'Confirmado', classes: ['bg-blue-100', 'text-blue-800', 'border-blue-200', 'dark:bg-blue-900/30', 'dark:text-blue-400', 'dark:border-blue-800'] },
|
||||||
|
in_progress: { label: 'En progreso', classes: ['bg-orange-100', 'text-orange-800', 'border-orange-200', 'dark:bg-orange-950/30', 'dark:text-orange-400', 'dark:border-orange-800'] },
|
||||||
|
ready: { label: 'Listo', classes: ['bg-green-100', 'text-green-800', 'border-green-200', 'dark:bg-green-900/30', 'dark:text-green-450', 'dark:border-green-800'] },
|
||||||
|
delivered: { label: 'Entregado', classes: ['bg-neutral-100', 'text-neutral-800', 'border-neutral-200', 'dark:bg-neutral-800', 'dark:text-neutral-400', 'dark:border-neutral-700'] }
|
||||||
|
};
|
||||||
|
const statusObj = statusMap[evento.extendedProps.status] || { label: 'Desconocido', classes: ['bg-neutral-100', 'text-neutral-800', 'border-neutral-200'] };
|
||||||
|
|
||||||
document.getElementById("viewEventBtn").href = url
|
const badge = document.getElementById("modalStatusBadge");
|
||||||
|
if (badge) {
|
||||||
|
badge.innerText = statusObj.label;
|
||||||
|
badge.className = "px-2.5 py-0.5 text-xs font-black rounded-full uppercase tracking-wider border";
|
||||||
|
statusObj.classes.forEach(c => badge.classList.add(c));
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
events: window.appointments ?? [],
|
events: window.appointments ?? [],
|
||||||
@@ -109,14 +119,22 @@ document.addEventListener('DOMContentLoaded', function () {
|
|||||||
|
|
||||||
calendar.render()
|
calendar.render()
|
||||||
|
|
||||||
const closeBtn = document.getElementById("closeModal")
|
// Manejo del cierre del modal con múltiples triggers (Cerrar, Botón X y Click afuera)
|
||||||
|
const closeModalElements = [
|
||||||
|
document.getElementById("closeModal"),
|
||||||
|
document.getElementById("closeModalCross"),
|
||||||
|
document.getElementById("eventModal")
|
||||||
|
]
|
||||||
|
|
||||||
if (closeBtn) {
|
closeModalElements.forEach(el => {
|
||||||
closeBtn.addEventListener("click", function () {
|
if (el) {
|
||||||
document.getElementById("eventModal").classList.add("hidden")
|
el.addEventListener("click", function (e) {
|
||||||
document.body.style.overflow = "auto"
|
if (el.id === "eventModal" && e.target !== el) return;
|
||||||
})
|
document.getElementById("eventModal").classList.add("hidden")
|
||||||
}
|
document.body.style.overflow = "auto"
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,323 @@
|
|||||||
|
<x-layout title="Empleados - Lauck">
|
||||||
|
<x-section-header subtitle="Personal" title="Administración de " highlight="Empleados" />
|
||||||
|
|
||||||
|
<div class="w-full max-w-5xl mx-auto space-y-6">
|
||||||
|
|
||||||
|
<!-- Formulario de Registro de Empleado -->
|
||||||
|
<div class="bg-gray-200 dark:bg-panel-bg border border-neutral-400 dark:border-neutral-800 rounded-xl p-6 shadow-lg">
|
||||||
|
<h3 class="text-lg font-bold text-gray-900 dark:text-white mb-4">Registrar Nuevo Empleado</h3>
|
||||||
|
<form action="{{ route('admin.employees.store') }}" method="POST" class="space-y-4">
|
||||||
|
@csrf
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||||
|
<!-- Nombre -->
|
||||||
|
<div>
|
||||||
|
<x-forms.label for="name" value="Nombre Completo" />
|
||||||
|
<x-forms.input id="name" name="name" type="text" required placeholder="Ej: Juan Pérez" :value="old('name')" :error="$errors->first('name')" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Correo -->
|
||||||
|
<div>
|
||||||
|
<x-forms.label for="email" value="Correo Electrónico" />
|
||||||
|
<x-forms.input id="email" name="email" type="email" required placeholder="empleado@lauck.com" :value="old('email')" :error="$errors->first('email')" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Botón Registrar (Desktop: abajo-derecha de la primera fila, o alineado. Pongámoslo al final) -->
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||||
|
<!-- Contraseña -->
|
||||||
|
<div>
|
||||||
|
<x-forms.label for="password" value="Contraseña (Mín. 8 caracteres)" />
|
||||||
|
<div class="relative">
|
||||||
|
<x-forms.input id="password" name="password" type="password" required placeholder="••••••••" :error="$errors->first('password')" class="pr-10" />
|
||||||
|
<button type="button" id="togglePassword" class="absolute right-3 top-[11px] text-neutral-500 hover:text-black dark:hover:text-white transition-colors">
|
||||||
|
{{-- Ojo abierto --}}
|
||||||
|
<svg id="iconShow" xmlns="http://www.w3.org/2000/svg" class="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.477 0 8.268 2.943 9.542 7-1.274 4.057-5.065 7-9.542 7-4.477 0-8.268-2.943-9.542-7z" />
|
||||||
|
</svg>
|
||||||
|
{{-- Ojo cerrado --}}
|
||||||
|
<svg id="iconHide" xmlns="http://www.w3.org/2000/svg" class="w-5 h-5 hidden" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13.875 18.825A10.05 10.05 0 0112 19c-4.477 0-8.268-2.943-9.542-7a9.956 9.956 0 012.293-3.95M6.938 6.938A9.956 9.956 0 0112 5c4.477 0 8.268 2.943 9.542 7a9.97 9.97 0 01-1.88 3.118M3 3l18 18" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Confirmar Contraseña -->
|
||||||
|
<div>
|
||||||
|
<x-forms.label for="password_confirmation" value="Confirmar Contraseña" />
|
||||||
|
<div class="relative">
|
||||||
|
<x-forms.input id="password_confirmation" name="password_confirmation" type="password" required placeholder="••••••••" class="pr-10" />
|
||||||
|
<button type="button" id="togglePasswordConf" class="absolute right-3 top-[11px] text-neutral-500 hover:text-black dark:hover:text-white transition-colors">
|
||||||
|
{{-- Ojo abierto --}}
|
||||||
|
<svg id="iconShowConf" xmlns="http://www.w3.org/2000/svg" class="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.477 0 8.268 2.943 9.542 7-1.274 4.057-5.065 7-9.542 7-4.477 0-8.268-2.943-9.542-7z" />
|
||||||
|
</svg>
|
||||||
|
{{-- Ojo cerrado --}}
|
||||||
|
<svg id="iconHideConf" xmlns="http://www.w3.org/2000/svg" class="w-5 h-5 hidden" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13.875 18.825A10.05 10.05 0 0112 19c-4.477 0-8.268-2.943-9.542-7a9.956 9.956 0 012.293-3.95M6.938 6.938A9.956 9.956 0 0112 5c4.477 0 8.268 2.943 9.542 7a9.97 9.97 0 01-1.88 3.118M3 3l18 18" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex justify-end pt-2">
|
||||||
|
<button type="submit" class="w-full md:w-auto px-6 py-2.5 bg-neutral-900 dark:bg-neon-lime text-neon-lime dark:text-neutral-900 font-bold rounded-lg hover:bg-neutral-800 hover:dark:bg-[#b3e600] transition-colors shadow-lg dark:shadow-neon-lime/20 uppercase text-xs tracking-wider">
|
||||||
|
Registrar Empleado
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Tabla de Empleados -->
|
||||||
|
<div class="bg-gray-200 dark:bg-panel-bg border border-neutral-400 dark:border-neutral-800 rounded-xl shadow-lg overflow-hidden">
|
||||||
|
<div class="overflow-x-auto">
|
||||||
|
<table class="w-full text-sm text-left text-neutral-900 dark:text-white">
|
||||||
|
<thead class="text-xs text-neutral-800 dark:text-gray-300 uppercase bg-gray-400 dark:bg-neutral-800 border-b border-gray-300 dark:border-neutral-700">
|
||||||
|
<tr>
|
||||||
|
<th scope="col" class="px-6 py-3">Nombre</th>
|
||||||
|
<th scope="col" class="px-6 py-3">Correo Electrónico</th>
|
||||||
|
<th scope="col" class="px-6 py-3">Fecha de Registro</th>
|
||||||
|
<th scope="col" class="px-6 py-3 text-right">Acciones</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
@forelse($employees as $employee)
|
||||||
|
<tr class="bg-gray-200/50 dark:bg-neutral-900/50 border-b border-gray-400 dark:border-neutral-800 hover:bg-gray-400 hover:dark:bg-neutral-800 transition-colors group">
|
||||||
|
<td class="px-6 py-4 font-bold text-neutral-900 dark:text-white">
|
||||||
|
{{ $employee->name }}
|
||||||
|
</td>
|
||||||
|
<td class="px-6 py-4 font-mono text-neutral-600 dark:text-gray-400">
|
||||||
|
{{ $employee->email }}
|
||||||
|
</td>
|
||||||
|
<td class="px-6 py-4 text-neutral-700 dark:text-gray-300">
|
||||||
|
{{ $employee->created_at->format('d/m/Y H:i') }}
|
||||||
|
</td>
|
||||||
|
<td class="px-6 py-4 text-right">
|
||||||
|
<div class="flex items-center justify-end gap-2">
|
||||||
|
<!-- Editar -->
|
||||||
|
<button onclick="openEditModal({{ $employee->id }}, '{{ addslashes($employee->name) }}', '{{ addslashes($employee->email) }}')" title="Editar Empleado" class="font-semibold p-2 text-blue-800 dark:text-blue-400 border-2 border-blue-800 rounded-lg hover:bg-blue-800 hover:text-white dark:hover:text-white transition-colors">
|
||||||
|
<svg class="size-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
|
||||||
|
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m14.304 4.844 2.852 2.852M7 7H4a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h11a1 1 0 0 0 1-1v-4.5m2.409-9.91a2.017 2.017 0 0 1 0 2.853l-6.844 6.844L8 14l.713-3.565 6.844-6.844a2.015 2.015 0 0 1 2.852 0Z"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
<!-- Eliminar -->
|
||||||
|
<form action="{{ route('admin.employees.destroy', $employee) }}" method="POST" class="delete-form inline">
|
||||||
|
@csrf
|
||||||
|
@method('DELETE')
|
||||||
|
<button title="Eliminar Empleado" type="submit" class="p-2 font-bold dark:font-medium text-red-600 dark:text-red-400 border-2 border-red-600 rounded-lg hover:bg-red-600 hover:text-white dark:hover:text-white transition-colors">
|
||||||
|
<svg class="size-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
|
||||||
|
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 7h14m-9 3v8m4-8v8M10 3h4a1 1 0 0 1 1 1v3H9V4a1 1 0 0 1 1-1ZM6 7h12v13a1 1 0 0 1-1 1H7a1 1 0 0 1-1-1V7Z"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
@empty
|
||||||
|
<tr>
|
||||||
|
<td colspan="4" class="px-6 py-10 text-center text-gray-500 dark:text-gray-400 font-semibold">
|
||||||
|
No hay empleados registrados actualmente.
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
@endforelse
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Modal de Edición de Empleado -->
|
||||||
|
<div id="editEmployeeModal"
|
||||||
|
class="hidden fixed inset-0 z-50 flex items-center justify-center p-4 bg-neutral-950/60 backdrop-blur-sm transition-all duration-300">
|
||||||
|
|
||||||
|
<div class="relative p-6 rounded-2xl w-full max-w-md shadow-2xl border transition-all transform scale-100
|
||||||
|
bg-white border-neutral-200 text-neutral-900
|
||||||
|
dark:bg-neutral-900 dark:border-neutral-800 dark:text-white">
|
||||||
|
|
||||||
|
<!-- Close button (X) -->
|
||||||
|
<button type="button" onclick="closeEditModal()" class="absolute top-4 right-4 text-neutral-400 hover:text-neutral-600 dark:hover:text-neutral-350 transition-colors p-1.5 rounded-lg hover:bg-neutral-100 dark:hover:bg-neutral-800">
|
||||||
|
<svg class="w-5 h-5" fill="none" stroke="currentColor" stroke-width="2.5" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<!-- Header -->
|
||||||
|
<div class="mb-5 pb-3 border-b border-neutral-200 dark:border-neutral-800 pr-8">
|
||||||
|
<h3 class="text-lg font-black text-neutral-900 dark:text-white flex items-center gap-2">
|
||||||
|
<svg class="w-5 h-5 text-neutral-500 dark:text-neutral-400" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M16.862 4.487l1.687-1.688a1.875 1.875 0 112.652 2.652L6.83 21.75a0.75 0.75 0 01-0.343.203l-4.852 1.213a0.075 0.075 0 01-0.09-.09l1.213-4.852a0.75 0.75 0 01.203-.343L16.862 4.487zm0 0L19.5 7.125" />
|
||||||
|
</svg>
|
||||||
|
Editar Empleado
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form id="editEmployeeForm" method="POST" class="space-y-4">
|
||||||
|
@csrf
|
||||||
|
@method('PUT')
|
||||||
|
|
||||||
|
<!-- Nombre -->
|
||||||
|
<div>
|
||||||
|
<x-forms.label for="edit_name" value="Nombre Completo" />
|
||||||
|
<x-forms.input id="edit_name" name="name" type="text" required placeholder="Ej: Juan Pérez" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Correo -->
|
||||||
|
<div>
|
||||||
|
<x-forms.label for="edit_email" value="Correo Electrónico" />
|
||||||
|
<x-forms.input id="edit_email" name="email" type="email" required placeholder="empleado@lauck.com" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Contraseña opcional -->
|
||||||
|
<div>
|
||||||
|
<x-forms.label for="edit_password" value="Nueva Contraseña (Opcional)" />
|
||||||
|
<div class="relative">
|
||||||
|
<x-forms.input id="edit_password" name="password" type="password" placeholder="Dejar vacío para no cambiar" class="pr-10" />
|
||||||
|
<button type="button" id="toggleEditPassword" class="absolute right-3 top-[11px] text-neutral-500 hover:text-black dark:hover:text-white transition-colors">
|
||||||
|
{{-- Ojo abierto --}}
|
||||||
|
<svg id="iconEditShow" xmlns="http://www.w3.org/2000/svg" class="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.477 0 8.268 2.943 9.542 7-1.274 4.057-5.065 7-9.542 7-4.477 0-8.268-2.943-9.542-7z" />
|
||||||
|
</svg>
|
||||||
|
{{-- Ojo cerrado --}}
|
||||||
|
<svg id="iconEditHide" xmlns="http://www.w3.org/2000/svg" class="w-5 h-5 hidden" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13.875 18.825A10.05 10.05 0 0112 19c-4.477 0-8.268-2.943-9.542-7a9.956 9.956 0 012.293-3.95M6.938 6.938A9.956 9.956 0 0112 5c4.477 0 8.268 2.943 9.542 7a9.97 9.97 0 01-1.88 3.118M3 3l18 18" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Confirmar Contraseña opcional -->
|
||||||
|
<div>
|
||||||
|
<x-forms.label for="edit_password_confirmation" value="Confirmar Nueva Contraseña" />
|
||||||
|
<div class="relative">
|
||||||
|
<x-forms.input id="edit_password_confirmation" name="password_confirmation" type="password" placeholder="Dejar vacío para no cambiar" class="pr-10" />
|
||||||
|
<button type="button" id="toggleEditPasswordConf" class="absolute right-3 top-[11px] text-neutral-500 hover:text-black dark:hover:text-white transition-colors">
|
||||||
|
{{-- Ojo abierto --}}
|
||||||
|
<svg id="iconEditShowConf" xmlns="http://www.w3.org/2000/svg" class="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.477 0 8.268 2.943 9.542 7-1.274 4.057-5.065 7-9.542 7-4.477 0-8.268-2.943-9.542-7z" />
|
||||||
|
</svg>
|
||||||
|
{{-- Ojo cerrado --}}
|
||||||
|
<svg id="iconEditHideConf" xmlns="http://www.w3.org/2000/svg" class="w-5 h-5 hidden" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13.875 18.825A10.05 10.05 0 0112 19c-4.477 0-8.268-2.943-9.542-7a9.956 9.956 0 012.293-3.95M6.938 6.938A9.956 9.956 0 0112 5c4.477 0 8.268 2.943 9.542 7a9.97 9.97 0 01-1.88 3.118M3 3l18 18" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Acciones -->
|
||||||
|
<div class="flex justify-end gap-2 pt-3 border-t border-neutral-100 dark:border-neutral-800">
|
||||||
|
<button type="button" onclick="closeEditModal()"
|
||||||
|
class="px-4 py-2 text-xs font-bold rounded-lg transition-colors bg-neutral-100 hover:bg-neutral-200 text-neutral-700 dark:bg-neutral-800 dark:hover:bg-neutral-700 dark:text-white">
|
||||||
|
Cancelar
|
||||||
|
</button>
|
||||||
|
<button type="submit"
|
||||||
|
class="px-4 py-2 text-xs font-bold rounded-lg transition-colors bg-neutral-950 hover:bg-neutral-900/80 text-neon-lime dark:bg-neon-lime dark:hover:bg-[#b3e600] dark:text-neutral-900">
|
||||||
|
Guardar Cambios
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@push('scripts')
|
||||||
|
<script>
|
||||||
|
function openEditModal(id, name, email) {
|
||||||
|
const modal = document.getElementById('editEmployeeModal');
|
||||||
|
const form = document.getElementById('editEmployeeForm');
|
||||||
|
|
||||||
|
document.getElementById('edit_name').value = name;
|
||||||
|
document.getElementById('edit_email').value = email;
|
||||||
|
document.getElementById('edit_password').value = '';
|
||||||
|
document.getElementById('edit_password_confirmation').value = '';
|
||||||
|
|
||||||
|
form.action = `/admin/employees/${id}`;
|
||||||
|
|
||||||
|
modal.classList.remove('hidden');
|
||||||
|
document.body.style.overflow = 'hidden';
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeEditModal() {
|
||||||
|
const modal = document.getElementById('editEmployeeModal');
|
||||||
|
modal.classList.add('hidden');
|
||||||
|
document.body.style.overflow = 'auto';
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
// Cierre por click en backdrop
|
||||||
|
const editModal = document.getElementById('editEmployeeModal');
|
||||||
|
if (editModal) {
|
||||||
|
editModal.addEventListener('click', function(e) {
|
||||||
|
if (e.target === editModal) {
|
||||||
|
closeEditModal();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Toggle contraseña principal (Registro)
|
||||||
|
const togglePassword = document.getElementById('togglePassword');
|
||||||
|
const passwordInput = document.getElementById('password');
|
||||||
|
const iconShow = document.getElementById('iconShow');
|
||||||
|
const iconHide = document.getElementById('iconHide');
|
||||||
|
|
||||||
|
if (togglePassword && passwordInput) {
|
||||||
|
togglePassword.addEventListener('click', function() {
|
||||||
|
const isPassword = passwordInput.getAttribute('type') === 'password';
|
||||||
|
passwordInput.setAttribute('type', isPassword ? 'text' : 'password');
|
||||||
|
iconShow.classList.toggle('hidden', isPassword);
|
||||||
|
iconHide.classList.toggle('hidden', !isPassword);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Toggle confirmar contraseña (Registro)
|
||||||
|
const togglePasswordConf = document.getElementById('togglePasswordConf');
|
||||||
|
const passwordConfInput = document.getElementById('password_confirmation');
|
||||||
|
const iconShowConf = document.getElementById('iconShowConf');
|
||||||
|
const iconHideConf = document.getElementById('iconHideConf');
|
||||||
|
|
||||||
|
if (togglePasswordConf && passwordConfInput) {
|
||||||
|
togglePasswordConf.addEventListener('click', function() {
|
||||||
|
const isPassword = passwordConfInput.getAttribute('type') === 'password';
|
||||||
|
passwordConfInput.setAttribute('type', isPassword ? 'text' : 'password');
|
||||||
|
iconShowConf.classList.toggle('hidden', isPassword);
|
||||||
|
iconHideConf.classList.toggle('hidden', !isPassword);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Toggle contraseña (Edición)
|
||||||
|
const toggleEditPassword = document.getElementById('toggleEditPassword');
|
||||||
|
const editPasswordInput = document.getElementById('edit_password');
|
||||||
|
const iconEditShow = document.getElementById('iconEditShow');
|
||||||
|
const iconEditHide = document.getElementById('iconEditHide');
|
||||||
|
|
||||||
|
if (toggleEditPassword && editPasswordInput) {
|
||||||
|
toggleEditPassword.addEventListener('click', function() {
|
||||||
|
const isPassword = editPasswordInput.getAttribute('type') === 'password';
|
||||||
|
editPasswordInput.setAttribute('type', isPassword ? 'text' : 'password');
|
||||||
|
iconEditShow.classList.toggle('hidden', isPassword);
|
||||||
|
iconEditHide.classList.toggle('hidden', !isPassword);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Toggle confirmar contraseña (Edición)
|
||||||
|
const toggleEditPasswordConf = document.getElementById('toggleEditPasswordConf');
|
||||||
|
const editPasswordConfInput = document.getElementById('edit_password_confirmation');
|
||||||
|
const iconEditShowConf = document.getElementById('iconEditShowConf');
|
||||||
|
const iconEditHideConf = document.getElementById('iconEditHideConf');
|
||||||
|
|
||||||
|
if (toggleEditPasswordConf && editPasswordConfInput) {
|
||||||
|
toggleEditPasswordConf.addEventListener('click', function() {
|
||||||
|
const isPassword = editPasswordConfInput.getAttribute('type') === 'password';
|
||||||
|
editPasswordConfInput.setAttribute('type', isPassword ? 'text' : 'password');
|
||||||
|
iconEditShowConf.classList.toggle('hidden', isPassword);
|
||||||
|
iconEditHideConf.classList.toggle('hidden', !isPassword);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
@endpush
|
||||||
|
</x-layout>
|
||||||
@@ -37,29 +37,84 @@
|
|||||||
</x-layout>
|
</x-layout>
|
||||||
|
|
||||||
<div id="eventModal"
|
<div id="eventModal"
|
||||||
class="hidden fixed inset-0 z-50 flex items-center justify-center">
|
class="hidden fixed inset-0 z-50 flex items-center justify-center p-4 bg-neutral-950/60 backdrop-blur-sm transition-all duration-300">
|
||||||
|
|
||||||
<div class="relative p-6 rounded-xl w-96 shadow-2xl border
|
<div class="relative p-6 rounded-2xl w-full max-w-sm shadow-2xl border transition-all transform scale-100
|
||||||
bg-white border-neutral-200 text-neutral-900
|
bg-white border-neutral-200 text-neutral-900
|
||||||
dark:bg-neutral-900 dark:border-neutral-700 dark:text-white">
|
dark:bg-neutral-900 dark:border-neutral-800 dark:text-white">
|
||||||
|
|
||||||
<h2 id="modalTitle" class="text-xl font-bold mb-2 text-neutral-900 dark:text-white"></h2>
|
<!-- Close button (X) -->
|
||||||
|
<button id="closeModalCross" class="absolute top-4 right-4 text-neutral-400 hover:text-neutral-600 dark:hover:text-neutral-350 transition-colors p-1.5 rounded-lg hover:bg-neutral-100 dark:hover:bg-neutral-800">
|
||||||
|
<svg class="w-5 h-5" fill="none" stroke="currentColor" stroke-width="2.5" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
|
||||||
<p id="modalDate" class="mb-4 text-neutral-500 dark:text-gray-300"></p>
|
<!-- Header -->
|
||||||
|
<div class="flex justify-between items-center mb-5 pb-3 border-b border-neutral-200 dark:border-neutral-800 pr-8">
|
||||||
|
<h3 class="text-base font-black text-neutral-900 dark:text-white flex items-center gap-2">
|
||||||
|
<svg class="w-5 h-5 text-neutral-500 dark:text-neutral-400" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M6.75 3v2.25M17.25 3v2.25M3 18.75V7.5a2.25 2.25 0 012.25-2.25h13.5A2.25 2.25 0 0121 7.5v11.25m-18 0A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75m-18 0v-7.5A2.25 2.25 0 015.25 9h13.5A2.25 2.25 0 0121 11.25v7.5" />
|
||||||
|
</svg>
|
||||||
|
Detalle del Turno
|
||||||
|
</h3>
|
||||||
|
<span id="modalStatusBadge" class="px-2.5 py-0.5 text-xs font-black rounded-full uppercase tracking-wider border"></span>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="flex justify-end gap-2">
|
<!-- Info Grid -->
|
||||||
|
<div class="space-y-4 mb-6">
|
||||||
|
<!-- Dueño -->
|
||||||
|
<div class="flex items-start gap-3">
|
||||||
|
<div class="p-2.5 bg-neutral-100 dark:bg-neutral-800 rounded-lg text-neutral-500 dark:text-neutral-400 shrink-0">
|
||||||
|
<svg class="w-5 h-5" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M15.75 6a3.75 3.75 0 1 1-7.5 0 3.75 3.75 0 0 1 7.5 0ZM4.501 20.118a7.5 7.5 0 0 1 14.998 0A17.933 17.933 0 0 1 12 21.75c-2.676 0-5.216-.584-7.499-1.632Z"/></svg>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p class="text-[10px] text-neutral-400 dark:text-neutral-500 uppercase font-bold tracking-wider">Dueño</p>
|
||||||
|
<p id="modalClientName" class="font-extrabold text-sm text-neutral-800 dark:text-neutral-100"></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Modelo de Bicicleta -->
|
||||||
|
<div class="flex items-start gap-3">
|
||||||
|
<div class="p-2.5 bg-neutral-100 dark:bg-neutral-800 rounded-lg text-neutral-500 dark:text-neutral-400 shrink-0">
|
||||||
|
<svg class="w-5 h-5" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M9.568 3H5.25A2.25 2.25 0 0 0 3 5.25v4.318c0 .597.237 1.17.659 1.591l9.581 9.581a1.125 1.125 0 0 0 1.591 0l7.261-7.26a1.125 1.125 0 0 0 0-1.591L12.51 3.659A2.25 2.25 0 0 0 10.917 3H9.568Z"/><path stroke-linecap="round" stroke-linejoin="round" d="M6 6h.008v.008H6V6Z"/></svg>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p class="text-[10px] text-neutral-400 dark:text-neutral-500 uppercase font-bold tracking-wider">Modelo de Bicicleta</p>
|
||||||
|
<p id="modalBikeModel" class="font-bold text-sm text-neutral-800 dark:text-neutral-100"></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Día y Horario Pactado -->
|
||||||
|
<div class="flex items-start gap-3">
|
||||||
|
<div class="p-2.5 bg-neutral-100 dark:bg-neutral-800 rounded-lg text-neutral-500 dark:text-neutral-400 shrink-0">
|
||||||
|
<svg class="w-5 h-5" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M12 6v6h4.5m4.5 0a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z"/></svg>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p class="text-[10px] text-neutral-400 dark:text-neutral-500 uppercase font-bold tracking-wider">Día y Horario Pactado</p>
|
||||||
|
<p id="modalDateTime" class="font-bold text-sm text-neutral-800 dark:text-neutral-100"></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Acciones -->
|
||||||
|
<div class="flex justify-end gap-2 pt-3 border-t border-neutral-100 dark:border-neutral-800">
|
||||||
<button id="closeModal"
|
<button id="closeModal"
|
||||||
class="px-4 py-2 rounded-lg
|
class="px-4 py-2 text-xs font-bold rounded-lg transition-colors
|
||||||
bg-neutral-100 hover:bg-neutral-200 text-neutral-700
|
bg-neutral-100 hover:bg-neutral-200 text-neutral-700
|
||||||
dark:bg-gray-600 dark:hover:bg-gray-500 dark:text-white">
|
dark:bg-neutral-800 dark:hover:bg-neutral-700 dark:text-white">
|
||||||
Cerrar
|
Cerrar
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<a id="viewEventBtn"
|
<a id="viewEventBtn"
|
||||||
class="px-4 py-2 font-bold rounded-lg
|
class="px-4 py-2 text-xs font-bold rounded-lg transition-colors flex items-center gap-1.5
|
||||||
bg-neutral-900 hover:bg-neutral-700 text-neon-lime
|
bg-neutral-950 hover:bg-neutral-900/80 text-neon-lime
|
||||||
dark:bg-neon-lime dark:hover:bg-[#b3e600] dark:text-neutral-900">
|
dark:bg-neon-lime dark:hover:bg-[#b3e600] dark:text-neutral-900">
|
||||||
Ver turno
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M2.036 12.322a1.012 1.012 0 010-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178z" />
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
|
||||||
|
</svg>
|
||||||
|
Ver Detalle Completo
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -2,109 +2,155 @@
|
|||||||
|
|
||||||
<x-section-header subtitle="Gestor de Turnos" title="Detalle del" highlight="Turno" />
|
<x-section-header subtitle="Gestor de Turnos" title="Detalle del" highlight="Turno" />
|
||||||
|
|
||||||
<div class="flex justify-end mb-6">
|
<div class="flex justify-end mb-6 gap-3">
|
||||||
<a href="{{ route('agenda') }}"
|
<a href="{{ route('taller.index') }}"
|
||||||
class="px-5 py-2.5 font-bold rounded-lg uppercase tracking-wide text-xs flex items-center gap-2
|
class="px-5 py-2.5 font-bold rounded-lg uppercase tracking-wide text-xs flex items-center gap-2
|
||||||
bg-neutral-900 text-white hover:bg-neutral-700
|
bg-neutral-900 text-white hover:bg-neutral-700
|
||||||
dark:bg-neon-lime dark:text-neutral-900 dark:hover:bg-[#b3e600]">
|
dark:bg-neon-lime dark:text-neutral-900 dark:hover:bg-[#b3e600] transition-colors">
|
||||||
|
← Volver a Taller
|
||||||
|
</a>
|
||||||
|
<a href="{{ route('agenda') }}"
|
||||||
|
class="px-5 py-2.5 font-bold rounded-lg uppercase tracking-wide text-xs flex items-center gap-2
|
||||||
|
bg-stone-200 dark:bg-neutral-800 text-neutral-800 dark:text-neutral-200 hover:bg-stone-300 dark:hover:bg-neutral-700 transition-colors">
|
||||||
← Volver a Agenda
|
← Volver a Agenda
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="rounded-2xl shadow-lg p-8 space-y-6
|
@php
|
||||||
bg-white border border-neutral-300
|
$statusMap = [
|
||||||
dark:bg-neutral-900/50 dark:border-neutral-700 dark:border-2">
|
'pending' => [
|
||||||
|
'label' => 'Pendiente',
|
||||||
|
'classes' => 'bg-red-100 text-red-800 border-red-200 dark:bg-red-900/30 dark:text-red-400 dark:border-red-800'
|
||||||
|
],
|
||||||
|
'confirmed' => [
|
||||||
|
'label' => 'Confirmado',
|
||||||
|
'classes' => 'bg-blue-100 text-blue-800 border-blue-200 dark:bg-blue-900/30 dark:text-blue-400 dark:border-blue-800'
|
||||||
|
],
|
||||||
|
'in_progress' => [
|
||||||
|
'label' => 'En progreso',
|
||||||
|
'classes' => 'bg-orange-100 text-orange-800 border-orange-200 dark:bg-orange-950/30 dark:text-orange-400 dark:border-orange-800'
|
||||||
|
],
|
||||||
|
'ready' => [
|
||||||
|
'label' => 'Listo',
|
||||||
|
'classes' => 'bg-green-100 text-green-800 border-green-200 dark:bg-green-900/30 dark:text-green-450 dark:border-green-800'
|
||||||
|
],
|
||||||
|
'delivered' => [
|
||||||
|
'label' => 'Entregado',
|
||||||
|
'classes' => 'bg-neutral-100 text-neutral-800 border-neutral-200 dark:bg-neutral-850 dark:text-gray-400 dark:border-neutral-700'
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
@php
|
$currentStatus = $statusMap[$appointment->status] ?? [
|
||||||
$statusMap = [
|
'label' => 'Desconocido',
|
||||||
'pending' => 'Pendiente',
|
'classes' => 'bg-neutral-100 text-neutral-800 border-neutral-200'
|
||||||
'confirmed' => 'Confirmado',
|
];
|
||||||
'in_progress' => 'En progreso',
|
@endphp
|
||||||
'ready' => 'Listo',
|
|
||||||
'delivered' => 'Entregado',
|
|
||||||
];
|
|
||||||
|
|
||||||
$translatedStatus = $statusMap[$appointment->status] ?? 'Desconocido';
|
<div class="max-w-2xl mx-auto bg-white dark:bg-neutral-900 border border-neutral-200 dark:border-neutral-800 rounded-2xl shadow-xl p-8 space-y-6">
|
||||||
|
<!-- Header / Status -->
|
||||||
$colorMap = [
|
<div class="flex justify-between items-center pb-4 border-b border-neutral-200 dark:border-neutral-800">
|
||||||
'pending' => '#ef4444',
|
<h3 class="text-lg font-black text-neutral-900 dark:text-white flex items-center gap-2">
|
||||||
'in_progress' => '#f59e0b',
|
<svg class="w-5 h-5 text-neutral-500 dark:text-neutral-400" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||||
'completed' => '#22c55e',
|
<path stroke-linecap="round" stroke-linejoin="round" d="M6.75 3v2.25M17.25 3v2.25M3 18.75V7.5a2.25 2.25 0 012.25-2.25h13.5A2.25 2.25 0 0121 7.5v11.25m-18 0A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75m-18 0v-7.5A2.25 2.25 0 015.25 9h13.5A2.25 2.25 0 0121 11.25v7.5" />
|
||||||
'ready' => '#22c55e',
|
</svg>
|
||||||
'delivered' => '#22c55e',
|
Ficha del Turno #{{ $appointment->id }}
|
||||||
];
|
</h3>
|
||||||
|
<span class="px-2.5 py-0.5 text-xs font-black rounded-full uppercase tracking-wider border {{ $currentStatus['classes'] }}">
|
||||||
$color = $colorMap[$appointment->status] ?? '#3b82f6';
|
{{ $currentStatus['label'] }}
|
||||||
@endphp
|
|
||||||
|
|
||||||
{{-- Estado --}}
|
|
||||||
<div class="text-center">
|
|
||||||
<span class="text-lg uppercase font-bold tracking-wide text-neutral-500 dark:text-gray-400">
|
|
||||||
Estado
|
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<div class="mt-2">
|
|
||||||
<span class="px-3 py-1 rounded-full text-lg font-semibold text-black"
|
|
||||||
style="background-color: {{ $color }}">
|
|
||||||
{{ $translatedStatus }}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{-- Información principal --}}
|
<!-- Info Grid -->
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||||
|
<!-- Cliente -->
|
||||||
<div>
|
<div class="flex items-start gap-3 md:col-span-2">
|
||||||
<p class="text-lg uppercase font-bold text-neutral-500 dark:text-gray-400">Cliente</p>
|
<div class="p-2.5 bg-neutral-100 dark:bg-neutral-800 rounded-lg text-neutral-500 dark:text-neutral-400 shrink-0">
|
||||||
<p class="text-lg font-semibold text-neutral-900 dark:text-white">
|
<svg class="w-5 h-5" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M15.75 6a3.75 3.75 0 1 1-7.5 0 3.75 3.75 0 0 1 7.5 0ZM4.501 20.118a7.5 7.5 0 0 1 14.998 0A17.933 17.933 0 0 1 12 21.75c-2.676 0-5.216-.584-7.499-1.632Z"/></svg>
|
||||||
{{ $appointment->client->name }}
|
</div>
|
||||||
</p>
|
<div>
|
||||||
|
<p class="text-[10px] text-neutral-400 dark:text-neutral-500 uppercase font-bold tracking-wider">Cliente</p>
|
||||||
|
<p class="font-extrabold text-base text-neutral-800 dark:text-neutral-100">{{ $appointment->client->name }}</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<!-- Teléfono -->
|
||||||
<p class="text-lg uppercase font-bold text-neutral-500 dark:text-gray-400">Teléfono</p>
|
<div class="flex items-start gap-3">
|
||||||
<p class="text-neutral-900 dark:text-white">
|
<div class="p-2.5 bg-neutral-100 dark:bg-neutral-800 rounded-lg text-neutral-500 dark:text-neutral-400 shrink-0">
|
||||||
{{ $appointment->contact_phone ?? '-' }}
|
<svg class="w-5 h-5" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M2.25 6.75c0 8.284 6.716 15 15 15h2.25a2.25 2.25 0 0 0 2.25-2.25v-1.372c0-.516-.351-.966-.852-1.091l-4.423-1.106c-.44-.11-.902.055-1.173.417l-.97 1.293c-.282.376-.769.542-1.21.387a12.035 12.035 0 0 1-7.108-7.108c-.145-.44.02-9.27.387-1.21l1.293-.97c.363-.271.527-.734.417-1.173L6.963 3.102a1.125 1.125 0 0 0-1.091-.852H4.5A2.25 2.25 0 0 0 2.25 4.5v2.25Z"/></svg>
|
||||||
</p>
|
</div>
|
||||||
|
<div>
|
||||||
|
<p class="text-[10px] text-neutral-400 dark:text-neutral-500 uppercase font-bold tracking-wider">Teléfono de contacto</p>
|
||||||
|
<p class="font-bold text-neutral-800 dark:text-neutral-100">{{ $appointment->contact_phone ?? 'Sin teléfono registrado' }}</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<!-- Bicicleta -->
|
||||||
<p class="text-lg uppercase font-bold text-neutral-500 dark:text-gray-400">Fecha pactada de entrega</p>
|
<div class="flex items-start gap-3">
|
||||||
<p class="text-neutral-900 dark:text-white">
|
<div class="p-2.5 bg-neutral-100 dark:bg-neutral-800 rounded-lg text-neutral-500 dark:text-neutral-400 shrink-0">
|
||||||
{{ $appointment->scheduled_at->format('d/m/Y') }}
|
<svg class="w-5 h-5" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M9.568 3H5.25A2.25 2.25 0 0 0 3 5.25v4.318c0 .597.237 1.17.659 1.591l9.581 9.581a1.125 1.125 0 0 0 1.591 0l7.261-7.26a1.125 1.125 0 0 0 0-1.591L12.51 3.659A2.25 2.25 0 0 0 10.917 3H9.568Z"/><path stroke-linecap="round" stroke-linejoin="round" d="M6 6h.008v.008H6V6Z"/></svg>
|
||||||
</p>
|
</div>
|
||||||
|
<div>
|
||||||
|
<p class="text-[10px] text-neutral-400 dark:text-neutral-500 uppercase font-bold tracking-wider">Bicicleta</p>
|
||||||
|
<p class="font-bold text-neutral-800 dark:text-neutral-100">{{ $appointment->bike_model ?? 'Sin modelo' }}</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<!-- Fecha y Hora de Entrega -->
|
||||||
<p class="text-lg uppercase font-bold text-neutral-500 dark:text-gray-400">Hora</p>
|
<div class="flex items-start gap-3">
|
||||||
<p class="text-neutral-900 dark:text-white">
|
<div class="p-2.5 bg-neutral-100 dark:bg-neutral-800 rounded-lg text-neutral-500 dark:text-neutral-400 shrink-0">
|
||||||
{{ $appointment->scheduled_at->format('H:i') }}
|
<svg class="w-5 h-5" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M12 6v6h4.5m4.5 0a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z"/></svg>
|
||||||
</p>
|
</div>
|
||||||
|
<div>
|
||||||
|
<p class="text-[10px] text-neutral-400 dark:text-neutral-500 uppercase font-bold tracking-wider">Fecha y Hora Pactada</p>
|
||||||
|
<p class="font-bold text-neutral-800 dark:text-neutral-100">
|
||||||
|
{{ ucfirst($appointment->scheduled_at->locale('es')->translatedFormat('l, d \d\e F \d\e Y')) }} a las {{ $appointment->scheduled_at->format('H:i') }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="md:col-span-2">
|
<!-- Presupuesto -->
|
||||||
<p class="text-lg uppercase font-bold text-neutral-500 dark:text-gray-400">Modelo de Bicicleta</p>
|
<div class="flex items-start gap-3">
|
||||||
<p class="text-neutral-900 dark:text-white">
|
<div class="p-2.5 bg-neutral-100 dark:bg-neutral-800 rounded-lg text-neutral-500 dark:text-neutral-400 shrink-0">
|
||||||
{{ $appointment->bike_model ?? '-' }}
|
<svg class="w-5 h-5 text-neutral-500 dark:text-neutral-400" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||||
</p>
|
<path stroke-linecap="round" stroke-linejoin="round" d="M12 6v12m-3 -2.818l0.879 0.659c1.171 0.879 3.07 0.879 4.242 0c1.172 -0.879 1.172 -2.303 0 -3.182C13.536 12.219 12.768 12 12 12c-0.725 0 -1.45 -0.22 -2.003 -0.659c-1.106 -0.879 -1.106 -2.303 0 -3.182s2.9 -0.879 4.006 0l0.415 0.33M21 12a9 9 0 1 1 -18 0a9 9 0 0 1 18 0Z" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p class="text-[10px] text-neutral-400 dark:text-neutral-500 uppercase font-bold tracking-wider">Presupuesto Estimado</p>
|
||||||
|
<p class="font-black text-neutral-800 dark:text-neutral-100 font-mono">
|
||||||
|
{{ $appointment->estimated_cost ? '$' . number_format($appointment->estimated_cost, 0, ',', '.') : 'Sin presupuestar' }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="md:col-span-2">
|
|
||||||
<p class="text-lg uppercase font-bold text-neutral-500 dark:text-gray-400">Problema Reportado</p>
|
|
||||||
<p class="text-neutral-900 dark:text-white">
|
|
||||||
{{ $appointment->problem_description }}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="md:col-span-2">
|
|
||||||
<p class="text-lg uppercase font-bold text-neutral-500 dark:text-gray-400">Notas</p>
|
|
||||||
<p class="text-neutral-900 dark:text-white">
|
|
||||||
{{ $appointment->notes ?? '-' }}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Descripción del problema -->
|
||||||
|
<div class="mt-6">
|
||||||
|
<p class="text-[10px] text-neutral-400 dark:text-neutral-500 uppercase font-bold tracking-wider mb-1.5">Descripción del problema</p>
|
||||||
|
<div class="p-4 bg-neutral-50 dark:bg-neutral-950/30 border border-neutral-100 dark:border-neutral-800 rounded-xl">
|
||||||
|
<p class="text-sm text-neutral-700 dark:text-neutral-300 leading-relaxed whitespace-pre-line">{{ $appointment->problem_description }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Repuestos necesarios (si existen) -->
|
||||||
|
@if($appointment->parts_needed)
|
||||||
|
<div class="mt-6">
|
||||||
|
<p class="text-[10px] text-neutral-400 dark:text-neutral-500 uppercase font-bold tracking-wider mb-1.5">Repuestos Necesarios</p>
|
||||||
|
<div class="p-4 bg-amber-50/50 dark:bg-amber-950/10 border border-amber-100/70 dark:border-amber-900/30 text-amber-800 dark:text-amber-300 rounded-xl">
|
||||||
|
<p class="text-sm leading-relaxed whitespace-pre-line">{{ $appointment->parts_needed }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
<!-- Notas internas (si existen) -->
|
||||||
|
@if($appointment->notes)
|
||||||
|
<div class="mt-6">
|
||||||
|
<p class="text-[10px] text-neutral-400 dark:text-neutral-500 uppercase font-bold tracking-wider mb-1.5">Notas Internas</p>
|
||||||
|
<div class="p-4 bg-blue-50/50 dark:bg-blue-950/10 border border-blue-100/70 dark:border-blue-900/30 text-blue-800 dark:text-blue-300 rounded-xl">
|
||||||
|
<p class="text-sm leading-relaxed whitespace-pre-line">{{ $appointment->notes }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</x-layout>
|
</x-layout>
|
||||||
@@ -21,9 +21,15 @@
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<a href="{{ route('clients.create') }}" class="w-full md:w-auto text-center px-5 py-3 text-sm font-bold text-neon-lime dark:text-neutral-900 bg-neutral-950 dark:bg-neon-lime rounded-lg hover:bg-neutral-900/80 hover:dark:bg-[#b3e600] transition-colors uppercase tracking-wide">
|
@if(auth()->user()->role === 'admin')
|
||||||
+ Nuevo Cliente
|
<a href="{{ route('clients.create') }}" class="w-full md:w-auto text-center px-5 py-3 text-sm font-bold text-neon-lime dark:text-neutral-900 bg-neutral-950 dark:bg-neon-lime rounded-lg hover:bg-neutral-900/80 hover:dark:bg-[#b3e600] transition-colors uppercase tracking-wide">
|
||||||
</a>
|
+ Nuevo Cliente
|
||||||
|
</a>
|
||||||
|
@else
|
||||||
|
<span title="Acceso denegado" class="w-full md:w-auto text-center px-5 py-3 text-sm font-bold text-gray-500 dark:text-neutral-500 bg-gray-300 dark:bg-neutral-800 border border-gray-400 dark:border-neutral-700 rounded-lg cursor-not-allowed pointer-events-none select-none uppercase tracking-wide">
|
||||||
|
+ Nuevo Cliente
|
||||||
|
</span>
|
||||||
|
@endif
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="relative overflow-x-auto shadow-md sm:rounded-lg border border-gray-400 dark:border-neutral-800 w-full">
|
<div class="relative overflow-x-auto shadow-md sm:rounded-lg border border-gray-400 dark:border-neutral-800 w-full">
|
||||||
@@ -61,20 +67,47 @@
|
|||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td class="px-6 py-4 text-right flex items-center justify-end gap-2">
|
<td class="px-6 py-4 text-right flex items-center justify-end gap-2">
|
||||||
<a href="{{ route('clients.edit', $client) }}" title="Editar" class="font-semibold p-2 text-blue-700 dark:text-blue-400 border-2 border-blue-700 rounded-lg hover:bg-blue-700 hover:text-white dark:hover:text-white transition-colors">
|
<!-- Ver Más -->
|
||||||
|
<a href="{{ route('clients.show', $client) }}" title="Ver Más" class="font-semibold p-2 text-green-700 dark:text-green-400 border-2 border-green-700 rounded-lg hover:bg-green-700 dark:hover:bg-green-600 dark:hover:border-green-600 hover:text-white dark:hover:text-white transition-colors">
|
||||||
<svg class="size-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
|
<svg class="size-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
|
||||||
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m14.304 4.844 2.852 2.852M7 7H4a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h11a1 1 0 0 0 1-1v-4.5m2.409-9.91a2.017 2.017 0 0 1 0 2.853l-6.844 6.844L8 14l.713-3.565 6.844-6.844a2.015 2.015 0 0 1 2.852 0Z"/>
|
<path stroke="currentColor" stroke-width="2" d="M21 12c0 1.2-4.03 6-9 6s-9-4.8-9-6c0-1.2 4.03-6 9-6s9 4.8 9 6Z"/>
|
||||||
|
<path stroke="currentColor" stroke-width="2" d="M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z"/>
|
||||||
</svg>
|
</svg>
|
||||||
</a>
|
</a>
|
||||||
<form action="{{route('clients.destroy',$client)}}" method="post" class="delete-form">
|
|
||||||
@csrf
|
<!-- Editar -->
|
||||||
@method('DELETE')
|
@if(auth()->user()->role === 'admin')
|
||||||
<button title="Eliminar" type="submit" class="w-full sm:w-auto p-2 font-bold dark:font-medium text-red-600 dark:text-red-400 border-2 border-red-600 rounded-lg hover:bg-red-600 hover:text-white dark:hover:text-white transition-colors">
|
<a href="{{ route('clients.edit', $client) }}" title="Editar" class="font-semibold p-2 text-blue-800 dark:text-blue-400 border-2 border-blue-800 rounded-lg hover:bg-blue-800 hover:text-white dark:hover:text-white transition-colors">
|
||||||
|
<svg class="size-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
|
||||||
|
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m14.304 4.844 2.852 2.852M7 7H4a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h11a1 1 0 0 0 1-1v-4.5m2.409-9.91a2.017 2.017 0 0 1 0 2.853l-6.844 6.844L8 14l.713-3.565 6.844-6.844a2.015 2.015 0 0 1 2.852 0Z"/>
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
@else
|
||||||
|
<span title="Acceso denegado" class="font-semibold p-2 text-gray-400 dark:text-neutral-500 border-2 border-gray-300 dark:border-neutral-700 rounded-lg bg-gray-100 dark:bg-neutral-800/30 cursor-not-allowed pointer-events-none select-none">
|
||||||
|
<svg class="size-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
|
||||||
|
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m14.304 4.844 2.852 2.852M7 7H4a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h11a1 1 0 0 0 1-1v-4.5m2.409-9.91a2.017 2.017 0 0 1 0 2.853l-6.844 6.844L8 14l.713-3.565 6.844-6.844a2.015 2.015 0 0 1 2.852 0Z"/>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
<!-- Eliminar -->
|
||||||
|
@if(auth()->user()->role === 'admin')
|
||||||
|
<form action="{{route('clients.destroy',$client)}}" method="post" class="delete-form">
|
||||||
|
@csrf
|
||||||
|
@method('DELETE')
|
||||||
|
<button title="Eliminar" type="submit" class="w-full sm:w-auto p-2 font-bold dark:font-medium text-red-600 dark:text-red-400 border-2 border-red-600 rounded-lg hover:bg-red-600 hover:text-white dark:hover:text-white transition-colors">
|
||||||
|
<svg class="size-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
|
||||||
|
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 7h14m-9 3v8m4-8v8M10 3h4a1 1 0 0 1 1 1v3H9V4a1 1 0 0 1 1-1ZM6 7h12v13a1 1 0 0 1-1 1H7a1 1 0 0 1-1-1V7Z"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
@else
|
||||||
|
<span title="Acceso denegado" class="p-2 font-bold dark:font-medium text-gray-400 dark:text-neutral-500 border-2 border-gray-300 dark:border-neutral-700 rounded-lg bg-gray-100 dark:bg-neutral-800/30 cursor-not-allowed pointer-events-none select-none">
|
||||||
<svg class="size-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
|
<svg class="size-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
|
||||||
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 7h14m-9 3v8m4-8v8M10 3h4a1 1 0 0 1 1 1v3H9V4a1 1 0 0 1 1-1ZM6 7h12v13a1 1 0 0 1-1 1H7a1 1 0 0 1-1-1V7Z"/>
|
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 7h14m-9 3v8m4-8v8M10 3h4a1 1 0 0 1 1 1v3H9V4a1 1 0 0 1 1-1ZM6 7h12v13a1 1 0 0 1-1 1H7a1 1 0 0 1-1-1V7Z"/>
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</span>
|
||||||
</form>
|
@endif
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
@@ -0,0 +1,61 @@
|
|||||||
|
<x-layout title="Lauck - Detalle de Cliente">
|
||||||
|
<x-section-header subtitle="Clientes" title="Detalle de " highlight="Cliente" />
|
||||||
|
|
||||||
|
<div class="w-full max-w-4xl mx-auto bg-gray-200 dark:bg-panel-bg border border-neutral-400 dark:border-neutral-800 rounded-xl p-8 shadow-lg relative">
|
||||||
|
<div class="flex justify-between items-start mb-6">
|
||||||
|
<div>
|
||||||
|
<h3 class="text-2xl font-bold text-neutral-900 dark:text-white">{{ $client->name }}</h3>
|
||||||
|
<p class="text-sm text-gray-600 dark:text-gray-400">Registrado el: {{ $client->created_at->format('d/m/Y H:i') }}</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<a href="{{ route('clients.index') }}" class="text-sm font-bold text-gray-500 hover:text-white transition-colors">Volver al listado</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 bg-gray-300 dark:bg-neutral-800 p-6 rounded-lg border border-gray-400 dark:border-neutral-700">
|
||||||
|
<div>
|
||||||
|
<p class="text-xs text-gray-500 uppercase tracking-wider mb-1">Nombre Completo</p>
|
||||||
|
<p class="text-lg font-bold text-neutral-900 dark:text-white">{{ $client->name }}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<p class="text-xs text-gray-500 uppercase tracking-wider mb-1">Teléfono / WhatsApp</p>
|
||||||
|
@if($client->phone)
|
||||||
|
<p class="text-lg font-bold text-neutral-900 dark:text-white font-mono">{{ $client->phone }}</p>
|
||||||
|
@else
|
||||||
|
<p class="text-lg text-gray-500 italic">No registrado</p>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<p class="text-xs text-gray-500 uppercase tracking-wider mb-1">Correo Electrónico</p>
|
||||||
|
@if($client->email)
|
||||||
|
<p class="text-base font-semibold text-neutral-900 dark:text-white font-mono">{{ $client->email }}</p>
|
||||||
|
@else
|
||||||
|
<p class="text-base text-gray-500 italic">No registrado</p>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<p class="text-xs text-gray-500 uppercase tracking-wider mb-1">Dirección</p>
|
||||||
|
@if($client->address)
|
||||||
|
<p class="text-base font-semibold text-neutral-900 dark:text-white">{{ $client->address }}</p>
|
||||||
|
@else
|
||||||
|
<p class="text-base text-gray-500 italic">No registrada</p>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-8 flex justify-end gap-4">
|
||||||
|
@if(auth()->user()->role === 'admin')
|
||||||
|
<a href="{{ route('clients.edit', $client) }}" class="px-6 py-2.5 text-sm font-bold text-white bg-blue-600 hover:bg-blue-700 rounded-lg transition-colors">
|
||||||
|
Editar Cliente
|
||||||
|
</a>
|
||||||
|
@else
|
||||||
|
<span title="Acceso denegado" class="px-6 py-2.5 text-sm font-bold text-gray-400 bg-gray-300 dark:bg-neutral-800 border border-gray-400 dark:border-neutral-700 rounded-lg cursor-not-allowed pointer-events-none">
|
||||||
|
Editar Cliente
|
||||||
|
</span>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</x-layout>
|
||||||
@@ -80,6 +80,9 @@
|
|||||||
<x-sidebar-link href="{{ route('admin.backups.index') }}" :active="request()->routeIs('admin.backups.*')" icon="database">
|
<x-sidebar-link href="{{ route('admin.backups.index') }}" :active="request()->routeIs('admin.backups.*')" icon="database">
|
||||||
Respaldos
|
Respaldos
|
||||||
</x-sidebar-link>
|
</x-sidebar-link>
|
||||||
|
<x-sidebar-link href="{{ route('admin.employees.index') }}" :active="request()->routeIs('admin.employees.*')" icon="users">
|
||||||
|
Empleados
|
||||||
|
</x-sidebar-link>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
<div class="pt-4 pb-2">
|
<div class="pt-4 pb-2">
|
||||||
|
|||||||
@@ -20,12 +20,23 @@
|
|||||||
<h4 class="text-gray-900 dark:text-white font-black text-sm mb-1">{{ $job->bike_model }}</h4>
|
<h4 class="text-gray-900 dark:text-white font-black text-sm mb-1">{{ $job->bike_model }}</h4>
|
||||||
<p class="text-gray-700 dark:text-gray-300 text-xs line-clamp-2 mb-3">{{ $job->problem_description }}</p>
|
<p class="text-gray-700 dark:text-gray-300 text-xs line-clamp-2 mb-3">{{ $job->problem_description }}</p>
|
||||||
|
|
||||||
@if($job->estimated_cost)
|
<div class="flex justify-between items-center mb-3">
|
||||||
<div class="text-right mb-3">
|
@if($job->estimated_cost)
|
||||||
<span class="text-xs text-gray-600 dark:text-gray-400">Presupuesto:</span>
|
<div>
|
||||||
<span class="text-sm font-mono text-gray-900 dark:text-white font-black">${{ number_format($job->estimated_cost, 0) }}</span>
|
<span class="text-xs text-gray-600 dark:text-gray-400">Presupuesto:</span>
|
||||||
</div>
|
<span class="text-sm font-mono text-gray-900 dark:text-white font-black">${{ number_format($job->estimated_cost, 0) }}</span>
|
||||||
@endif
|
</div>
|
||||||
|
@else
|
||||||
|
<div></div>
|
||||||
|
@endif
|
||||||
|
<a href="{{ route('appointments.show', $job) }}" class="text-xs font-bold text-neon-lime dark:text-neutral-900 bg-neutral-950 dark:bg-neon-lime rounded px-2.5 py-1 hover:bg-neutral-900/80 hover:dark:bg-[#b3e600] transition-colors flex items-center gap-1">
|
||||||
|
<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" stroke-width="2.5" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M2.036 12.322a1.012 1.012 0 010-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178z" />
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
|
||||||
|
</svg>
|
||||||
|
Ver
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Controles de Estado -->
|
<!-- Controles de Estado -->
|
||||||
<div class="flex justify-between items-center pt-2 border-t border-gray-200 dark:border-neutral-700 mt-2 opacity-100 md:opacity-50 group-hover:opacity-100 transition-opacity">
|
<div class="flex justify-between items-center pt-2 border-t border-gray-200 dark:border-neutral-700 mt-2 opacity-100 md:opacity-50 group-hover:opacity-100 transition-opacity">
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="w-full md:w-1/3">
|
<div class="w-full md:w-1/3">
|
||||||
<select name="category" onchange="this.form.submit()" class="block w-full p-3 text-sm text-black dark:text-white border border-neutral-400 dark:border-neutral-700 rounded-lg bg-neutral-200 dark:bg-neutral-800">
|
<select name="category" onchange="this.form.submit()" class="block w-full p-3 pr-10 text-sm text-black dark:text-white border border-neutral-400 dark:border-neutral-700 rounded-lg bg-neutral-200 dark:bg-neutral-800">
|
||||||
<option value="">Todas las Categorías</option>
|
<option value="">Todas las Categorías</option>
|
||||||
<option value="Mercadería" {{ request('category') == 'Mercadería' ? 'selected' : '' }}>Mercadería</option>
|
<option value="Mercadería" {{ request('category') == 'Mercadería' ? 'selected' : '' }}>Mercadería</option>
|
||||||
<option value="Servicios" {{ request('category') == 'Servicios' ? 'selected' : '' }}>Servicios (Luz, Internet...)</option>
|
<option value="Servicios" {{ request('category') == 'Servicios' ? 'selected' : '' }}>Servicios (Luz, Internet...)</option>
|
||||||
@@ -28,9 +28,15 @@
|
|||||||
<button type="submit" class="hidden">Buscar</button>
|
<button type="submit" class="hidden">Buscar</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<a href="{{ route('expenses.create') }}" class="w-full md:w-auto text-center px-5 py-3 text-sm font-bold text-neon-lime dark:text-neutral-900 bg-neutral-950 dark:bg-neon-lime rounded-lg hover:bg-neutral-900/80 hover:dark:bg-[#b3e600] transition-colors uppercase tracking-wide">
|
@if(auth()->user()->role === 'admin')
|
||||||
+ Nuevo Gasto
|
<a href="{{ route('expenses.create') }}" class="w-full md:w-auto text-center px-5 py-3 text-sm font-bold text-neon-lime dark:text-neutral-900 bg-neutral-950 dark:bg-neon-lime rounded-lg hover:bg-neutral-900/80 hover:dark:bg-[#b3e600] transition-colors uppercase tracking-wide">
|
||||||
</a>
|
+ Nuevo Gasto
|
||||||
|
</a>
|
||||||
|
@else
|
||||||
|
<span title="Acceso denegado" class="w-full md:w-auto text-center px-5 py-3 text-sm font-bold text-gray-500 dark:text-neutral-500 bg-gray-300 dark:bg-neutral-800 border border-gray-400 dark:border-neutral-700 rounded-lg cursor-not-allowed pointer-events-none select-none uppercase tracking-wide">
|
||||||
|
+ Nuevo Gasto
|
||||||
|
</span>
|
||||||
|
@endif
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="relative overflow-x-auto shadow-md sm:rounded-lg border border-gray-400 dark:border-neutral-800 w-full">
|
<div class="relative overflow-x-auto shadow-md sm:rounded-lg border border-gray-400 dark:border-neutral-800 w-full">
|
||||||
@@ -83,26 +89,47 @@
|
|||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td class="px-6 py-4 text-right flex items-center justify-end gap-3">
|
<td class="px-6 py-4 text-right flex items-center justify-end gap-3">
|
||||||
<a href="{{ route('expenses.show', $expense) }}" title="Ver Detalle" class="font-semibold p-2 text-gray-700 dark:text-gray-300 border-2 border-gray-500 rounded-lg hover:bg-gray-500 hover:text-white dark:hover:text-white transition-colors">
|
<!-- Ver Más -->
|
||||||
|
<a href="{{ route('expenses.show', $expense) }}" title="Ver Detalle" class="font-semibold p-2 text-green-700 dark:text-green-400 border-2 border-green-700 rounded-lg hover:bg-green-700 dark:hover:bg-green-600 dark:hover:border-green-600 hover:text-white dark:hover:text-white transition-colors">
|
||||||
<svg class="size-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
|
<svg class="size-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
|
||||||
<path stroke="currentColor" stroke-width="2" d="M21 12c0 1.2-4.03 6-9 6s-9-4.8-9-6c0-1.2 4.03-6 9-6s9 4.8 9 6Z"/>
|
<path stroke="currentColor" stroke-width="2" d="M21 12c0 1.2-4.03 6-9 6s-9-4.8-9-6c0-1.2 4.03-6 9-6s9 4.8 9 6Z"/>
|
||||||
<path stroke="currentColor" stroke-width="2" d="M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z"/>
|
<path stroke="currentColor" stroke-width="2" d="M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z"/>
|
||||||
</svg>
|
</svg>
|
||||||
</a>
|
</a>
|
||||||
<a href="{{ route('expenses.edit', $expense) }}" title="Editar" class="font-semibold p-2 text-blue-700 dark:text-blue-400 border-2 border-blue-700 rounded-lg hover:bg-blue-700 hover:text-white dark:hover:text-white transition-colors">
|
|
||||||
<svg class="size-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
|
<!-- Editar -->
|
||||||
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m14.304 4.844 2.852 2.852M7 7H4a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h11a1 1 0 0 0 1-1v-4.5m2.409-9.91a2.017 2.017 0 0 1 0 2.853l-6.844 6.844L8 14l.713-3.565 6.844-6.844a2.015 2.015 0 0 1 2.852 0Z"/>
|
@if(auth()->user()->role === 'admin')
|
||||||
</svg>
|
<a href="{{ route('expenses.edit', $expense) }}" title="Editar" class="font-semibold p-2 text-blue-800 dark:text-blue-400 border-2 border-blue-800 rounded-lg hover:bg-blue-800 hover:text-white dark:hover:text-white transition-colors">
|
||||||
</a>
|
<svg class="size-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
|
||||||
<form action="{{route('expenses.destroy', $expense)}}" method="post" class="delete-form">
|
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m14.304 4.844 2.852 2.852M7 7H4a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h11a1 1 0 0 0 1-1v-4.5m2.409-9.91a2.017 2.017 0 0 1 0 2.853l-6.844 6.844L8 14l.713-3.565 6.844-6.844a2.015 2.015 0 0 1 2.852 0Z"/>
|
||||||
@csrf
|
</svg>
|
||||||
@method('DELETE')
|
</a>
|
||||||
<button title="Eliminar" type="submit" class="w-full sm:w-auto p-2 font-bold dark:font-medium text-red-600 dark:text-red-400 border-2 border-red-600 rounded-lg hover:bg-red-600 hover:text-white dark:hover:text-white transition-colors">
|
@else
|
||||||
|
<span title="Acceso denegado" class="font-semibold p-2 text-gray-400 dark:text-neutral-500 border-2 border-gray-300 dark:border-neutral-700 rounded-lg bg-gray-100 dark:bg-neutral-800/30 cursor-not-allowed pointer-events-none select-none">
|
||||||
|
<svg class="size-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
|
||||||
|
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m14.304 4.844 2.852 2.852M7 7H4a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h11a1 1 0 0 0 1-1v-4.5m2.409-9.91a2.017 2.017 0 0 1 0 2.853l-6.844 6.844L8 14l.713-3.565 6.844-6.844a2.015 2.015 0 0 1 2.852 0Z"/>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
<!-- Eliminar -->
|
||||||
|
@if(auth()->user()->role === 'admin')
|
||||||
|
<form action="{{route('expenses.destroy', $expense)}}" method="post" class="delete-form">
|
||||||
|
@csrf
|
||||||
|
@method('DELETE')
|
||||||
|
<button title="Eliminar" type="submit" class="w-full sm:w-auto p-2 font-bold dark:font-medium text-red-600 dark:text-red-400 border-2 border-red-600 rounded-lg hover:bg-red-600 hover:text-white dark:hover:text-white transition-colors">
|
||||||
|
<svg class="size-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
|
||||||
|
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 7h14m-9 3v8m4-8v8M10 3h4a1 1 0 0 1 1 1v3H9V4a1 1 0 0 1 1-1ZM6 7h12v13a1 1 0 0 1-1 1H7a1 1 0 0 1-1-1V7Z"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
@else
|
||||||
|
<span title="Acceso denegado" class="p-2 font-bold dark:font-medium text-gray-400 dark:text-neutral-500 border-2 border-gray-300 dark:border-neutral-700 rounded-lg bg-gray-100 dark:bg-neutral-800/30 cursor-not-allowed pointer-events-none select-none">
|
||||||
<svg class="size-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
|
<svg class="size-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
|
||||||
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 7h14m-9 3v8m4-8v8M10 3h4a1 1 0 0 1 1 1v3H9V4a1 1 0 0 1 1-1ZM6 7h12v13a1 1 0 0 1-1 1H7a1 1 0 0 1-1-1V7Z"/>
|
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 7h14m-9 3v8m4-8v8M10 3h4a1 1 0 0 1 1 1v3H9V4a1 1 0 0 1 1-1ZM6 7h12v13a1 1 0 0 1-1 1H7a1 1 0 0 1-1-1V7Z"/>
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</span>
|
||||||
</form>
|
@endif
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@empty
|
@empty
|
||||||
|
|||||||
@@ -39,9 +39,15 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<a href="{{ route('productos.create') }}" class="w-full xl:w-auto text-center px-5 py-3 text-sm font-bold text-neon-lime dark:text-neutral-900 bg-neutral-950 dark:bg-neon-lime rounded-lg hover:bg-neutral-900/80 hover:dark:bg-[#b3e600] transition-colors uppercase tracking-wide">
|
@if(auth()->user()->role === 'admin')
|
||||||
+ Nuevo Producto
|
<a href="{{ route('productos.create') }}" class="w-full xl:w-auto text-center px-5 py-3 text-sm font-bold text-neon-lime dark:text-neutral-900 bg-neutral-950 dark:bg-neon-lime rounded-lg hover:bg-neutral-900/80 hover:dark:bg-[#b3e600] transition-colors uppercase tracking-wide">
|
||||||
</a>
|
+ Nuevo Producto
|
||||||
|
</a>
|
||||||
|
@else
|
||||||
|
<span title="Acceso denegado" class="w-full xl:w-auto text-center px-5 py-3 text-sm font-bold text-gray-500 dark:text-neutral-500 bg-gray-300 dark:bg-neutral-800 border border-gray-400 dark:border-neutral-700 rounded-lg cursor-not-allowed pointer-events-none select-none uppercase tracking-wide">
|
||||||
|
+ Nuevo Producto
|
||||||
|
</span>
|
||||||
|
@endif
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="relative overflow-x-auto shadow-md sm:rounded-lg border border-gray-400 dark:border-neutral-800 w-full mb-4">
|
<div class="relative overflow-x-auto shadow-md sm:rounded-lg border border-gray-400 dark:border-neutral-800 w-full mb-4">
|
||||||
@@ -112,16 +118,30 @@
|
|||||||
<a href="{{ route('productos.show', $product) }}" title="Ver Mas" class="font-semibold p-2 text-green-700 dark:text-green-400 border-2 border-green-700 rounded-lg hover:bg-green-700 dark:hover:bg-green-600 dark:hover:border-green-600 hover:text-white dark:hover:text-white transition-colors">
|
<a href="{{ route('productos.show', $product) }}" title="Ver Mas" class="font-semibold p-2 text-green-700 dark:text-green-400 border-2 border-green-700 rounded-lg hover:bg-green-700 dark:hover:bg-green-600 dark:hover:border-green-600 hover:text-white dark:hover:text-white transition-colors">
|
||||||
<svg class="size-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24"><path stroke="currentColor" stroke-width="2" d="M21 12c0 1.2-4.03 6-9 6s-9-4.8-9-6c0-1.2 4.03-6 9-6s9 4.8 9 6Z"/><path stroke="currentColor" stroke-width="2" d="M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z"/></svg>
|
<svg class="size-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24"><path stroke="currentColor" stroke-width="2" d="M21 12c0 1.2-4.03 6-9 6s-9-4.8-9-6c0-1.2 4.03-6 9-6s9 4.8 9 6Z"/><path stroke="currentColor" stroke-width="2" d="M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z"/></svg>
|
||||||
</a>
|
</a>
|
||||||
<a href="{{ route('productos.edit', $product) }}" title="Editar" class="font-semibold p-2 text-blue-800 dark:text-blue-400 border-2 border-blue-800 rounded-lg hover:bg-blue-800 hover:text-white dark:hover:text-white transition-colors">
|
|
||||||
<svg class="size-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24"><path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m14.304 4.844 2.852 2.852M7 7H4a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h11a1 1 0 0 0 1-1v-4.5m2.409-9.91a2.017 2.017 0 0 1 0 2.853l-6.844 6.844L8 14l.713-3.565 6.844-6.844a2.015 2.015 0 0 1 2.852 0Z"/></svg>
|
@if(auth()->user()->role === 'admin')
|
||||||
</a>
|
<a href="{{ route('productos.edit', $product) }}" title="Editar" class="font-semibold p-2 text-blue-800 dark:text-blue-400 border-2 border-blue-800 rounded-lg hover:bg-blue-800 hover:text-white dark:hover:text-white transition-colors">
|
||||||
<form action="{{route('productos.destroy',$product)}}" method="post" class="delete-form">
|
<svg class="size-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24"><path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m14.304 4.844 2.852 2.852M7 7H4a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h11a1 1 0 0 0 1-1v-4.5m2.409-9.91a2.017 2.017 0 0 1 0 2.853l-6.844 6.844L8 14l.713-3.565 6.844-6.844a2.015 2.015 0 0 1 2.852 0Z"/></svg>
|
||||||
@csrf
|
</a>
|
||||||
@method('DELETE')
|
@else
|
||||||
<button title="Eliminar" type="submit" class="w-full sm:w-auto p-2 font-bold dark:font-medium text-red-600 dark:text-red-400 border-2 border-red-600 rounded-lg hover:bg-red-600 hover:text-white dark:hover:text-white transition-colors">
|
<span title="Acceso denegado" class="font-semibold p-2 text-gray-400 dark:text-neutral-500 border-2 border-gray-300 dark:border-neutral-700 rounded-lg bg-gray-100 dark:bg-neutral-800/30 cursor-not-allowed pointer-events-none select-none">
|
||||||
|
<svg class="size-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24"><path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m14.304 4.844 2.852 2.852M7 7H4a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h11a1 1 0 0 0 1-1v-4.5m2.409-9.91a2.017 2.017 0 0 1 0 2.853l-6.844 6.844L8 14l.713-3.565 6.844-6.844a2.015 2.015 0 0 1 2.852 0Z"/></svg>
|
||||||
|
</span>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
@if(auth()->user()->role === 'admin')
|
||||||
|
<form action="{{route('productos.destroy',$product)}}" method="post" class="delete-form">
|
||||||
|
@csrf
|
||||||
|
@method('DELETE')
|
||||||
|
<button title="Eliminar" type="submit" class="w-full sm:w-auto p-2 font-bold dark:font-medium text-red-600 dark:text-red-400 border-2 border-red-600 rounded-lg hover:bg-red-600 hover:text-white dark:hover:text-white transition-colors">
|
||||||
|
<svg class="size-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24"><path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 7h14m-9 3v8m4-8v8M10 3h4a1 1 0 0 1 1 1v3H9V4a1 1 0 0 1 1-1ZM6 7h12v13a1 1 0 0 1-1 1H7a1 1 0 0 1-1-1V7Z"/></svg>
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
@else
|
||||||
|
<span title="Acceso denegado" class="p-2 font-bold dark:font-medium text-gray-400 dark:text-neutral-500 border-2 border-gray-300 dark:border-neutral-700 rounded-lg bg-gray-100 dark:bg-neutral-800/30 cursor-not-allowed pointer-events-none select-none">
|
||||||
<svg class="size-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24"><path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 7h14m-9 3v8m4-8v8M10 3h4a1 1 0 0 1 1 1v3H9V4a1 1 0 0 1 1-1ZM6 7h12v13a1 1 0 0 1-1 1H7a1 1 0 0 1-1-1V7Z"/></svg>
|
<svg class="size-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24"><path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 7h14m-9 3v8m4-8v8M10 3h4a1 1 0 0 1 1 1v3H9V4a1 1 0 0 1 1-1ZM6 7h12v13a1 1 0 0 1-1 1H7a1 1 0 0 1-1-1V7Z"/></svg>
|
||||||
</button>
|
</span>
|
||||||
</form>
|
@endif
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
@@ -20,9 +20,15 @@
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<a href="{{ route('suppliers.create') }}" class="w-full md:w-auto text-center px-5 py-3 text-sm font-bold text-neon-lime dark:text-neutral-900 bg-neutral-950 dark:bg-neon-lime rounded-lg hover:bg-neutral-900/80 hover:dark:bg-[#b3e600] transition-colors uppercase tracking-wide">
|
@if(auth()->user()->role === 'admin')
|
||||||
+ Nuevo Proveedor
|
<a href="{{ route('suppliers.create') }}" class="w-full md:w-auto text-center px-5 py-3 text-sm font-bold text-neon-lime dark:text-neutral-900 bg-neutral-950 dark:bg-neon-lime rounded-lg hover:bg-neutral-900/80 hover:dark:bg-[#b3e600] transition-colors uppercase tracking-wide">
|
||||||
</a>
|
+ Nuevo Proveedor
|
||||||
|
</a>
|
||||||
|
@else
|
||||||
|
<span title="Acceso denegado" class="w-full md:w-auto text-center px-5 py-3 text-sm font-bold text-gray-500 dark:text-neutral-500 bg-gray-300 dark:bg-neutral-800 border border-gray-400 dark:border-neutral-700 rounded-lg cursor-not-allowed pointer-events-none select-none uppercase tracking-wide">
|
||||||
|
+ Nuevo Proveedor
|
||||||
|
</span>
|
||||||
|
@endif
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="relative overflow-x-auto shadow-md sm:rounded-lg border border-gray-400 dark:border-neutral-800 w-full">
|
<div class="relative overflow-x-auto shadow-md sm:rounded-lg border border-gray-400 dark:border-neutral-800 w-full">
|
||||||
@@ -60,25 +66,54 @@
|
|||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td class="px-6 py-4 text-right flex items-center justify-end gap-3">
|
<td class="px-6 py-4 text-right flex items-center justify-end gap-3">
|
||||||
|
<!-- Ver Más -->
|
||||||
|
<a href="{{ route('suppliers.show', $supplier) }}" title="Ver Más" class="font-semibold p-2 text-green-700 dark:text-green-400 border-2 border-green-700 rounded-lg hover:bg-green-700 dark:hover:bg-green-600 dark:hover:border-green-600 hover:text-white dark:hover:text-white transition-colors">
|
||||||
|
<svg class="size-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
|
||||||
|
<path stroke="currentColor" stroke-width="2" d="M21 12c0 1.2-4.03 6-9 6s-9-4.8-9-6c0-1.2 4.03-6 9-6s9 4.8 9 6Z"/>
|
||||||
|
<path stroke="currentColor" stroke-width="2" d="M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z"/>
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<!-- Hacer Pedido -->
|
||||||
<a href="{{ route('suppliers.order', $supplier) }}" title="Hacer Pedido" class="font-semibold p-2 text-green-600 dark:text-green-400 border-2 border-green-600 rounded-lg hover:bg-green-600 hover:text-white dark:hover:text-white transition-colors">
|
<a href="{{ route('suppliers.order', $supplier) }}" title="Hacer Pedido" class="font-semibold p-2 text-green-600 dark:text-green-400 border-2 border-green-600 rounded-lg hover:bg-green-600 hover:text-white dark:hover:text-white transition-colors">
|
||||||
<svg class="size-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 24 24">
|
<svg class="size-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 24 24">
|
||||||
<path fill-rule="evenodd" d="M12 4a8 8 0 0 0-6.895 12.06l.569 1.167-1.076 2.872 3.018-1.045 1.18.528A8 8 0 1 0 12 4Zm5.1 10.3c-.28-.14-1.65-.815-1.905-.909-.255-.094-.44-.14-.625.14-.185.28-.72 1.054-.882 1.265-.162.21-.324.234-.604.094-.28-.14-1.178-.435-2.246-1.385-.83-.739-1.39-1.65-1.552-1.93-.162-.28-.017-.432.123-.57.126-.125.28-.328.42-.493.14-.165.187-.28.28-.468.093-.188.047-.35-.023-.491-.07-.14-.625-1.508-.857-2.064-.225-.544-.454-.47-.625-.478-.162-.008-.348-.01-.533-.01-.185 0-.485.07-.74.35-.255.28-.972.95-.972 2.316 0 1.366.995 2.687 1.133 2.874.138.188 1.956 2.986 4.74 4.153.662.277 1.18.442 1.583.565.665.204 1.27.175 1.745.106.531-.077 1.65-.674 1.882-1.325.232-.651.232-1.21.162-1.325-.07-.116-.255-.186-.535-.326Z" clip-rule="evenodd"/>
|
<path fill-rule="evenodd" d="M12 4a8 8 0 0 0-6.895 12.06l.569 1.167-1.076 2.872 3.018-1.045 1.18.528A8 8 0 1 0 12 4Zm5.1 10.3c-.28-.14-1.65-.815-1.905-.909-.255-.094-.44-.14-.625.14-.185.28-.72 1.054-.882 1.265-.162.21-.324.234-.604.094-.28-.14-1.178-.435-2.246-1.385-.83-.739-1.39-1.65-1.552-1.93-.162-.28-.017-.432.123-.57.126-.125.28-.328.42-.493.14-.165.187-.28.28-.468.093-.188.047-.35-.023-.491-.07-.14-.625-1.508-.857-2.064-.225-.544-.454-.47-.625-.478-.162-.008-.348-.01-.533-.01-.185 0-.485.07-.74.35-.255.28-.972.95-.972 2.316 0 1.366.995 2.687 1.133 2.874.138.188 1.956 2.986 4.74 4.153.662.277 1.18.442 1.583.565.665.204 1.27.175 1.745.106.531-.077 1.65-.674 1.882-1.325.232-.651.232-1.21.162-1.325-.07-.116-.255-.186-.535-.326Z" clip-rule="evenodd"/>
|
||||||
</svg>
|
</svg>
|
||||||
</a>
|
</a>
|
||||||
<a href="{{ route('suppliers.edit', $supplier) }}" title="Editar" class="font-semibold p-2 text-blue-700 dark:text-blue-400 border-2 border-blue-700 rounded-lg hover:bg-blue-700 hover:text-white dark:hover:text-white transition-colors">
|
|
||||||
<svg class="size-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
|
<!-- Editar -->
|
||||||
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m14.304 4.844 2.852 2.852M7 7H4a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h11a1 1 0 0 0 1-1v-4.5m2.409-9.91a2.017 2.017 0 0 1 0 2.853l-6.844 6.844L8 14l.713-3.565 6.844-6.844a2.015 2.015 0 0 1 2.852 0Z"/>
|
@if(auth()->user()->role === 'admin')
|
||||||
</svg>
|
<a href="{{ route('suppliers.edit', $supplier) }}" title="Editar" class="font-semibold p-2 text-blue-800 dark:text-blue-400 border-2 border-blue-800 rounded-lg hover:bg-blue-800 hover:text-white dark:hover:text-white transition-colors">
|
||||||
</a>
|
<svg class="size-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
|
||||||
<form action="{{route('suppliers.destroy', $supplier)}}" method="post" class="delete-form">
|
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m14.304 4.844 2.852 2.852M7 7H4a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h11a1 1 0 0 0 1-1v-4.5m2.409-9.91a2.017 2.017 0 0 1 0 2.853l-6.844 6.844L8 14l.713-3.565 6.844-6.844a2.015 2.015 0 0 1 2.852 0Z"/>
|
||||||
@csrf
|
</svg>
|
||||||
@method('DELETE')
|
</a>
|
||||||
<button title="Eliminar" type="submit" class="w-full sm:w-auto p-2 font-bold dark:font-medium text-red-600 dark:text-red-400 border-2 border-red-600 rounded-lg hover:bg-red-600 hover:text-white dark:hover:text-white transition-colors">
|
@else
|
||||||
|
<span title="Acceso denegado" class="font-semibold p-2 text-gray-400 dark:text-neutral-500 border-2 border-gray-300 dark:border-neutral-700 rounded-lg bg-gray-100 dark:bg-neutral-800/30 cursor-not-allowed pointer-events-none select-none">
|
||||||
|
<svg class="size-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
|
||||||
|
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m14.304 4.844 2.852 2.852M7 7H4a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h11a1 1 0 0 0 1-1v-4.5m2.409-9.91a2.017 2.017 0 0 1 0 2.853l-6.844 6.844L8 14l.713-3.565 6.844-6.844a2.015 2.015 0 0 1 2.852 0Z"/>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
<!-- Eliminar -->
|
||||||
|
@if(auth()->user()->role === 'admin')
|
||||||
|
<form action="{{route('suppliers.destroy', $supplier)}}" method="post" class="delete-form">
|
||||||
|
@csrf
|
||||||
|
@method('DELETE')
|
||||||
|
<button title="Eliminar" type="submit" class="w-full sm:w-auto p-2 font-bold dark:font-medium text-red-600 dark:text-red-400 border-2 border-red-600 rounded-lg hover:bg-red-600 hover:text-white dark:hover:text-white transition-colors">
|
||||||
|
<svg class="size-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
|
||||||
|
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 7h14m-9 3v8m4-8v8M10 3h4a1 1 0 0 1 1 1v3H9V4a1 1 0 0 1 1-1ZM6 7h12v13a1 1 0 0 1-1 1H7a1 1 0 0 1-1-1V7Z"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
@else
|
||||||
|
<span title="Acceso denegado" class="p-2 font-bold dark:font-medium text-gray-400 dark:text-neutral-500 border-2 border-gray-300 dark:border-neutral-700 rounded-lg bg-gray-100 dark:bg-neutral-800/30 cursor-not-allowed pointer-events-none select-none">
|
||||||
<svg class="size-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
|
<svg class="size-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
|
||||||
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 7h14m-9 3v8m4-8v8M10 3h4a1 1 0 0 1 1 1v3H9V4a1 1 0 0 1 1-1ZM6 7h12v13a1 1 0 0 1-1 1H7a1 1 0 0 1-1-1V7Z"/>
|
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 7h14m-9 3v8m4-8v8M10 3h4a1 1 0 0 1 1 1v3H9V4a1 1 0 0 1 1-1ZM6 7h12v13a1 1 0 0 1-1 1H7a1 1 0 0 1-1-1V7Z"/>
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</span>
|
||||||
</form>
|
@endif
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
@@ -0,0 +1,67 @@
|
|||||||
|
<x-layout title="Lauck - Detalle de Proveedor">
|
||||||
|
<x-section-header subtitle="Proveedores" title="Detalle de " highlight="Proveedor" />
|
||||||
|
|
||||||
|
<div class="w-full max-w-4xl mx-auto bg-gray-200 dark:bg-panel-bg border border-neutral-400 dark:border-neutral-800 rounded-xl p-8 shadow-lg relative">
|
||||||
|
<div class="flex justify-between items-start mb-6">
|
||||||
|
<div>
|
||||||
|
<h3 class="text-2xl font-bold text-neutral-900 dark:text-white">{{ $supplier->name }}</h3>
|
||||||
|
<p class="text-sm text-gray-600 dark:text-gray-400">Registrado el: {{ $supplier->created_at->format('d/m/Y H:i') }}</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<a href="{{ route('suppliers.index') }}" class="text-sm font-bold text-gray-500 hover:text-white transition-colors">Volver al listado</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 bg-gray-300 dark:bg-neutral-800 p-6 rounded-lg border border-gray-400 dark:border-neutral-700">
|
||||||
|
<div>
|
||||||
|
<p class="text-xs text-gray-500 uppercase tracking-wider mb-1">Nombre / Razón Social</p>
|
||||||
|
<p class="text-lg font-bold text-neutral-900 dark:text-white">{{ $supplier->name }}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<p class="text-xs text-gray-500 uppercase tracking-wider mb-1">Teléfono / WhatsApp</p>
|
||||||
|
@if($supplier->phone)
|
||||||
|
<p class="text-lg font-bold text-neutral-900 dark:text-white font-mono">{{ $supplier->phone }}</p>
|
||||||
|
@else
|
||||||
|
<p class="text-lg text-gray-500 italic">No registrado</p>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<p class="text-xs text-gray-500 uppercase tracking-wider mb-1">Correo Electrónico</p>
|
||||||
|
@if($supplier->email)
|
||||||
|
<p class="text-base font-semibold text-neutral-900 dark:text-white font-mono">{{ $supplier->email }}</p>
|
||||||
|
@else
|
||||||
|
<p class="text-base text-gray-500 italic">No registrado</p>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<p class="text-xs text-gray-500 uppercase tracking-wider mb-1">Dirección</p>
|
||||||
|
@if($supplier->address)
|
||||||
|
<p class="text-base font-semibold text-neutral-900 dark:text-white">{{ $supplier->address }}</p>
|
||||||
|
@else
|
||||||
|
<p class="text-base text-gray-500 italic">No registrada</p>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-8 flex justify-end gap-4">
|
||||||
|
@if(auth()->user()->role === 'admin')
|
||||||
|
<a href="{{ route('suppliers.order', $supplier) }}" class="px-6 py-2.5 text-sm font-bold text-white bg-green-600 hover:bg-green-700 rounded-lg transition-colors">
|
||||||
|
Hacer Pedido
|
||||||
|
</a>
|
||||||
|
<a href="{{ route('suppliers.edit', $supplier) }}" class="px-6 py-2.5 text-sm font-bold text-white bg-blue-600 hover:bg-blue-700 rounded-lg transition-colors">
|
||||||
|
Editar Proveedor
|
||||||
|
</a>
|
||||||
|
@else
|
||||||
|
<span title="Acceso denegado" class="px-6 py-2.5 text-sm font-bold text-gray-400 bg-gray-300 dark:bg-neutral-800 border border-gray-400 dark:border-neutral-700 rounded-lg cursor-not-allowed pointer-events-none">
|
||||||
|
Hacer Pedido
|
||||||
|
</span>
|
||||||
|
<span title="Acceso denegado" class="px-6 py-2.5 text-sm font-bold text-gray-400 bg-gray-300 dark:bg-neutral-800 border border-gray-400 dark:border-neutral-700 rounded-lg cursor-not-allowed pointer-events-none">
|
||||||
|
Editar Proveedor
|
||||||
|
</span>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</x-layout>
|
||||||
@@ -17,6 +17,7 @@ use App\Http\Controllers\PasswordResetLinkController;
|
|||||||
use App\Http\Controllers\NewPasswordController;
|
use App\Http\Controllers\NewPasswordController;
|
||||||
use App\Http\Controllers\TagController;
|
use App\Http\Controllers\TagController;
|
||||||
use App\Http\Controllers\Admin\BackupController;
|
use App\Http\Controllers\Admin\BackupController;
|
||||||
|
use App\Http\Controllers\Admin\EmployeeController;
|
||||||
use App\Models\Product;
|
use App\Models\Product;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Illuminate\Support\Facades\Session;
|
use Illuminate\Support\Facades\Session;
|
||||||
@@ -90,5 +91,11 @@ Route::middleware(['auth'])->group(function () {
|
|||||||
Route::post('/backups/{filename}/restore', [BackupController::class, 'restore'])->name('backups.restore');
|
Route::post('/backups/{filename}/restore', [BackupController::class, 'restore'])->name('backups.restore');
|
||||||
Route::get('/backups/{filename}/download', [BackupController::class, 'download'])->name('backups.download');
|
Route::get('/backups/{filename}/download', [BackupController::class, 'download'])->name('backups.download');
|
||||||
Route::delete('/backups/{filename}', [BackupController::class, 'destroy'])->name('backups.destroy');
|
Route::delete('/backups/{filename}', [BackupController::class, 'destroy'])->name('backups.destroy');
|
||||||
|
|
||||||
|
// Gestión de Empleados
|
||||||
|
Route::get('/employees', [EmployeeController::class, 'index'])->name('employees.index');
|
||||||
|
Route::post('/employees', [EmployeeController::class, 'store'])->name('employees.store');
|
||||||
|
Route::put('/employees/{user}', [EmployeeController::class, 'update'])->name('employees.update');
|
||||||
|
Route::delete('/employees/{user}', [EmployeeController::class, 'destroy'])->name('employees.destroy');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user