mejoras en la gestión de proyectos y documentos: se añaden nuevos campos y validaciones para optimizar la organización y el seguimiento de los mismos.
This commit is contained in:
53
app/Http/Controllers/CompanyContactController.php
Normal file
53
app/Http/Controllers/CompanyContactController.php
Normal file
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\Company;
|
||||
use App\Models\User;
|
||||
|
||||
class CompanyContactController extends Controller
|
||||
{
|
||||
public function store(Request $request, Company $company)
|
||||
{
|
||||
$request->validate([
|
||||
'user_id' => 'required|exists:users,id',
|
||||
'position' => 'nullable|string|max:100'
|
||||
]);
|
||||
|
||||
// Evitar duplicados
|
||||
if (!$company->contacts()->where('user_id', $request->user_id)->exists()) {
|
||||
$company->contacts()->attach($request->user_id, [
|
||||
'position' => $request->position
|
||||
]);
|
||||
|
||||
return redirect()->back()
|
||||
->with('success', 'Contacto agregado exitosamente');
|
||||
}
|
||||
|
||||
return redirect()->back()
|
||||
->with('error', 'Este contacto ya está asociado a la empresa');
|
||||
}
|
||||
|
||||
public function update(Request $request, Company $company, User $contact)
|
||||
{
|
||||
$request->validate([
|
||||
'position' => 'nullable|string|max:100'
|
||||
]);
|
||||
|
||||
$company->contacts()->updateExistingPivot($contact->id, [
|
||||
'position' => $request->position
|
||||
]);
|
||||
|
||||
return redirect()->back()
|
||||
->with('success', 'Cargo del contacto actualizado');
|
||||
}
|
||||
|
||||
public function destroy(Company $company, User $contact)
|
||||
{
|
||||
$company->contacts()->detach($contact->id);
|
||||
|
||||
return redirect()->back()
|
||||
->with('success', 'Contacto eliminado de la empresa');
|
||||
}
|
||||
}
|
||||
143
app/Http/Controllers/CompanyController.php
Normal file
143
app/Http/Controllers/CompanyController.php
Normal file
@@ -0,0 +1,143 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Company;
|
||||
use App\Models\User;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class CompanyController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$companies = Company::orderBy('name')->paginate(10);
|
||||
return view('companies.index', compact('companies'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
return view('companies.form');
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'name' => 'required|string|max:255',
|
||||
'commercial_name' => 'required|string|max:255',
|
||||
'status' => 'required|in:active,closed',
|
||||
'address' => 'nullable|string|max:255',
|
||||
'postal_code' => 'nullable|string|max:10',
|
||||
'city' => 'nullable|string|max:100',
|
||||
'country' => 'nullable|string|max:100',
|
||||
'phone' => 'nullable|string|max:20',
|
||||
'email' => 'nullable|email|max:255',
|
||||
'cif' => 'nullable|string|max:20',
|
||||
'logo' => 'nullable|image|max:2048|mimes:jpg,jpeg,png,gif',
|
||||
]);
|
||||
|
||||
// Manejar la carga del logo
|
||||
if ($request->hasFile('logo')) {
|
||||
$validated['logo'] = $request->file('logo')->store('companies/logos', 'public');
|
||||
}
|
||||
|
||||
Company::create($validated);
|
||||
|
||||
return redirect()->route('companies.index')
|
||||
->with('success', 'Empresa creada exitosamente.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*/
|
||||
public function show(Company $company)
|
||||
{
|
||||
$company->load(['contacts' => function($query) {
|
||||
$query->withPivot('position');
|
||||
}]);
|
||||
|
||||
$contacts = $company->contacts()->paginate(5);
|
||||
$projects = $company->contacts()->paginate(5);//$company->projects()->paginate(5);
|
||||
$availableUsers = User::whereDoesntHave('companies', function($query) use ($company) {
|
||||
$query->where('company_id', $company->id);
|
||||
})->get();
|
||||
|
||||
return view('companies.show', compact('company', 'contacts', 'projects', 'availableUsers'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*/
|
||||
public function edit(Company $company)
|
||||
{
|
||||
|
||||
return view('companies.form', compact('company'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*/
|
||||
public function update(Request $request, Company $company)
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'name' => 'required|string|max:255',
|
||||
'commercial_name' => 'required|string|max:255',
|
||||
'status' => 'required|in:active,closed',
|
||||
'address' => 'nullable|string|max:255',
|
||||
'postal_code' => 'nullable|string|max:10',
|
||||
'city' => 'nullable|string|max:100',
|
||||
'country' => 'nullable|string|max:100',
|
||||
'phone' => 'nullable|string|max:20',
|
||||
'email' => 'nullable|email|max:255',
|
||||
'cif' => 'nullable|string|max:20',
|
||||
'logo' => 'nullable|image|max:2048|mimes:jpg,jpeg,png,gif',
|
||||
]);
|
||||
|
||||
// Manejar la actualización del logo
|
||||
if ($request->hasFile('logo')) {
|
||||
// Eliminar el logo anterior si existe
|
||||
if ($company->logo && Storage::disk('public')->exists($company->logo)) {
|
||||
Storage::disk('public')->delete($company->logo);
|
||||
}
|
||||
$validated['logo'] = $request->file('logo')->store('companies/logos', 'public');
|
||||
} elseif ($request->has('remove_logo')) {
|
||||
// Eliminar el logo si se seleccionó la opción de eliminar
|
||||
if ($company->logo && Storage::disk('public')->exists($company->logo)) {
|
||||
Storage::disk('public')->delete($company->logo);
|
||||
}
|
||||
$validated['logo'] = null;
|
||||
} else {
|
||||
// Mantener el logo existente
|
||||
$validated['logo'] = $company->logo;
|
||||
}
|
||||
|
||||
$company->update($validated);
|
||||
|
||||
return redirect()->route('companies.index')
|
||||
->with('success', 'Empresa actualizada exitosamente.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*/
|
||||
public function destroy(Company $company)
|
||||
{
|
||||
// Eliminar el logo si existe
|
||||
if ($company->logo && Storage::disk('public')->exists($company->logo)) {
|
||||
Storage::disk('public')->delete($company->logo);
|
||||
}
|
||||
|
||||
$company->delete();
|
||||
|
||||
return redirect()->route('companies.index')
|
||||
->with('success', 'Empresa eliminada exitosamente.');
|
||||
}
|
||||
}
|
||||
@@ -19,8 +19,8 @@ class ProjectController extends Controller
|
||||
public function index()
|
||||
{
|
||||
$projects = auth()->user()->hasRole('admin')
|
||||
? Project::get() // Todos los proyectos para admin
|
||||
: auth()->user()->projects()->latest()->get(); // Solo proyectos asignados
|
||||
? Project::get() // Todos los proyectos para admin
|
||||
: auth()->user()->projects()->latest()->get(); // Solo proyectos asignados
|
||||
|
||||
/*
|
||||
$projects = Project::whereHas('users', function($query) {
|
||||
@@ -43,6 +43,7 @@ class ProjectController extends Controller
|
||||
'project' => $project,
|
||||
'categories' => Category::orderBy('name')->get(),
|
||||
'users' => User::where('id', '!=', auth()->id())->get(),
|
||||
'companies' => \App\Models\Company::all(), // Pass companies to the view
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -65,9 +66,8 @@ class ProjectController extends Controller
|
||||
'start_date' => 'nullable|date',
|
||||
'deadline' => 'nullable|date|after:start_date',
|
||||
'categories' => 'nullable|array|exists:categories,id',
|
||||
//'categories' => 'required|array',
|
||||
//'categories.*' => 'exists:categories,id',
|
||||
'project_image_path' => 'nullable|string',
|
||||
'company_id' => 'required|exists:companies,id', // Validate company_id
|
||||
]);
|
||||
|
||||
|
||||
@@ -82,8 +82,8 @@ class ProjectController extends Controller
|
||||
$tempPath = $request->project_image_path;
|
||||
$newPath = 'images/projects/' . basename($tempPath);
|
||||
|
||||
Storage::move($tempPath, $newPath); // Mover el archivo
|
||||
$validated['project_image_path'] = $newPath; // Actualizar path
|
||||
Storage::move($tempPath, $newPath); // Mover el archivo
|
||||
$validated['project_image_path'] = $newPath; // Actualizar path
|
||||
}
|
||||
|
||||
// Crear el proyecto con todos los datos validados
|
||||
@@ -111,6 +111,7 @@ class ProjectController extends Controller
|
||||
'project' => $project,
|
||||
'categories' => Category::orderBy('name')->get(),
|
||||
'users' => User::where('id', '!=', auth()->id())->get(),
|
||||
'companies' => \App\Models\Company::all(), // Pass companies to the view
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -135,8 +136,31 @@ class ProjectController extends Controller
|
||||
public function update(Request $request, Project $project)
|
||||
{
|
||||
$this->authorize('update', $project);
|
||||
// Lógica de actualización
|
||||
$project->update($request->all());
|
||||
|
||||
$validated = $request->validate([
|
||||
'reference' => 'required|string|max:255',
|
||||
'name' => 'required|string|max:255',
|
||||
'description' => 'nullable|string',
|
||||
'status' => 'required|in:Activo,Inactivo',
|
||||
'address' => 'nullable|string|max:255',
|
||||
'province' => 'nullable|string|max:100',
|
||||
'country' => 'nullable|string|size:2',
|
||||
'postal_code' => 'nullable|string|max:10',
|
||||
'latitude' => 'required|numeric|between:-90,90',
|
||||
'longitude' => 'required|numeric|between:-180,180',
|
||||
'start_date' => 'nullable|date',
|
||||
'deadline' => 'nullable|date|after:start_date',
|
||||
'categories' => 'nullable|array|exists:categories,id',
|
||||
'project_image_path' => 'nullable|string',
|
||||
'company_id' => 'required|exists:companies,id', // Validate company_id
|
||||
]);
|
||||
|
||||
$project->update($validated);
|
||||
|
||||
if ($request->has('categories')) {
|
||||
$project->categories()->sync($request->categories);
|
||||
}
|
||||
|
||||
return redirect()->route('projects.show', $project)->with('success', 'Project updated successfully.');
|
||||
}
|
||||
|
||||
|
||||
@@ -65,6 +65,8 @@ class UserController extends Controller
|
||||
'email' => 'required|email|unique:users',
|
||||
'phone' => 'nullable|string|max:20',
|
||||
'address' => 'nullable|string|max:255',
|
||||
'user_type' => 'required|integer|in:0,1,2',
|
||||
'company_id' => 'nullable|exists:companies,id', // Si se usa una relación con empresas
|
||||
'profile_photo_path' => 'nullable|string' // Ruta de la imagen subida por Livewire
|
||||
]);
|
||||
|
||||
@@ -80,7 +82,9 @@ class UserController extends Controller
|
||||
'address' => $validated['address'],
|
||||
'access_start' => $validated['start_date'],
|
||||
'access_end' => $validated['end_date'],
|
||||
'is_active' => true,
|
||||
'is_active' => $validated['is_active'] ?? false, // Por defecto, inactivo
|
||||
'user_type' => $validated['user_type'] ?? 0, // 0: Usuario, 1: Administrador, 2: Super Admin
|
||||
'company_id' => $validated['company_id'] ?? null, // Si se usa una relación con empresas
|
||||
'profile_photo_path' => $validated['profile_photo_path'] ?? null
|
||||
]);
|
||||
|
||||
|
||||
65
app/Models/Company.php
Normal file
65
app/Models/Company.php
Normal file
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
|
||||
class Company extends Model
|
||||
{
|
||||
use HasFactory, SoftDeletes;
|
||||
|
||||
protected $fillable = [
|
||||
'name',
|
||||
'commercial_name',
|
||||
'status',
|
||||
'address',
|
||||
'postal_code',
|
||||
'city',
|
||||
'country',
|
||||
'phone',
|
||||
'email',
|
||||
'cif',
|
||||
'logo'
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'created_at' => 'datetime:d/m/Y H:i',
|
||||
'updated_at' => 'datetime:d/m/Y H:i',
|
||||
];
|
||||
|
||||
public function getStatusColorAttribute()
|
||||
{
|
||||
return [
|
||||
'active' => 'bg-green-100 text-green-800',
|
||||
'closed' => 'bg-red-100 text-red-800',
|
||||
][$this->status] ?? 'bg-gray-100 text-gray-800';
|
||||
}
|
||||
|
||||
public function getStatusTextAttribute()
|
||||
{
|
||||
return [
|
||||
'active' => 'Activo',
|
||||
'closed' => 'Cerrado',
|
||||
][$this->status] ?? 'Desconocido';
|
||||
}
|
||||
|
||||
public function contacts(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(User::class, 'company_contacts')
|
||||
->withPivot('position')
|
||||
->withTimestamps();
|
||||
}
|
||||
|
||||
public function users()
|
||||
{
|
||||
return $this->hasMany(User::class);
|
||||
}
|
||||
|
||||
public function projects()
|
||||
{
|
||||
return $this->hasMany(Project::class);
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ use Illuminate\Database\Eloquent\Model;
|
||||
class Project extends Model
|
||||
{
|
||||
protected $fillable = [
|
||||
'reference',
|
||||
'name',
|
||||
'description',
|
||||
'creator_id',
|
||||
@@ -22,6 +23,7 @@ class Project extends Model
|
||||
'icon',
|
||||
'start_date',
|
||||
'deadline',
|
||||
'company_id',
|
||||
// Agrega cualquier otro campo nuevo aquí
|
||||
];
|
||||
|
||||
@@ -81,5 +83,8 @@ class Project extends Model
|
||||
return $this->belongsToMany(Category::class);
|
||||
}
|
||||
|
||||
|
||||
public function company()
|
||||
{
|
||||
return $this->belongsTo(Company::class);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ use Illuminate\Notifications\Notifiable;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Str;
|
||||
use Spatie\Permission\Traits\HasRoles;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
|
||||
class User extends Authenticatable
|
||||
{
|
||||
@@ -110,4 +111,16 @@ class User extends Authenticatable
|
||||
return $this->profile_photo ? Storage::url($this->profile_photo) : asset('images/default-user.png');
|
||||
}
|
||||
|
||||
public function companies(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(Company::class, 'company_contacts')
|
||||
->withPivot('position')
|
||||
->withTimestamps();
|
||||
}
|
||||
|
||||
public function company()
|
||||
{
|
||||
return $this->belongsTo(Company::class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -21,6 +21,10 @@ class Accordion extends Component
|
||||
*/
|
||||
public function render(): View|Closure|string
|
||||
{
|
||||
return view('components.accordion');
|
||||
return <<<'blade'
|
||||
<div>
|
||||
<!-- Simplicity is the essence of happiness. - Cedric Bledsoe -->
|
||||
</div>
|
||||
blade;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('companies', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('name'); // Nombre legal
|
||||
$table->string('commercial_name'); // Apodo comercial
|
||||
$table->enum('status', ['active', 'closed'])->default('active');
|
||||
$table->string('address')->nullable();
|
||||
$table->string('postal_code')->nullable();
|
||||
$table->string('city')->nullable();
|
||||
$table->string('country')->nullable();
|
||||
$table->string('phone')->nullable();
|
||||
$table->string('email')->nullable();
|
||||
$table->string('cif')->nullable(); // Código de identificación fiscal
|
||||
$table->string('logo')->nullable(); // Ruta del logo
|
||||
$table->timestamps();
|
||||
$table->softDeletes();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('companies');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('company_contacts', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('company_id')->constrained()->onDelete('cascade');
|
||||
$table->foreignId('user_id')->constrained()->onDelete('cascade');
|
||||
$table->string('position')->nullable();
|
||||
$table->timestamps();
|
||||
|
||||
$table->unique(['company_id', 'user_id']);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('company_contacts');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
// 1. Corregir tipo de dato para 'type' (boolean en lugar de boolval)
|
||||
$table->unsignedSmallInteger('user_type')->default(false)->after('remember_token');
|
||||
|
||||
// 2. Agregar company_id como nullable con constrained correcto
|
||||
$table->foreignId('company_id')
|
||||
->nullable()
|
||||
->after('user_type')
|
||||
->constrained('companies'); // Especificar tabla explícitamente
|
||||
});
|
||||
|
||||
Schema::table('projects', function (Blueprint $table) {
|
||||
$table->foreignId('company_id')
|
||||
->constrained('companies');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
// 5. Eliminar restricción de clave foránea primero
|
||||
$table->dropForeign(['company_id']);
|
||||
|
||||
// 6. Eliminar columnas en orden inverso
|
||||
$table->dropColumn('company_id');
|
||||
$table->dropColumn('user_type');
|
||||
});
|
||||
|
||||
Schema::table('projects', function (Blueprint $table) {
|
||||
// 7. Eliminar restricción antes de la columna
|
||||
$table->dropForeign(['company_id']);
|
||||
$table->dropColumn('company_id');
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -896,7 +896,7 @@ const defaultOptions = {
|
||||
};
|
||||
{
|
||||
defaultOptions.defaultUrl = {
|
||||
value: "./compressed.tracemonkey-pldi-09.pdf",
|
||||
value: "compressed.tracemonkey-pldi-09.pdf",
|
||||
kind: OptionKind.VIEWER
|
||||
};
|
||||
defaultOptions.sandboxBundleSrc = {
|
||||
|
||||
286
resources/views/companies/form.blade.php
Normal file
286
resources/views/companies/form.blade.php
Normal file
@@ -0,0 +1,286 @@
|
||||
@extends('companies.layout')
|
||||
|
||||
@section('company-content')
|
||||
|
||||
|
||||
<!-- Header -->
|
||||
<div class="mb-8">
|
||||
<div class="flex items-center gap-4 mb-4">
|
||||
<flux:icon.building-office class="size-10" variant="solid"/>
|
||||
<h1 class="text-3xl font-bold text-gray-800">
|
||||
{{ (isset($company) && $company->id) ? 'Editar Empresa' : 'Nueva Empresa' }}
|
||||
</h1>
|
||||
</div>
|
||||
<p class="text-gray-600 text-sm">
|
||||
@if(isset($user) && $user->id)
|
||||
Modifique los campos necesarios para actualizar la información del usuario.
|
||||
@else
|
||||
Complete todos los campos obligatorios para registrar un nuevo usuario en el sistema.
|
||||
@endisset
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<form action="{{ isset($company) ? route('companies.update', $company) : route('companies.store') }}"
|
||||
method="POST"
|
||||
enctype="multipart/form-data"
|
||||
class="p-6">
|
||||
@csrf
|
||||
@if(isset($company))
|
||||
@method('PUT')
|
||||
@endif
|
||||
|
||||
<!-- Separador -->
|
||||
<div class="relative">
|
||||
<div class="absolute inset-0 flex items-center">
|
||||
<div class="w-full border-t border-gray-300"></div>
|
||||
</div>
|
||||
<div class="relative flex justify-center">
|
||||
<span class="px-4 bg-white text-sm text-gray-500">Datos Personales</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Datos Personales -->
|
||||
<div class="bg-white py-6">
|
||||
<table class="w-full">
|
||||
<tbody class="space-y-4">
|
||||
<!-- Nombre -->
|
||||
<tr>
|
||||
<td class="py-2 pr-4">
|
||||
<label class="block text-sm font-bold text-gray-700">
|
||||
Nombre
|
||||
</label>
|
||||
</td>
|
||||
<td class="py-2">
|
||||
<input type="text" name="name" id="name"
|
||||
value="{{ old('name', $company->name ?? '') }}"
|
||||
required
|
||||
class="w-[500px] border-b-1 border-gray-300 focus:border-blue-500 focus:outline-none"
|
||||
autofocus>
|
||||
@error('name')
|
||||
<p class="mt-1 text-sm text-red-600">{{ $message }}</p>
|
||||
@enderror
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- Nombre comercial -->
|
||||
<tr>
|
||||
<td class="py-2 pr-4">
|
||||
<label class="block text-sm text-gray-700">
|
||||
Nombre Comercial
|
||||
</label>
|
||||
</td>
|
||||
<td class="py-2">
|
||||
<input type="text" name="commercial_name" id="commercial_name"
|
||||
value="{{ old('commercial_name', $company->commercial_name ?? '') }}"
|
||||
required
|
||||
class="w-[500px] border-b-1 border-gray-300 focus:border-blue-500 focus:outline-none">
|
||||
@error('commercial_name')
|
||||
<p class="mt-1 text-sm text-red-600">{{ $message }}</p>
|
||||
@enderror
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- CIF -->
|
||||
<tr>
|
||||
<td class="py-2 pr-4">
|
||||
<label class="block text-sm text-gray-700">
|
||||
CIF
|
||||
</label>
|
||||
</td>
|
||||
<td class="py-2">
|
||||
<input type="text" name="cif" id="cif"
|
||||
value="{{ old('cif', $company->cif ?? '') }}"
|
||||
class="w-[250px] border-b-1 border-gray-300 focus:border-blue-500 focus:outline-none">
|
||||
@error('cif')
|
||||
<p class="mt-1 text-sm text-red-600">{{ $message }}</p>
|
||||
@enderror
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- Estado -->
|
||||
<tr>
|
||||
<td class="py-2 pr-4">
|
||||
<label class="block text-sm text-gray-700">
|
||||
Estado
|
||||
</label>
|
||||
</td>
|
||||
<td class="py-2">
|
||||
<select name="status" id="status"
|
||||
required
|
||||
class="w-[100px] border-b-1 border-gray-300 focus:border-blue-500 focus:outline-none">
|
||||
<option value="active" {{ (old('status', $company->status ?? '') == 'active' ? 'selected' : '') }}>
|
||||
Activo
|
||||
</option>
|
||||
<option value="closed" {{ (old('status', $company->status ?? '') == 'closed' ? 'selected' : '') }}>
|
||||
Cerrado
|
||||
</option>
|
||||
</select>
|
||||
@error('status')
|
||||
<p class="mt-1 text-sm text-red-600">{{ $message }}</p>
|
||||
@enderror
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Separador -->
|
||||
<div class="relative">
|
||||
<div class="absolute inset-0 flex items-center">
|
||||
<div class="w-full border-t border-gray-300"></div>
|
||||
</div>
|
||||
<div class="relative flex justify-center">
|
||||
<span class="px-4 bg-white text-sm text-gray-500">Configuración de acceso</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Datos Personales -->
|
||||
<div class="bg-white py-6">
|
||||
<table class="w-full">
|
||||
<tbody class="space-y-4">
|
||||
<!-- Dirección -->
|
||||
<tr>
|
||||
<td class="py-2 pr-4">
|
||||
<label class="block text-sm font-bold text-gray-700">
|
||||
Dirección
|
||||
</label>
|
||||
</td>
|
||||
<td class="py-2">
|
||||
<input type="text" name="address" id="address"
|
||||
value="{{ old('address', $company->address ?? '') }}"
|
||||
class="w-full border-b-1 border-gray-300 focus:border-blue-500 focus:outline-none">
|
||||
@error('address')
|
||||
<p class="mt-1 text-sm text-red-600">{{ $message }}</p>
|
||||
@enderror
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- Código postal -->
|
||||
<tr>
|
||||
<td class="py-2 pr-4">
|
||||
<label class="block text-sm text-gray-700">
|
||||
Código Postal
|
||||
</label>
|
||||
</td>
|
||||
<td class="py-2">
|
||||
<input type="text" name="postal_code" id="postal_code"
|
||||
value="{{ old('postal_code', $company->postal_code ?? '') }}"
|
||||
class="w-[250px] border-b-1 border-gray-300 focus:border-blue-500 focus:outline-none">
|
||||
@error('postal_code')
|
||||
<p class="mt-1 text-sm text-red-600">{{ $message }}</p>
|
||||
@enderror
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- Ciudad -->
|
||||
<tr>
|
||||
<td class="py-2 pr-4">
|
||||
<label class="block text-sm text-gray-700">
|
||||
Ciudad
|
||||
</label>
|
||||
</td>
|
||||
<td class="py-2">
|
||||
<input type="text" name="city" id="city"
|
||||
value="{{ old('city', $company->city ?? '') }}"
|
||||
class="w-[250px] border-b-1 border-gray-300 focus:border-blue-500 focus:outline-none">
|
||||
@error('city')
|
||||
<p class="mt-1 text-sm text-red-600">{{ $message }}</p>
|
||||
@enderror
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- Estado -->
|
||||
<tr>
|
||||
<td class="py-2 pr-4">
|
||||
<label class="block text-sm text-gray-700">
|
||||
Pais
|
||||
</label>
|
||||
</td>
|
||||
<td class="py-2">
|
||||
<input type="text" name="country" id="country"
|
||||
value="{{ old('country', $company->country ?? '') }}"
|
||||
class="w-[250px] border-b-1 border-gray-300 focus:border-blue-500 focus:outline-none">
|
||||
@error('country')
|
||||
<p class="mt-1 text-sm text-red-600">{{ $message }}</p>
|
||||
@enderror
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- Teléfono -->
|
||||
<tr>
|
||||
<td class="py-2 pr-4">
|
||||
<label class="block text-sm text-gray-700">
|
||||
Teléfono
|
||||
</label>
|
||||
</td>
|
||||
<td class="py-2">
|
||||
<input type="text" name="phone" id="phone"
|
||||
value="{{ old('phone', $company->phone ?? '') }}"
|
||||
class="w-[250px] border-b-1 border-gray-300 focus:border-blue-500 focus:outline-none">
|
||||
@error('phone')
|
||||
<p class="mt-1 text-sm text-red-600">{{ $message }}</p>
|
||||
@enderror
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- email -->
|
||||
<tr>
|
||||
<td class="py-2 pr-4">
|
||||
<label class="block text-sm text-gray-700">
|
||||
email
|
||||
</label>
|
||||
</td>
|
||||
<td class="py-2">
|
||||
<input type="email" name="email" id="email"
|
||||
value="{{ old('email', $company->email ?? '') }}"
|
||||
class="w-[250px] border-b-1 border-gray-300 focus:border-blue-500 focus:outline-none">
|
||||
@error('email')
|
||||
<p class="mt-1 text-sm text-red-600">{{ $message }}</p>
|
||||
@enderror
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- logo -->
|
||||
<tr>
|
||||
<td class="py-2 pr-4">
|
||||
<label class="block text-sm text-gray-700">
|
||||
Logo
|
||||
</label>
|
||||
</td>
|
||||
<td class="py-2">
|
||||
<input type="file" name="logo" id="logo"
|
||||
class="mt-1 block w-full text-sm text-gray-500 file:mr-4 file:py-2 file:px-4 file:rounded-md file:border-0 file:text-sm file:font-semibold file:bg-blue-50 file:text-blue-700 hover:file:bg-blue-100">
|
||||
@error('logo')
|
||||
<p class="mt-1 text-sm text-red-600">{{ $message }}</p>
|
||||
@enderror
|
||||
|
||||
@if(isset($company) && $company->logo)
|
||||
<div class="mt-2 flex items-center">
|
||||
<img src="{{ Storage::disk('public')->url($company->logo) }}"
|
||||
alt="Logo actual"
|
||||
class="h-16 w-16 rounded object-contain border">
|
||||
<div class="ml-4">
|
||||
<label class="flex items-center">
|
||||
<input type="checkbox" name="remove_logo" class="rounded">
|
||||
<span class="ml-2 text-sm text-gray-600">Eliminar logo</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-end space-x-3 pt-6 border-t">
|
||||
<a href="{{ route('companies.index') }}" class="btn btn-secondary">
|
||||
Cancelar
|
||||
</a>
|
||||
<button type="submit" class="btn btn-primary">
|
||||
{{ isset($company) ? 'Actualizar Empresa' : 'Crear Empresa' }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
@endsection
|
||||
91
resources/views/companies/index.blade.php
Normal file
91
resources/views/companies/index.blade.php
Normal file
@@ -0,0 +1,91 @@
|
||||
@extends('companies.layout')
|
||||
|
||||
@section('company-content')
|
||||
<div class="bg-white rounded-lg shadow overflow-hidden">
|
||||
<div class="px-6 py-4 border-b flex justify-between items-center">
|
||||
<h3 class="text-lg font-medium text-gray-900">Listado de Empresas</h3>
|
||||
<a href="{{ route('companies.create') }}" class="btn btn-primary">
|
||||
<flux:icon.plus class="w-4 h-4 mr-1"/> Nueva Empresa
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="overflow-x-auto">
|
||||
<table class="min-w-full divide-y divide-gray-200">
|
||||
<thead class="bg-gray-50">
|
||||
<tr>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Nombre</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Nombre Comercial</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Estado</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">CIF</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Acciones</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="bg-white divide-y divide-gray-200">
|
||||
@forelse($companies as $company)
|
||||
<tr class="hover:bg-gray-50">
|
||||
<td class="px-6 py-4 whitespace-nowrap">
|
||||
<div class="flex items-center">
|
||||
@if($company->logo)
|
||||
<img src="{{ Storage::disk('public')->url($company->logo) }}"
|
||||
alt="{{ $company->name }}"
|
||||
class="w-10 h-10 rounded-full object-cover mr-3">
|
||||
@else
|
||||
<div class="bg-gray-200 border-2 border-dashed rounded-xl w-10 h-10 mr-3"></div>
|
||||
@endif
|
||||
<div>
|
||||
<div class="font-medium text-gray-900">{{ $company->name }}</div>
|
||||
<div class="text-sm text-gray-500">{{ $company->email }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-gray-500">
|
||||
{{ $company->commercial_name }}
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap">
|
||||
<span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full {{ $company->status_color }}">
|
||||
{{ $company->status_text }}
|
||||
</span>
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-gray-500">
|
||||
{{ $company->cif }}
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium">
|
||||
<div class="flex space-x-2">
|
||||
<a href="{{ route('companies.show', $company) }}"
|
||||
class="text-blue-600 hover:text-blue-900"
|
||||
title="Ver detalles">
|
||||
<flux:icon.eye class="w-5 h-5"/>
|
||||
</a>
|
||||
<a href="{{ route('companies.edit', $company) }}"
|
||||
class="text-yellow-600 hover:text-yellow-900"
|
||||
title="Editar">
|
||||
<flux:icon.pencil class="w-5 h-5"/>
|
||||
</a>
|
||||
<form action="{{ route('companies.destroy', $company) }}" method="POST"
|
||||
onsubmit="return confirm('¿Estás seguro de eliminar esta empresa?')">
|
||||
@csrf
|
||||
@method('DELETE')
|
||||
<button type="submit" class="text-red-600 hover:text-red-900"
|
||||
title="Eliminar">
|
||||
<flux:icon.trash class="w-5 h-5"/>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
@empty
|
||||
<tr>
|
||||
<td colspan="5" class="px-6 py-4 text-center text-gray-500">
|
||||
No se han encontrado empresas
|
||||
</td>
|
||||
</tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="px-6 py-4 border-t">
|
||||
{{ $companies->links() }}
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
39
resources/views/companies/layout.blade.php
Normal file
39
resources/views/companies/layout.blade.php
Normal file
@@ -0,0 +1,39 @@
|
||||
<x-layouts.app :title="__('Companies')" :showSidebar={{ $showSidebar }}>
|
||||
|
||||
@if(session('success'))
|
||||
<div class="mb-4 p-4 bg-green-100 text-green-700 rounded-lg">
|
||||
{{ session('success') }}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@yield('company-content')
|
||||
|
||||
|
||||
<!-- Sidebar menu -->
|
||||
@push('sidebar-menu')
|
||||
<flux:navlist variant="outline">
|
||||
<!-- Sección de Usuarios -->
|
||||
<flux:navlist.group :heading="__('Empresas')">
|
||||
<flux:navlist.item
|
||||
icon="building-office-2"
|
||||
:href="route('companies.index')"
|
||||
wire:navigate
|
||||
>
|
||||
{{ __('List companies') }}
|
||||
</flux:navlist.item>
|
||||
|
||||
<flux:navlist.item
|
||||
icon="building-office"
|
||||
:href="route('companies.create')"
|
||||
wire:navigate
|
||||
>
|
||||
{{ __('Create new company') }}
|
||||
</flux:navlist.item>
|
||||
</flux:navlist.group>
|
||||
|
||||
<flux:separator />
|
||||
</flux:navlist>
|
||||
|
||||
@endpush
|
||||
|
||||
</x-layouts.app>
|
||||
362
resources/views/companies/show.blade.php
Normal file
362
resources/views/companies/show.blade.php
Normal file
@@ -0,0 +1,362 @@
|
||||
@extends('companies.layout')
|
||||
|
||||
@section('company-content')
|
||||
|
||||
<!-- Header Section -->
|
||||
<div class="bg-white p-6 mb-6 flex content-start justify-between">
|
||||
<!-- User Info Left -->
|
||||
<div class="flex content-start space-x-6">
|
||||
<!-- User Photo -->
|
||||
<flux:avatar
|
||||
class="w-24 h-24 rounded-lg shadow-lg object-cover border-2 border-gray-600"
|
||||
name="{{ $company->name }}"
|
||||
src="{{ $company->logo ? Storage::disk('public')->url($company->logo) : null }}" />
|
||||
|
||||
<!-- User Details -->
|
||||
<div>
|
||||
<h1 class="text-2xl font-bold text-gray-700">
|
||||
{{ $company->name }}
|
||||
</h1>
|
||||
|
||||
<!-- Contact Info -->
|
||||
<div class="mt-2 space-y-1">
|
||||
@if($company->commercial_name )
|
||||
<div class="flex items-center text-gray-600">
|
||||
<p class="text-sm text-gray-700">
|
||||
{{ $company->commercial_name }}
|
||||
</p>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if($company->address )
|
||||
<div class="flex items-center text-gray-600">
|
||||
<flux:icon.map-pin />
|
||||
<p class="text-sm text-gray-700">
|
||||
{{ $company->address }}
|
||||
</p>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if($company->email)
|
||||
<div class="flex items-center text-gray-600">
|
||||
<svg class="w-5 h-5 mr-2" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M20 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 14H4V8l8 5 8-5v10zm-8-7L4 6h16l-8 5z"/>
|
||||
</svg>
|
||||
<a href="mailto:{{ $company->email }}" class="hover:text-blue-600">
|
||||
{{ $company->email }}
|
||||
</a>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if($company->phone)
|
||||
<div class="flex items-center text-gray-600">
|
||||
<svg class="w-5 h-5 mr-2" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M6.62 10.79c1.44 2.83 3.76 5.14 6.59 6.59l2.2-2.2c.27-.27.67-.36 1.02-.24 1.12.37 2.33.57 3.57.57.55 0 1 .45 1 1V20c0 .55-.45 1-1 1-9.39 0-17-7.61-17-17 0-.55.45-1 1-1h3.5c.55 0 1 .45 1 1 0 1.25.2 2.45.57 3.57.11.35.03.74-.25 1.02l-2.2 2.2z"/>
|
||||
</svg>
|
||||
<a href="tel:{{ $company->phone }}" class="hover:text-blue-600">
|
||||
{{ $company->phone }}
|
||||
</a>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Right Section -->
|
||||
<div class="flex flex-col items-end space-y-4">
|
||||
<!-- Navigation Toolbar -->
|
||||
<div class="flex space-x-2">
|
||||
|
||||
<flux:button
|
||||
href="{{ route('companies.index') }}"
|
||||
icon:trailing="arrow-uturn-left"
|
||||
variant="ghost"
|
||||
>
|
||||
</flux:button>
|
||||
|
||||
@if(true)
|
||||
<flux:button
|
||||
href="{{ route('companies.show', 1) }}"
|
||||
icon:trailing="chevron-left"
|
||||
variant="ghost"
|
||||
>
|
||||
</flux:button>
|
||||
@endif
|
||||
|
||||
@if(true)
|
||||
<flux:button
|
||||
href="{{ route('companies.show', 2) }}"
|
||||
icon:trailing="chevron-right"
|
||||
variant="ghost"
|
||||
>
|
||||
</flux:button>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<!-- Status Badge -->
|
||||
<span class="px-4 py-2 w-30 rounded-lg text-sm text-center font-semibold {{ $company->status_color }}">
|
||||
{{ $company->status_text}}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Contend: -->
|
||||
<div x-data="{ activeTab: 'info' }" class="bg-white rounded-lg shadow-md border-1">
|
||||
<!-- Tab Headers -->
|
||||
<div class="border-b border-gray-200">
|
||||
<nav class="flex space-x-8 px-6">
|
||||
<button @click="activeTab = 'info'"
|
||||
:class="activeTab === 'info' ? 'border-blue-500 text-blue-600' : 'border-transparent text-gray-500 hover:text-gray-700'"
|
||||
class="py-4 px-1 border-b-2 font-medium">
|
||||
Empresa
|
||||
</button>
|
||||
|
||||
<button @click="activeTab = 'contacts'"
|
||||
:class="activeTab === 'contacts' ? 'border-blue-500 text-blue-600' : 'border-transparent text-gray-500 hover:text-gray-700'"
|
||||
class="py-4 px-1 border-b-2 font-medium">
|
||||
Contactos
|
||||
</button>
|
||||
|
||||
<button @click="activeTab = 'projects'"
|
||||
:class="activeTab === 'projects' ? 'border-blue-500 text-blue-600' : 'border-transparent text-gray-500 hover:text-gray-700'"
|
||||
class="py-4 px-1 border-b-2 font-medium">
|
||||
Proyectos
|
||||
</button>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
<div class="p-6">
|
||||
<!-- Info Tab -->
|
||||
<div x-show="activeTab === 'info'">
|
||||
<div class="overflow-x-auto">
|
||||
<table class="min-w-full divide-y divide-gray-200">
|
||||
<tbody class="bg-white divide-y divide-gray-200">
|
||||
@foreach(['name' => 'Nombre', 'commercial_name' => 'Nombre Comercial', 'cif' => 'CIF/NIF', 'created_at' => 'Creado el', 'updated_at' => 'Última actualización'] as $field => $label)
|
||||
<tr>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">{{ $label }}</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
||||
{{ $company->$field ?? 'N/A' }}
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<!-- Action Buttons -->
|
||||
<div class="mt-6 flex justify-end space-x-4">
|
||||
<a href="{{ route('companies.edit', $company) }}"
|
||||
class="w-[150px] px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg flex items-center justify-center">
|
||||
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z"/>
|
||||
</svg>
|
||||
Editar
|
||||
</a>
|
||||
|
||||
{{-- Formulario de Edición --}}
|
||||
<form method="POST" action="{{ route('users.update', $company) }}">
|
||||
@csrf
|
||||
@method('PUT') <!-- Important! -->
|
||||
<button type="submit"
|
||||
class="w-[150px] px-4 py-2 bg-yellow-500 hover:bg-yellow-600 text-white rounded-lg flex items-center justify-center">
|
||||
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M18.364 18.364A9 9 0 005.636 5.636m12.728 12.728A9 9 0 015.636 5.636m12.728 12.728L5.636 5.636"/>
|
||||
</svg>
|
||||
{{ $company->is_active ? 'Desactivar' : 'Activar' }}
|
||||
</button>
|
||||
</form>
|
||||
|
||||
{{-- Formulario de Eliminación --}}
|
||||
<form method="POST" action="{{ route('users.destroy', $company) }}">
|
||||
@csrf
|
||||
@method('DELETE') <!-- Important! -->
|
||||
<button type="submit"
|
||||
onclick="return confirm('¿Estás seguro de querer eliminar este usuario?')"
|
||||
class="px-4 py-2 w-[150px] bg-red-600 hover:bg-red-700 text-white rounded-lg flex items-center justify-center">
|
||||
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"/>
|
||||
</svg>
|
||||
Eliminar
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Pestaña de Contactos -->
|
||||
<div x-show="activeTab === 'contacts'">
|
||||
<div class="flex justify-between items-center mb-4">
|
||||
<h4 class="text-lg font-medium text-gray-900">Contactos de la Empresa</h4>
|
||||
<button @click="openAddContactModal()" class="btn btn-primary btn-sm">
|
||||
<flux:icon.plus class="w-4 h-4 mr-1" /> Nuevo Contacto
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@if($contacts->isEmpty())
|
||||
<div class="bg-gray-50 rounded-lg p-8 text-center">
|
||||
<p class="text-gray-500">No hay contactos asociados a esta empresa.</p>
|
||||
<button @click="openAddContactModal()" class="mt-4 btn btn-primary">
|
||||
Agregar Contacto
|
||||
</button>
|
||||
</div>
|
||||
@else
|
||||
<div class="overflow-x-auto">
|
||||
<table class="min-w-full divide-y divide-gray-200">
|
||||
<thead class="bg-gray-50">
|
||||
<tr>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Nombre</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Cargo</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Email</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Teléfono</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Acciones</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="bg-white divide-y divide-gray-200">
|
||||
@foreach($contacts as $contact)
|
||||
<tr>
|
||||
<td class="px-6 py-4 whitespace-nowrap">
|
||||
<div class="flex items-center">
|
||||
<div class="flex-shrink-0 h-10 w-10">
|
||||
<img class="h-10 w-10 rounded-full"
|
||||
src="{{ $contact->profile_photo_url }}"
|
||||
alt="{{ $contact->name }}">
|
||||
</div>
|
||||
<div class="ml-4">
|
||||
<div class="text-sm font-medium text-gray-900">{{ $contact->name }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
||||
{{ $contact->pivot->position }}
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
||||
{{ $contact->email }}
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
||||
{{ $contact->phone ?? 'N/A' }}
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium">
|
||||
<button @click="editContact({{ $contact->id }})"
|
||||
class="text-yellow-600 hover:text-yellow-900 mr-3">
|
||||
<flux:icon.pencil class="w-5 h-5" />
|
||||
</button>
|
||||
<button @click="confirmDeleteContact({{ $contact->id }})"
|
||||
class="text-red-600 hover:text-red-900">
|
||||
<flux:icon.trash class="w-5 h-5" />
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="mt-4">
|
||||
{{ $contacts->links() }}
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<!-- Pestaña de Proyectos -->
|
||||
<div x-show="activeTab === 'projects'">
|
||||
<div class="flex justify-between items-center mb-4">
|
||||
<h4 class="text-lg font-medium text-gray-900">Proyectos de la Empresa</h4>
|
||||
<a href="{{ route('projects.create', ['company_id' => $company->id]) }}"
|
||||
class="btn btn-primary btn-sm">
|
||||
<flux:icon.plus class="w-4 h-4 mr-1" /> Nuevo Proyecto
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@if($projects->isEmpty())
|
||||
<div class="bg-gray-50 rounded-lg p-8 text-center">
|
||||
<p class="text-gray-500">No hay proyectos asociados a esta empresa.</p>
|
||||
<a href="{{ route('projects.create', ['company_id' => $company->id]) }}"
|
||||
class="mt-4 btn btn-primary">
|
||||
Crear Proyecto
|
||||
</a>
|
||||
</div>
|
||||
@else
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||
@foreach($projects as $project)
|
||||
<div class="border rounded-lg overflow-hidden shadow hover:shadow-md transition-shadow">
|
||||
<div class="p-4 bg-white">
|
||||
<div class="flex justify-between items-start">
|
||||
<h5 class="font-bold text-gray-900">{{ $project->name }}</h5>
|
||||
<span class="px-2 py-1 text-xs font-semibold rounded-full
|
||||
{{ $project->status === 'active' ? 'bg-green-100 text-green-800' : 'bg-gray-100 text-gray-800' }}">
|
||||
{{ $project->status === 'active' ? 'Activo' : 'Completado' }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<p class="mt-2 text-sm text-gray-600 line-clamp-2">
|
||||
{{ $project->description }}
|
||||
</p>
|
||||
|
||||
<div class="mt-4 flex items-center text-sm text-gray-500">
|
||||
<flux:icon.calendar class="w-4 h-4 mr-1" />
|
||||
<span>
|
||||
{{ $project->created_at->format('d M Y') }} -
|
||||
{{ $project->due_date?->format('d M Y') ?? 'Sin fecha límite' }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 flex justify-between items-center">
|
||||
<div class="flex items-center">
|
||||
<flux:icon.users class="w-4 h-4 mr-1 text-gray-500" />
|
||||
<span class="text-sm text-gray-600">
|
||||
{{ $project->users_count }} miembros
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<a href="{{ route('projects.show', $project) }}"
|
||||
class="text-blue-600 hover:text-blue-800 text-sm">
|
||||
Ver detalles
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
|
||||
<div class="mt-4">
|
||||
{{ $projects->links('pagination::tailwind', ['pageName' => 'projects_page']) }}
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
document.addEventListener('alpine:init', () => {
|
||||
Alpine.data('companyShow', () => ({
|
||||
// ... otras propiedades ...
|
||||
|
||||
openAddContactModal() {
|
||||
this.contactModalTitle = 'Agregar Nuevo Contacto';
|
||||
this.contactModalButton = 'Agregar Contacto';
|
||||
this.contactMethod = 'POST';
|
||||
|
||||
this.selectedContactId = null;
|
||||
this.contactPosition = '';
|
||||
this.showContactModal = true;
|
||||
},
|
||||
|
||||
editContact(contactId) {
|
||||
const contact = @json($contacts->items()).find(c => c.id === contactId);
|
||||
if (contact) {
|
||||
this.contactModalTitle = 'Editar Contacto';
|
||||
this.contactModalButton = 'Actualizar Contacto';
|
||||
this.contactMethod = 'PUT';
|
||||
|
||||
this.selectedContactId = contact.id;
|
||||
this.contactPosition = contact.pivot.position;
|
||||
this.showContactModal = true;
|
||||
}
|
||||
},
|
||||
|
||||
confirmDeleteContact(contactId) {
|
||||
|
||||
this.showDeleteContactModal = true;
|
||||
}
|
||||
}));
|
||||
});
|
||||
</stringth>
|
||||
|
||||
@endsection
|
||||
34
resources/views/components/accordion-item.blade.php
Normal file
34
resources/views/components/accordion-item.blade.php
Normal file
@@ -0,0 +1,34 @@
|
||||
@props(['title' => ''])
|
||||
|
||||
<div
|
||||
x-data="{
|
||||
id: $id('accordion'),
|
||||
isOpen: false
|
||||
}"
|
||||
x-init="
|
||||
isOpen = $parent.isMultiple
|
||||
? $parent.active.includes(id)
|
||||
: $parent.active === id;
|
||||
$watch('$parent.active', value => {
|
||||
isOpen = $parent.isMultiple
|
||||
? value.includes(id)
|
||||
: value === id;
|
||||
});
|
||||
"
|
||||
{{ $attributes->merge(['class' => 'border rounded-lg']) }}
|
||||
>
|
||||
<button
|
||||
@click="$parent.toggleItem(id)"
|
||||
class="w-full px-4 py-3 text-left bg-gray-100 hover:bg-gray-200 transition-colors"
|
||||
>
|
||||
{{ $title }}
|
||||
</button>
|
||||
|
||||
<div
|
||||
x-show="isOpen"
|
||||
x-collapse
|
||||
class="p-4 bg-white"
|
||||
>
|
||||
{{ $slot }}
|
||||
</div>
|
||||
</div>
|
||||
19
resources/views/components/accordion.blade.php
Normal file
19
resources/views/components/accordion.blade.php
Normal file
@@ -0,0 +1,19 @@
|
||||
@props(['allowMultiple' => false])
|
||||
|
||||
<div
|
||||
x-data="{
|
||||
active: {{ $allowMultiple ? '[]' : 'null' }},
|
||||
isMultiple: {{ $allowMultiple ? 'true' : 'false' }},
|
||||
toggleItem(id) {
|
||||
if (this.isMultiple) {
|
||||
const index = this.active.indexOf(id);
|
||||
index === -1 ? this.active.push(id) : this.active.splice(index, 1);
|
||||
} else {
|
||||
this.active = this.active === id ? null : id;
|
||||
}
|
||||
}
|
||||
}"
|
||||
{{ $attributes->merge(['class' => 'space-y-4']) }}
|
||||
>
|
||||
{{ $slot }}
|
||||
</div>
|
||||
@@ -1,17 +1,20 @@
|
||||
@props(['folder', 'currentFolder', 'expandedFolders', 'level' => 0, 'itemsCount' => 0])
|
||||
<li class="pl-{{ $level * 4 }}">
|
||||
<div class="flex items-center justify-between p-2 hover:bg-gray-50
|
||||
<div class="flex items-center justify-between p-1 hover:bg-gray-50
|
||||
{{ $folder->id === optional($currentFolder)->id ? 'bg-blue-50' : '' }}">
|
||||
<div class="flex items-center relative flex-1" wire:click="selectFolder({{ $folder->id }})">
|
||||
<button wire:click.prevent="toggleFolder({{ $folder->id }})"
|
||||
class="mr-2">
|
||||
<button wire:click.prevent="toggleFolder({{ $folder->id }})" class="mr-2">
|
||||
@if(in_array($folder->id, $expandedFolders))
|
||||
<x-icons icon="chevron-down" class="w-4 h-4" />
|
||||
@else
|
||||
<x-icons icon="chevron-right" class="w-4 h-4" />
|
||||
@endif
|
||||
</button>
|
||||
<flux:icon.folder class="size-5 mr-2 text-yellow-500"/>
|
||||
@if(in_array($folder->id, $expandedFolders))
|
||||
<flux:icon.folder-open class="size-5 mr-2"/>
|
||||
@else
|
||||
<flux:icon.folder class="size-5 mr-2"/>
|
||||
@endif
|
||||
<span class="flex-1 whitespace-nowrap">{{ $folder->name }}</span>
|
||||
@if($itemsCount > 0)
|
||||
<flux:badge class="text-xs font-medium rounded-sm px-1 py-0.5 text-gray-700 dark:text-gray-200 bg-gray-400/15 dark:bg-white/10" size="sm" inset="top bottom">{{ $itemsCount }}</flux:badge>
|
||||
|
||||
@@ -7,17 +7,23 @@
|
||||
'trendColor' => 'text-gray-500' // Color por defecto
|
||||
])
|
||||
|
||||
<div class="bg-white p-6 rounded-lg shadow">
|
||||
<div class="bg-white p-6 rounded-lg shadow hover:shadow-lg transition duration-300">
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
<p class="text-sm text-gray-500">{{ $title }}</p>
|
||||
<p class="text-3xl font-bold">{{ $value }}</p>
|
||||
<h2>
|
||||
<p class="text-xl font-bold text-gray-500">{{ $title }}</p>
|
||||
</h2>
|
||||
<p class="text-2xl font-bold">{{ $value }}</p>
|
||||
</div>
|
||||
<div class="{{ $color }} p-3 rounded-full">
|
||||
@if($icon === 'folder')
|
||||
<x-icons icon="folder" class="w-8 h-8 text-white" />
|
||||
<flux:icon.folder variant="solid" class="w-8 h-8 text-white"/>
|
||||
@elseif($icon === 'document')
|
||||
<x-icons icon = "document" class="w-8 h-8 text-white" />
|
||||
<flux:icon.document variant="solid" class="w-8 h-8 text-white"/>
|
||||
@elseif($icon === 'storage')
|
||||
<flux:icon.server variant="solid" class="w-8 h-8 text-white"/>
|
||||
@elseif($icon === 'clock')
|
||||
<flux:icon.clock variant="solid" class="w-8 h-8 text-white"/>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -68,7 +68,7 @@
|
||||
<li class="mb-4">
|
||||
<div class="flex items-center space-x-3">
|
||||
<div class="flex-shrink-0">
|
||||
<x-icons icon="activity" class="w-8 h-8 text-blue-500" />
|
||||
<flux:icon.calendar variant="solid" class="w-8 h-8 text-blue-800"/>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<p class="text-sm text-gray-900">{{ $activity->description }}</p>
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
<x-layouts.app :title="__('Show document')">
|
||||
<div class="flex h-screen bg-gray-100">
|
||||
|
||||
<div class="grid grid-cols-2 gap-x-4 h-screen bg-gray-100">
|
||||
<!-- Zona izquierda - Visualizador de documentos -->
|
||||
<div class="container w-1/2 bg-gray-100 relative">
|
||||
<div class="bg-gray-100 relative">
|
||||
<div id="outerContainer">
|
||||
|
||||
<div id="sidebarContainer">
|
||||
@@ -47,7 +46,11 @@
|
||||
<div id="sidebarResizer"></div>
|
||||
</div> <!-- sidebarContainer -->
|
||||
|
||||
|
||||
|
||||
<div id="mainContainer">
|
||||
|
||||
|
||||
<div class="toolbar">
|
||||
<div id="toolbarContainer">
|
||||
<div id="toolbarViewer" class="toolbarHorizontalGroup">
|
||||
@@ -60,48 +63,48 @@
|
||||
<button id="viewFindButton" class="toolbarButton" type="button" tabindex="0" data-l10n-id="pdfjs-findbar-button" aria-expanded="false" aria-controls="findbar">
|
||||
<span data-l10n-id="pdfjs-findbar-button-label"></span>
|
||||
</button>
|
||||
<div class="hidden doorHanger toolbarHorizontalGroup" id="findbar">
|
||||
<div id="findInputContainer" class="toolbarHorizontalGroup">
|
||||
<span class="loadingInput end toolbarHorizontalGroup">
|
||||
<input id="findInput" class="toolbarField" tabindex="0" data-l10n-id="pdfjs-find-input" aria-invalid="false">
|
||||
</span>
|
||||
<div class="toolbarHorizontalGroup">
|
||||
<button id="findPreviousButton" class="toolbarButton" type="button" tabindex="0" data-l10n-id="pdfjs-find-previous-button">
|
||||
<span data-l10n-id="pdfjs-find-previous-button-label"></span>
|
||||
</button>
|
||||
<div class="splitToolbarButtonSeparator"></div>
|
||||
<button id="findNextButton" class="toolbarButton" type="button" tabindex="0" data-l10n-id="pdfjs-find-next-button">
|
||||
<span data-l10n-id="pdfjs-find-next-button-label"></span>
|
||||
</button>
|
||||
<div class="hidden doorHanger toolbarHorizontalGroup" id="findbar">
|
||||
<div id="findInputContainer" class="toolbarHorizontalGroup">
|
||||
<span class="loadingInput end toolbarHorizontalGroup">
|
||||
<input id="findInput" class="toolbarField" tabindex="0" data-l10n-id="pdfjs-find-input" aria-invalid="false">
|
||||
</span>
|
||||
<div class="toolbarHorizontalGroup">
|
||||
<button id="findPreviousButton" class="toolbarButton" type="button" tabindex="0" data-l10n-id="pdfjs-find-previous-button">
|
||||
<span data-l10n-id="pdfjs-find-previous-button-label"></span>
|
||||
</button>
|
||||
<div class="splitToolbarButtonSeparator"></div>
|
||||
<button id="findNextButton" class="toolbarButton" type="button" tabindex="0" data-l10n-id="pdfjs-find-next-button">
|
||||
<span data-l10n-id="pdfjs-find-next-button-label"></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="findbarOptionsOneContainer" class="toolbarHorizontalGroup">
|
||||
<div class="toggleButton toolbarLabel">
|
||||
<input type="checkbox" id="findHighlightAll" tabindex="0" />
|
||||
<label for="findHighlightAll" data-l10n-id="pdfjs-find-highlight-checkbox"></label>
|
||||
</div>
|
||||
<div class="toggleButton toolbarLabel">
|
||||
<input type="checkbox" id="findMatchCase" tabindex="0" />
|
||||
<label for="findMatchCase" data-l10n-id="pdfjs-find-match-case-checkbox-label"></label>
|
||||
</div>
|
||||
</div>
|
||||
<div id="findbarOptionsTwoContainer" class="toolbarHorizontalGroup">
|
||||
<div class="toggleButton toolbarLabel">
|
||||
<input type="checkbox" id="findMatchDiacritics" tabindex="0" />
|
||||
<label for="findMatchDiacritics" data-l10n-id="pdfjs-find-match-diacritics-checkbox-label"></label>
|
||||
</div>
|
||||
<div class="toggleButton toolbarLabel">
|
||||
<input type="checkbox" id="findEntireWord" tabindex="0" />
|
||||
<label for="findEntireWord" data-l10n-id="pdfjs-find-entire-word-checkbox-label"></label>
|
||||
</div>
|
||||
</div>
|
||||
<div id="findbarOptionsOneContainer" class="toolbarHorizontalGroup">
|
||||
<div class="toggleButton toolbarLabel">
|
||||
<input type="checkbox" id="findHighlightAll" tabindex="0" />
|
||||
<label for="findHighlightAll" data-l10n-id="pdfjs-find-highlight-checkbox"></label>
|
||||
</div>
|
||||
<div class="toggleButton toolbarLabel">
|
||||
<input type="checkbox" id="findMatchCase" tabindex="0" />
|
||||
<label for="findMatchCase" data-l10n-id="pdfjs-find-match-case-checkbox-label"></label>
|
||||
</div>
|
||||
</div>
|
||||
<div id="findbarOptionsTwoContainer" class="toolbarHorizontalGroup">
|
||||
<div class="toggleButton toolbarLabel">
|
||||
<input type="checkbox" id="findMatchDiacritics" tabindex="0" />
|
||||
<label for="findMatchDiacritics" data-l10n-id="pdfjs-find-match-diacritics-checkbox-label"></label>
|
||||
</div>
|
||||
<div class="toggleButton toolbarLabel">
|
||||
<input type="checkbox" id="findEntireWord" tabindex="0" />
|
||||
<label for="findEntireWord" data-l10n-id="pdfjs-find-entire-word-checkbox-label"></label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="findbarMessageContainer" class="toolbarHorizontalGroup" aria-live="polite">
|
||||
<span id="findResultsCount" class="toolbarLabel"></span>
|
||||
<span id="findMsg" class="toolbarLabel"></span>
|
||||
</div>
|
||||
</div> <!-- findbar -->
|
||||
<div id="findbarMessageContainer" class="toolbarHorizontalGroup" aria-live="polite">
|
||||
<span id="findResultsCount" class="toolbarLabel"></span>
|
||||
<span id="findMsg" class="toolbarLabel"></span>
|
||||
</div>
|
||||
</div> <!-- findbar -->
|
||||
</div>
|
||||
<div class="toolbarHorizontalGroup hiddenSmallView">
|
||||
<button class="toolbarButton" type="button" id="previous" tabindex="0" data-l10n-id="pdfjs-previous-button">
|
||||
@@ -119,245 +122,245 @@
|
||||
<span id="numPages" class="toolbarLabel"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div id="toolbarViewerMiddle" class="toolbarHorizontalGroup">
|
||||
<div class="toolbarHorizontalGroup">
|
||||
<button id="zoomOutButton" class="toolbarButton" type="button" tabindex="0" data-l10n-id="pdfjs-zoom-out-button">
|
||||
<span data-l10n-id="pdfjs-zoom-out-button-label"></span>
|
||||
</button>
|
||||
<div class="splitToolbarButtonSeparator"></div>
|
||||
<button id="zoomInButton" class="toolbarButton" type="button" tabindex="0" data-l10n-id="pdfjs-zoom-in-button">
|
||||
<span data-l10n-id="pdfjs-zoom-in-button-label"></span>
|
||||
</button>
|
||||
</div>
|
||||
<span id="scaleSelectContainer" class="dropdownToolbarButton">
|
||||
<select id="scaleSelect" tabindex="0" data-l10n-id="pdfjs-zoom-select">
|
||||
<option id="pageAutoOption" value="auto" selected="selected" data-l10n-id="pdfjs-page-scale-auto"></option>
|
||||
<option id="pageActualOption" value="page-actual" data-l10n-id="pdfjs-page-scale-actual"></option>
|
||||
<option id="pageFitOption" value="page-fit" data-l10n-id="pdfjs-page-scale-fit"></option>
|
||||
<option id="pageWidthOption" value="page-width" data-l10n-id="pdfjs-page-scale-width"></option>
|
||||
<option id="customScaleOption" value="custom" disabled="disabled" hidden="true" data-l10n-id="pdfjs-page-scale-percent" data-l10n-args='{ "scale": 0 }'></option>
|
||||
<option value="0.5" data-l10n-id="pdfjs-page-scale-percent" data-l10n-args='{ "scale": 50 }'></option>
|
||||
<option value="0.75" data-l10n-id="pdfjs-page-scale-percent" data-l10n-args='{ "scale": 75 }'></option>
|
||||
<option value="1" data-l10n-id="pdfjs-page-scale-percent" data-l10n-args='{ "scale": 100 }'></option>
|
||||
<option value="1.25" data-l10n-id="pdfjs-page-scale-percent" data-l10n-args='{ "scale": 125 }'></option>
|
||||
<option value="1.5" data-l10n-id="pdfjs-page-scale-percent" data-l10n-args='{ "scale": 150 }'></option>
|
||||
<option value="2" data-l10n-id="pdfjs-page-scale-percent" data-l10n-args='{ "scale": 200 }'></option>
|
||||
<option value="3" data-l10n-id="pdfjs-page-scale-percent" data-l10n-args='{ "scale": 300 }'></option>
|
||||
<option value="4" data-l10n-id="pdfjs-page-scale-percent" data-l10n-args='{ "scale": 400 }'></option>
|
||||
</select>
|
||||
</span>
|
||||
</div>
|
||||
<div id="toolbarViewerRight" class="toolbarHorizontalGroup">
|
||||
<div id="editorModeButtons" class="toolbarHorizontalGroup" role="radiogroup">
|
||||
<div id="editorSignature" class="toolbarButtonWithContainer" hidden="true">
|
||||
<button id="editorSignatureButton" class="toolbarButton" type="button" tabindex="0" disabled="disabled" role="radio" aria-expanded="false" aria-haspopup="true" aria-controls="editorSignatureParamsToolbar" data-l10n-id="pdfjs-editor-signature-button">
|
||||
<span data-l10n-id="pdfjs-editor-signature-button-label"></span>
|
||||
</button>
|
||||
<div class="editorParamsToolbar hidden doorHangerRight menu" id="editorSignatureParamsToolbar">
|
||||
<div id="addSignatureDoorHanger" class="menuContainer" role="region" data-l10n-id="pdfjs-editor-add-signature-container">
|
||||
<button id="editorSignatureAddSignature" class="toolbarButton labeled" type="button" tabindex="0" data-l10n-id="pdfjs-editor-signature-add-signature-button">
|
||||
<span data-l10n-id="pdfjs-editor-signature-add-signature-button-label" class="editorParamsLabel"></span>
|
||||
<div id="toolbarViewerMiddle" class="toolbarHorizontalGroup">
|
||||
<div class="toolbarHorizontalGroup">
|
||||
<button id="zoomOutButton" class="toolbarButton" type="button" tabindex="0" data-l10n-id="pdfjs-zoom-out-button">
|
||||
<span data-l10n-id="pdfjs-zoom-out-button-label"></span>
|
||||
</button>
|
||||
<div class="splitToolbarButtonSeparator"></div>
|
||||
<button id="zoomInButton" class="toolbarButton" type="button" tabindex="0" data-l10n-id="pdfjs-zoom-in-button">
|
||||
<span data-l10n-id="pdfjs-zoom-in-button-label"></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<span id="scaleSelectContainer" class="dropdownToolbarButton">
|
||||
<select id="scaleSelect" tabindex="0" data-l10n-id="pdfjs-zoom-select">
|
||||
<option id="pageAutoOption" value="auto" selected="selected" data-l10n-id="pdfjs-page-scale-auto"></option>
|
||||
<option id="pageActualOption" value="page-actual" data-l10n-id="pdfjs-page-scale-actual"></option>
|
||||
<option id="pageFitOption" value="page-fit" data-l10n-id="pdfjs-page-scale-fit"></option>
|
||||
<option id="pageWidthOption" value="page-width" data-l10n-id="pdfjs-page-scale-width"></option>
|
||||
<option id="customScaleOption" value="custom" disabled="disabled" hidden="true" data-l10n-id="pdfjs-page-scale-percent" data-l10n-args='{ "scale": 0 }'></option>
|
||||
<option value="0.5" data-l10n-id="pdfjs-page-scale-percent" data-l10n-args='{ "scale": 50 }'></option>
|
||||
<option value="0.75" data-l10n-id="pdfjs-page-scale-percent" data-l10n-args='{ "scale": 75 }'></option>
|
||||
<option value="1" data-l10n-id="pdfjs-page-scale-percent" data-l10n-args='{ "scale": 100 }'></option>
|
||||
<option value="1.25" data-l10n-id="pdfjs-page-scale-percent" data-l10n-args='{ "scale": 125 }'></option>
|
||||
<option value="1.5" data-l10n-id="pdfjs-page-scale-percent" data-l10n-args='{ "scale": 150 }'></option>
|
||||
<option value="2" data-l10n-id="pdfjs-page-scale-percent" data-l10n-args='{ "scale": 200 }'></option>
|
||||
<option value="3" data-l10n-id="pdfjs-page-scale-percent" data-l10n-args='{ "scale": 300 }'></option>
|
||||
<option value="4" data-l10n-id="pdfjs-page-scale-percent" data-l10n-args='{ "scale": 400 }'></option>
|
||||
</select>
|
||||
</span>
|
||||
</div>
|
||||
<div id="editorHighlight" class="toolbarButtonWithContainer">
|
||||
<button id="editorHighlightButton" class="toolbarButton" type="button" disabled="disabled" role="radio" aria-expanded="false" aria-haspopup="true" aria-controls="editorHighlightParamsToolbar" tabindex="0" data-l10n-id="pdfjs-editor-highlight-button">
|
||||
<span data-l10n-id="pdfjs-editor-highlight-button-label"></span>
|
||||
</button>
|
||||
<div class="editorParamsToolbar hidden doorHangerRight" id="editorHighlightParamsToolbar">
|
||||
<div id="highlightParamsToolbarContainer" class="editorParamsToolbarContainer">
|
||||
<div id="editorHighlightColorPicker" class="colorPicker">
|
||||
<span id="highlightColorPickerLabel" class="editorParamsLabel" data-l10n-id="pdfjs-editor-highlight-colorpicker-label"></span>
|
||||
</div>
|
||||
<div id="editorHighlightThickness">
|
||||
<label for="editorFreeHighlightThickness" class="editorParamsLabel" data-l10n-id="pdfjs-editor-free-highlight-thickness-input"></label>
|
||||
<div class="thicknessPicker">
|
||||
<input type="range" id="editorFreeHighlightThickness" class="editorParamsSlider" data-l10n-id="pdfjs-editor-free-highlight-thickness-title" value="12" min="8" max="24" step="1" tabindex="0">
|
||||
</div>
|
||||
</div>
|
||||
<div id="editorHighlightVisibility">
|
||||
<div class="divider"></div>
|
||||
<div class="toggler">
|
||||
<label for="editorHighlightShowAll" class="editorParamsLabel" data-l10n-id="pdfjs-editor-highlight-show-all-button-label"></label>
|
||||
<button id="editorHighlightShowAll" class="toggle-button" type="button" data-l10n-id="pdfjs-editor-highlight-show-all-button" aria-pressed="true" tabindex="0"></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="editorFreeText" class="toolbarButtonWithContainer">
|
||||
<button id="editorFreeTextButton" class="toolbarButton" type="button" disabled="disabled" role="radio" aria-expanded="false" aria-haspopup="true" aria-controls="editorFreeTextParamsToolbar" tabindex="0" data-l10n-id="pdfjs-editor-free-text-button">
|
||||
<span data-l10n-id="pdfjs-editor-free-text-button-label"></span>
|
||||
</button>
|
||||
<div class="editorParamsToolbar hidden doorHangerRight" id="editorFreeTextParamsToolbar">
|
||||
<div class="editorParamsToolbarContainer">
|
||||
<div class="editorParamsSetter">
|
||||
<label for="editorFreeTextColor" class="editorParamsLabel" data-l10n-id="pdfjs-editor-free-text-color-input"></label>
|
||||
<input type="color" id="editorFreeTextColor" class="editorParamsColor" tabindex="0">
|
||||
</div>
|
||||
<div class="editorParamsSetter">
|
||||
<label for="editorFreeTextFontSize" class="editorParamsLabel" data-l10n-id="pdfjs-editor-free-text-size-input"></label>
|
||||
<input type="range" id="editorFreeTextFontSize" class="editorParamsSlider" value="10" min="5" max="100" step="1" tabindex="0">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="editorInk" class="toolbarButtonWithContainer">
|
||||
<button id="editorInkButton" class="toolbarButton" type="button" disabled="disabled" role="radio" aria-expanded="false" aria-haspopup="true" aria-controls="editorInkParamsToolbar" tabindex="0" data-l10n-id="pdfjs-editor-ink-button">
|
||||
<span data-l10n-id="pdfjs-editor-ink-button-label"></span>
|
||||
</button>
|
||||
<div class="editorParamsToolbar hidden doorHangerRight" id="editorInkParamsToolbar">
|
||||
<div class="editorParamsToolbarContainer">
|
||||
<div class="editorParamsSetter">
|
||||
<label for="editorInkColor" class="editorParamsLabel" data-l10n-id="pdfjs-editor-ink-color-input"></label>
|
||||
<input type="color" id="editorInkColor" class="editorParamsColor" tabindex="0">
|
||||
</div>
|
||||
<div class="editorParamsSetter">
|
||||
<label for="editorInkThickness" class="editorParamsLabel" data-l10n-id="pdfjs-editor-ink-thickness-input"></label>
|
||||
<input type="range" id="editorInkThickness" class="editorParamsSlider" value="1" min="1" max="20" step="1" tabindex="0">
|
||||
</div>
|
||||
<div class="editorParamsSetter">
|
||||
<label for="editorInkOpacity" class="editorParamsLabel" data-l10n-id="pdfjs-editor-ink-opacity-input"></label>
|
||||
<input type="range" id="editorInkOpacity" class="editorParamsSlider" value="1" min="0.05" max="1" step="0.05" tabindex="0">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="editorStamp" class="toolbarButtonWithContainer">
|
||||
<button id="editorStampButton" class="toolbarButton" type="button" disabled="disabled" role="radio" aria-expanded="false" aria-haspopup="true" aria-controls="editorStampParamsToolbar" tabindex="0" data-l10n-id="pdfjs-editor-stamp-button">
|
||||
<span data-l10n-id="pdfjs-editor-stamp-button-label"></span>
|
||||
</button>
|
||||
<div class="editorParamsToolbar hidden doorHangerRight menu" id="editorStampParamsToolbar">
|
||||
<div class="menuContainer">
|
||||
<button id="editorStampAddImage" class="toolbarButton labeled" type="button" tabindex="0" data-l10n-id="pdfjs-editor-stamp-add-image-button">
|
||||
<span class="editorParamsLabel" data-l10n-id="pdfjs-editor-stamp-add-image-button-label"></span>
|
||||
<div id="toolbarViewerRight" class="toolbarHorizontalGroup">
|
||||
<div id="editorModeButtons" class="toolbarHorizontalGroup" role="radiogroup">
|
||||
<div id="editorSignature" class="toolbarButtonWithContainer" hidden="true">
|
||||
<button id="editorSignatureButton" class="toolbarButton" type="button" tabindex="0" disabled="disabled" role="radio" aria-expanded="false" aria-haspopup="true" aria-controls="editorSignatureParamsToolbar" data-l10n-id="pdfjs-editor-signature-button">
|
||||
<span data-l10n-id="pdfjs-editor-signature-button-label"></span>
|
||||
</button>
|
||||
<div class="editorParamsToolbar hidden doorHangerRight menu" id="editorSignatureParamsToolbar">
|
||||
<div id="addSignatureDoorHanger" class="menuContainer" role="region" data-l10n-id="pdfjs-editor-add-signature-container">
|
||||
<button id="editorSignatureAddSignature" class="toolbarButton labeled" type="button" tabindex="0" data-l10n-id="pdfjs-editor-signature-add-signature-button">
|
||||
<span data-l10n-id="pdfjs-editor-signature-add-signature-button-label" class="editorParamsLabel"></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="editorHighlight" class="toolbarButtonWithContainer">
|
||||
<button id="editorHighlightButton" class="toolbarButton" type="button" disabled="disabled" role="radio" aria-expanded="false" aria-haspopup="true" aria-controls="editorHighlightParamsToolbar" tabindex="0" data-l10n-id="pdfjs-editor-highlight-button">
|
||||
<span data-l10n-id="pdfjs-editor-highlight-button-label"></span>
|
||||
</button>
|
||||
<div class="editorParamsToolbar hidden doorHangerRight" id="editorHighlightParamsToolbar">
|
||||
<div id="highlightParamsToolbarContainer" class="editorParamsToolbarContainer">
|
||||
<div id="editorHighlightColorPicker" class="colorPicker">
|
||||
<span id="highlightColorPickerLabel" class="editorParamsLabel" data-l10n-id="pdfjs-editor-highlight-colorpicker-label"></span>
|
||||
</div>
|
||||
<div id="editorHighlightThickness">
|
||||
<label for="editorFreeHighlightThickness" class="editorParamsLabel" data-l10n-id="pdfjs-editor-free-highlight-thickness-input"></label>
|
||||
<div class="thicknessPicker">
|
||||
<input type="range" id="editorFreeHighlightThickness" class="editorParamsSlider" data-l10n-id="pdfjs-editor-free-highlight-thickness-title" value="12" min="8" max="24" step="1" tabindex="0">
|
||||
</div>
|
||||
</div>
|
||||
<div id="editorHighlightVisibility">
|
||||
<div class="divider"></div>
|
||||
<div class="toggler">
|
||||
<label for="editorHighlightShowAll" class="editorParamsLabel" data-l10n-id="pdfjs-editor-highlight-show-all-button-label"></label>
|
||||
<button id="editorHighlightShowAll" class="toggle-button" type="button" data-l10n-id="pdfjs-editor-highlight-show-all-button" aria-pressed="true" tabindex="0"></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="editorFreeText" class="toolbarButtonWithContainer">
|
||||
<button id="editorFreeTextButton" class="toolbarButton" type="button" disabled="disabled" role="radio" aria-expanded="false" aria-haspopup="true" aria-controls="editorFreeTextParamsToolbar" tabindex="0" data-l10n-id="pdfjs-editor-free-text-button">
|
||||
<span data-l10n-id="pdfjs-editor-free-text-button-label"></span>
|
||||
</button>
|
||||
<div class="editorParamsToolbar hidden doorHangerRight" id="editorFreeTextParamsToolbar">
|
||||
<div class="editorParamsToolbarContainer">
|
||||
<div class="editorParamsSetter">
|
||||
<label for="editorFreeTextColor" class="editorParamsLabel" data-l10n-id="pdfjs-editor-free-text-color-input"></label>
|
||||
<input type="color" id="editorFreeTextColor" class="editorParamsColor" tabindex="0">
|
||||
</div>
|
||||
<div class="editorParamsSetter">
|
||||
<label for="editorFreeTextFontSize" class="editorParamsLabel" data-l10n-id="pdfjs-editor-free-text-size-input"></label>
|
||||
<input type="range" id="editorFreeTextFontSize" class="editorParamsSlider" value="10" min="5" max="100" step="1" tabindex="0">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="editorInk" class="toolbarButtonWithContainer">
|
||||
<button id="editorInkButton" class="toolbarButton" type="button" disabled="disabled" role="radio" aria-expanded="false" aria-haspopup="true" aria-controls="editorInkParamsToolbar" tabindex="0" data-l10n-id="pdfjs-editor-ink-button">
|
||||
<span data-l10n-id="pdfjs-editor-ink-button-label"></span>
|
||||
</button>
|
||||
<div class="editorParamsToolbar hidden doorHangerRight" id="editorInkParamsToolbar">
|
||||
<div class="editorParamsToolbarContainer">
|
||||
<div class="editorParamsSetter">
|
||||
<label for="editorInkColor" class="editorParamsLabel" data-l10n-id="pdfjs-editor-ink-color-input"></label>
|
||||
<input type="color" id="editorInkColor" class="editorParamsColor" tabindex="0">
|
||||
</div>
|
||||
<div class="editorParamsSetter">
|
||||
<label for="editorInkThickness" class="editorParamsLabel" data-l10n-id="pdfjs-editor-ink-thickness-input"></label>
|
||||
<input type="range" id="editorInkThickness" class="editorParamsSlider" value="1" min="1" max="20" step="1" tabindex="0">
|
||||
</div>
|
||||
<div class="editorParamsSetter">
|
||||
<label for="editorInkOpacity" class="editorParamsLabel" data-l10n-id="pdfjs-editor-ink-opacity-input"></label>
|
||||
<input type="range" id="editorInkOpacity" class="editorParamsSlider" value="1" min="0.05" max="1" step="0.05" tabindex="0">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="editorStamp" class="toolbarButtonWithContainer">
|
||||
<button id="editorStampButton" class="toolbarButton" type="button" disabled="disabled" role="radio" aria-expanded="false" aria-haspopup="true" aria-controls="editorStampParamsToolbar" tabindex="0" data-l10n-id="pdfjs-editor-stamp-button">
|
||||
<span data-l10n-id="pdfjs-editor-stamp-button-label"></span>
|
||||
</button>
|
||||
<div class="editorParamsToolbar hidden doorHangerRight menu" id="editorStampParamsToolbar">
|
||||
<div class="menuContainer">
|
||||
<button id="editorStampAddImage" class="toolbarButton labeled" type="button" tabindex="0" data-l10n-id="pdfjs-editor-stamp-add-image-button">
|
||||
<span class="editorParamsLabel" data-l10n-id="pdfjs-editor-stamp-add-image-button-label"></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="editorModeSeparator" class="verticalToolbarSeparator"></div>
|
||||
<div id="editorModeSeparator" class="verticalToolbarSeparator"></div>
|
||||
|
||||
<div class="toolbarHorizontalGroup hiddenMediumView">
|
||||
<button id="printButton" class="toolbarButton" type="button" tabindex="0" data-l10n-id="pdfjs-print-button">
|
||||
<span data-l10n-id="pdfjs-print-button-label"></span>
|
||||
</button>
|
||||
|
||||
<button id="downloadButton" class="toolbarButton" type="button" tabindex="0" data-l10n-id="pdfjs-save-button">
|
||||
<span data-l10n-id="pdfjs-save-button-label"></span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="verticalToolbarSeparator hiddenMediumView"></div>
|
||||
|
||||
<div id="secondaryToolbarToggle" class="toolbarButtonWithContainer">
|
||||
<button id="secondaryToolbarToggleButton" class="toolbarButton" type="button" tabindex="0" data-l10n-id="pdfjs-tools-button" aria-expanded="false" aria-haspopup="true" aria-controls="secondaryToolbar">
|
||||
<span data-l10n-id="pdfjs-tools-button-label"></span>
|
||||
</button>
|
||||
<div id="secondaryToolbar" class="hidden doorHangerRight menu">
|
||||
<div id="secondaryToolbarButtonContainer" class="menuContainer">
|
||||
<button id="secondaryOpenFile" class="toolbarButton labeled" type="button" tabindex="0" data-l10n-id="pdfjs-open-file-button">
|
||||
<span data-l10n-id="pdfjs-open-file-button-label"></span>
|
||||
</button>
|
||||
|
||||
<div class="visibleMediumView">
|
||||
<button id="secondaryPrint" class="toolbarButton labeled" type="button" tabindex="0" data-l10n-id="pdfjs-print-button">
|
||||
<div class="toolbarHorizontalGroup hiddenMediumView">
|
||||
<button id="printButton" class="toolbarButton" type="button" tabindex="0" data-l10n-id="pdfjs-print-button">
|
||||
<span data-l10n-id="pdfjs-print-button-label"></span>
|
||||
</button>
|
||||
</button>
|
||||
|
||||
<button id="secondaryDownload" class="toolbarButton labeled" type="button" tabindex="0" data-l10n-id="pdfjs-save-button">
|
||||
<button id="downloadButton" class="toolbarButton" type="button" tabindex="0" data-l10n-id="pdfjs-save-button">
|
||||
<span data-l10n-id="pdfjs-save-button-label"></span>
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="horizontalToolbarSeparator"></div>
|
||||
|
||||
<button id="presentationMode" class="toolbarButton labeled" type="button" tabindex="0" data-l10n-id="pdfjs-presentation-mode-button">
|
||||
<span data-l10n-id="pdfjs-presentation-mode-button-label"></span>
|
||||
</button>
|
||||
|
||||
<a href="#" id="viewBookmark" class="toolbarButton labeled" tabindex="0" data-l10n-id="pdfjs-bookmark-button">
|
||||
<span data-l10n-id="pdfjs-bookmark-button-label"></span>
|
||||
</a>
|
||||
|
||||
<div id="viewBookmarkSeparator" class="horizontalToolbarSeparator"></div>
|
||||
|
||||
<button id="firstPage" class="toolbarButton labeled" type="button" tabindex="0" data-l10n-id="pdfjs-first-page-button">
|
||||
<span data-l10n-id="pdfjs-first-page-button-label"></span>
|
||||
</button>
|
||||
<button id="lastPage" class="toolbarButton labeled" type="button" tabindex="0" data-l10n-id="pdfjs-last-page-button">
|
||||
<span data-l10n-id="pdfjs-last-page-button-label"></span>
|
||||
</button>
|
||||
|
||||
<div class="horizontalToolbarSeparator"></div>
|
||||
|
||||
<button id="pageRotateCw" class="toolbarButton labeled" type="button" tabindex="0" data-l10n-id="pdfjs-page-rotate-cw-button">
|
||||
<span data-l10n-id="pdfjs-page-rotate-cw-button-label"></span>
|
||||
</button>
|
||||
<button id="pageRotateCcw" class="toolbarButton labeled" type="button" tabindex="0" data-l10n-id="pdfjs-page-rotate-ccw-button">
|
||||
<span data-l10n-id="pdfjs-page-rotate-ccw-button-label"></span>
|
||||
</button>
|
||||
|
||||
<div class="horizontalToolbarSeparator"></div>
|
||||
|
||||
<div id="cursorToolButtons" role="radiogroup">
|
||||
<button id="cursorSelectTool" class="toolbarButton labeled toggled" type="button" tabindex="0" data-l10n-id="pdfjs-cursor-text-select-tool-button" role="radio" aria-checked="true">
|
||||
<span data-l10n-id="pdfjs-cursor-text-select-tool-button-label"></span>
|
||||
</button>
|
||||
<button id="cursorHandTool" class="toolbarButton labeled" type="button" tabindex="0" data-l10n-id="pdfjs-cursor-hand-tool-button" role="radio" aria-checked="false">
|
||||
<span data-l10n-id="pdfjs-cursor-hand-tool-button-label"></span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="horizontalToolbarSeparator"></div>
|
||||
|
||||
<div id="scrollModeButtons" role="radiogroup">
|
||||
<button id="scrollPage" class="toolbarButton labeled" type="button" tabindex="0" data-l10n-id="pdfjs-scroll-page-button" role="radio" aria-checked="false">
|
||||
<span data-l10n-id="pdfjs-scroll-page-button-label"></span>
|
||||
</button>
|
||||
<button id="scrollVertical" class="toolbarButton labeled toggled" type="button" tabindex="0" data-l10n-id="pdfjs-scroll-vertical-button" role="radio" aria-checked="true">
|
||||
<span data-l10n-id="pdfjs-scroll-vertical-button-label"></span>
|
||||
</button>
|
||||
<button id="scrollHorizontal" class="toolbarButton labeled" type="button" tabindex="0" data-l10n-id="pdfjs-scroll-horizontal-button" role="radio" aria-checked="false">
|
||||
<span data-l10n-id="pdfjs-scroll-horizontal-button-label"></span>
|
||||
</button>
|
||||
<button id="scrollWrapped" class="toolbarButton labeled" type="button" tabindex="0" data-l10n-id="pdfjs-scroll-wrapped-button" role="radio" aria-checked="false">
|
||||
<span data-l10n-id="pdfjs-scroll-wrapped-button-label"></span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="horizontalToolbarSeparator"></div>
|
||||
|
||||
<div id="spreadModeButtons" role="radiogroup">
|
||||
<button id="spreadNone" class="toolbarButton labeled toggled" type="button" tabindex="0" data-l10n-id="pdfjs-spread-none-button" role="radio" aria-checked="true">
|
||||
<span data-l10n-id="pdfjs-spread-none-button-label"></span>
|
||||
</button>
|
||||
<button id="spreadOdd" class="toolbarButton labeled" type="button" tabindex="0" data-l10n-id="pdfjs-spread-odd-button" role="radio" aria-checked="false">
|
||||
<span data-l10n-id="pdfjs-spread-odd-button-label"></span>
|
||||
</button>
|
||||
<button id="spreadEven" class="toolbarButton labeled" type="button" tabindex="0" data-l10n-id="pdfjs-spread-even-button" role="radio" aria-checked="false">
|
||||
<span data-l10n-id="pdfjs-spread-even-button-label"></span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div id="imageAltTextSettingsSeparator" class="horizontalToolbarSeparator hidden"></div>
|
||||
<button id="imageAltTextSettings" type="button" class="toolbarButton labeled hidden" tabindex="0" data-l10n-id="pdfjs-image-alt-text-settings-button" aria-controls="altTextSettingsDialog">
|
||||
<span data-l10n-id="pdfjs-image-alt-text-settings-button-label"></span>
|
||||
</button>
|
||||
|
||||
<div class="horizontalToolbarSeparator"></div>
|
||||
|
||||
<button id="documentProperties" class="toolbarButton labeled" type="button" tabindex="0" data-l10n-id="pdfjs-document-properties-button" aria-controls="documentPropertiesDialog">
|
||||
<span data-l10n-id="pdfjs-document-properties-button-label"></span>
|
||||
</button>
|
||||
</div>
|
||||
</div> <!-- secondaryToolbar -->
|
||||
|
||||
<div class="verticalToolbarSeparator hiddenMediumView"></div>
|
||||
|
||||
<div id="secondaryToolbarToggle" class="toolbarButtonWithContainer">
|
||||
<button id="secondaryToolbarToggleButton" class="toolbarButton" type="button" tabindex="0" data-l10n-id="pdfjs-tools-button" aria-expanded="false" aria-haspopup="true" aria-controls="secondaryToolbar">
|
||||
<span data-l10n-id="pdfjs-tools-button-label"></span>
|
||||
</button>
|
||||
<div id="secondaryToolbar" class="hidden doorHangerRight menu">
|
||||
<div id="secondaryToolbarButtonContainer" class="menuContainer">
|
||||
<button id="secondaryOpenFile" class="toolbarButton labeled" type="button" tabindex="0" data-l10n-id="pdfjs-open-file-button">
|
||||
<span data-l10n-id="pdfjs-open-file-button-label"></span>
|
||||
</button>
|
||||
|
||||
<div class="visibleMediumView">
|
||||
<button id="secondaryPrint" class="toolbarButton labeled" type="button" tabindex="0" data-l10n-id="pdfjs-print-button">
|
||||
<span data-l10n-id="pdfjs-print-button-label"></span>
|
||||
</button>
|
||||
|
||||
<button id="secondaryDownload" class="toolbarButton labeled" type="button" tabindex="0" data-l10n-id="pdfjs-save-button">
|
||||
<span data-l10n-id="pdfjs-save-button-label"></span>
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="horizontalToolbarSeparator"></div>
|
||||
|
||||
<button id="presentationMode" class="toolbarButton labeled" type="button" tabindex="0" data-l10n-id="pdfjs-presentation-mode-button">
|
||||
<span data-l10n-id="pdfjs-presentation-mode-button-label"></span>
|
||||
</button>
|
||||
|
||||
<a href="#" id="viewBookmark" class="toolbarButton labeled" tabindex="0" data-l10n-id="pdfjs-bookmark-button">
|
||||
<span data-l10n-id="pdfjs-bookmark-button-label"></span>
|
||||
</a>
|
||||
|
||||
<div id="viewBookmarkSeparator" class="horizontalToolbarSeparator"></div>
|
||||
|
||||
<button id="firstPage" class="toolbarButton labeled" type="button" tabindex="0" data-l10n-id="pdfjs-first-page-button">
|
||||
<span data-l10n-id="pdfjs-first-page-button-label"></span>
|
||||
</button>
|
||||
<button id="lastPage" class="toolbarButton labeled" type="button" tabindex="0" data-l10n-id="pdfjs-last-page-button">
|
||||
<span data-l10n-id="pdfjs-last-page-button-label"></span>
|
||||
</button>
|
||||
|
||||
<div class="horizontalToolbarSeparator"></div>
|
||||
|
||||
<button id="pageRotateCw" class="toolbarButton labeled" type="button" tabindex="0" data-l10n-id="pdfjs-page-rotate-cw-button">
|
||||
<span data-l10n-id="pdfjs-page-rotate-cw-button-label"></span>
|
||||
</button>
|
||||
<button id="pageRotateCcw" class="toolbarButton labeled" type="button" tabindex="0" data-l10n-id="pdfjs-page-rotate-ccw-button">
|
||||
<span data-l10n-id="pdfjs-page-rotate-ccw-button-label"></span>
|
||||
</button>
|
||||
|
||||
<div class="horizontalToolbarSeparator"></div>
|
||||
|
||||
<div id="cursorToolButtons" role="radiogroup">
|
||||
<button id="cursorSelectTool" class="toolbarButton labeled toggled" type="button" tabindex="0" data-l10n-id="pdfjs-cursor-text-select-tool-button" role="radio" aria-checked="true">
|
||||
<span data-l10n-id="pdfjs-cursor-text-select-tool-button-label"></span>
|
||||
</button>
|
||||
<button id="cursorHandTool" class="toolbarButton labeled" type="button" tabindex="0" data-l10n-id="pdfjs-cursor-hand-tool-button" role="radio" aria-checked="false">
|
||||
<span data-l10n-id="pdfjs-cursor-hand-tool-button-label"></span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="horizontalToolbarSeparator"></div>
|
||||
|
||||
<div id="scrollModeButtons" role="radiogroup">
|
||||
<button id="scrollPage" class="toolbarButton labeled" type="button" tabindex="0" data-l10n-id="pdfjs-scroll-page-button" role="radio" aria-checked="false">
|
||||
<span data-l10n-id="pdfjs-scroll-page-button-label"></span>
|
||||
</button>
|
||||
<button id="scrollVertical" class="toolbarButton labeled toggled" type="button" tabindex="0" data-l10n-id="pdfjs-scroll-vertical-button" role="radio" aria-checked="true">
|
||||
<span data-l10n-id="pdfjs-scroll-vertical-button-label"></span>
|
||||
</button>
|
||||
<button id="scrollHorizontal" class="toolbarButton labeled" type="button" tabindex="0" data-l10n-id="pdfjs-scroll-horizontal-button" role="radio" aria-checked="false">
|
||||
<span data-l10n-id="pdfjs-scroll-horizontal-button-label"></span>
|
||||
</button>
|
||||
<button id="scrollWrapped" class="toolbarButton labeled" type="button" tabindex="0" data-l10n-id="pdfjs-scroll-wrapped-button" role="radio" aria-checked="false">
|
||||
<span data-l10n-id="pdfjs-scroll-wrapped-button-label"></span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="horizontalToolbarSeparator"></div>
|
||||
|
||||
<div id="spreadModeButtons" role="radiogroup">
|
||||
<button id="spreadNone" class="toolbarButton labeled toggled" type="button" tabindex="0" data-l10n-id="pdfjs-spread-none-button" role="radio" aria-checked="true">
|
||||
<span data-l10n-id="pdfjs-spread-none-button-label"></span>
|
||||
</button>
|
||||
<button id="spreadOdd" class="toolbarButton labeled" type="button" tabindex="0" data-l10n-id="pdfjs-spread-odd-button" role="radio" aria-checked="false">
|
||||
<span data-l10n-id="pdfjs-spread-odd-button-label"></span>
|
||||
</button>
|
||||
<button id="spreadEven" class="toolbarButton labeled" type="button" tabindex="0" data-l10n-id="pdfjs-spread-even-button" role="radio" aria-checked="false">
|
||||
<span data-l10n-id="pdfjs-spread-even-button-label"></span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div id="imageAltTextSettingsSeparator" class="horizontalToolbarSeparator hidden"></div>
|
||||
<button id="imageAltTextSettings" type="button" class="toolbarButton labeled hidden" tabindex="0" data-l10n-id="pdfjs-image-alt-text-settings-button" aria-controls="altTextSettingsDialog">
|
||||
<span data-l10n-id="pdfjs-image-alt-text-settings-button-label"></span>
|
||||
</button>
|
||||
|
||||
<div class="horizontalToolbarSeparator"></div>
|
||||
|
||||
<button id="documentProperties" class="toolbarButton labeled" type="button" tabindex="0" data-l10n-id="pdfjs-document-properties-button" aria-controls="documentPropertiesDialog">
|
||||
<span data-l10n-id="pdfjs-document-properties-button-label"></span>
|
||||
</button>
|
||||
</div>
|
||||
</div> <!-- secondaryToolbar -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="loadingBar">
|
||||
<div class="progress">
|
||||
<div class="glimmer">
|
||||
@@ -366,10 +369,10 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="viewerContainer" tabindex="0">
|
||||
<div id="viewer" class="pdfViewer"></div>
|
||||
</div>
|
||||
|
||||
</div> <!-- mainContainer -->
|
||||
|
||||
<div id="dialogContainer">
|
||||
@@ -701,33 +704,33 @@
|
||||
</div>
|
||||
|
||||
<!-- Zona derecha - Tabs de información -->
|
||||
<div x-data="{ activeTab: 'properties' }" class="w-1/2 flex flex-col bg-white">
|
||||
<div x-data="{ activeTab: 'properties' }" class="flex flex-col bg-white">
|
||||
<!-- Tabs de navegación -->
|
||||
<div class="border-b border-gray-200">
|
||||
<nav class="flex space-x-4 px-4 pt-2">
|
||||
<button @click="activeTab = 'properties'"
|
||||
:class="activeTab === 'properties' ? 'border-blue-500 text-blue-600' : 'border-transparent text-gray-500 hover:text-gray-700'"
|
||||
class="py-4 px-1 border-b-2 font-medium">
|
||||
class="py-1 px-1 border-b-2 font-medium">
|
||||
Propiedades
|
||||
</button>
|
||||
<button @click="activeTab = 'security'"
|
||||
:class="activeTab === 'security' ? 'border-blue-500 text-blue-600' : 'border-transparent text-gray-500 hover:text-gray-700'"
|
||||
class="py-4 px-1 border-b-2 font-medium">
|
||||
class="py-1 px-1 border-b-2 font-medium">
|
||||
Seguridad
|
||||
</button>
|
||||
<button @click="activeTab = 'comments'"
|
||||
:class="activeTab === 'comments' ? 'border-blue-500 text-blue-600' : 'border-transparent text-gray-500 hover:text-gray-700'"
|
||||
class="py-4 px-1 border-b-2 font-medium">
|
||||
class="py-1 px-1 border-b-2 font-medium">
|
||||
Comentarios
|
||||
</button>
|
||||
<button @click="activeTab = 'history'"
|
||||
:class="activeTab === 'history' ? 'border-blue-500 text-blue-600' : 'border-transparent text-gray-500 hover:text-gray-700'"
|
||||
class="py-4 px-1 border-b-2 font-medium">
|
||||
class="py-1 px-1 border-b-2 font-medium">
|
||||
Historial
|
||||
</button>
|
||||
<button @click="activeTab = 'relations'"
|
||||
:class="activeTab === 'relations' ? 'border-blue-500 text-blue-600' : 'border-transparent text-gray-500 hover:text-gray-700'"
|
||||
class="py-4 px-1 border-b-2 font-medium">
|
||||
class="py-1 px-1 border-b-2 font-medium">
|
||||
Relaciones
|
||||
</button>
|
||||
</nav>
|
||||
@@ -774,8 +777,22 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@push('scripts')
|
||||
<script>
|
||||
window.OptionKind = window.OptionKind || { VIEWER: 0, API: 1 };
|
||||
|
||||
const PDF_URL = @json(Storage::url($document->file_path));
|
||||
console.log("PDF URL:", PDF_URL);
|
||||
|
||||
window.PDFViewerApplicationOptions = {
|
||||
defaultUrl: {
|
||||
value: encodeURI(PDF_URL),
|
||||
kind: OptionKind.VIEWER
|
||||
},
|
||||
cMapUrl: '/js/pdfjs-5.2.133-dist/web/cmaps/',
|
||||
cMapPacked: true
|
||||
};
|
||||
</script>
|
||||
|
||||
@vite([
|
||||
'resources/js/pdfjs-5.2.133-dist/build/pdf.mjs',
|
||||
@@ -783,280 +800,20 @@
|
||||
'resources/js/pdfjs-5.2.133-dist/web/viewer.css'
|
||||
])
|
||||
|
||||
@endpush
|
||||
|
||||
<script type="module">
|
||||
/*
|
||||
const pdfjsVersion = "5.2.133";
|
||||
const pdfjsBuild = "4f7761353";
|
||||
const AppConstants = {
|
||||
LinkTarget: LinkTarget,
|
||||
RenderingStates: RenderingStates,
|
||||
ScrollMode: ScrollMode,
|
||||
SpreadMode: SpreadMode
|
||||
};
|
||||
window.PDFViewerApplication = PDFViewerApplication;
|
||||
window.PDFViewerApplicationConstants = AppConstants;
|
||||
window.PDFViewerApplicationOptions = AppOptions;
|
||||
function getViewerConfiguration() {
|
||||
return {
|
||||
appContainer: document.body,
|
||||
principalContainer: document.getElementById("mainContainer"),
|
||||
mainContainer: document.getElementById("viewerContainer"),
|
||||
viewerContainer: document.getElementById("viewer"),
|
||||
toolbar: {
|
||||
container: document.getElementById("toolbarContainer"),
|
||||
numPages: document.getElementById("numPages"),
|
||||
pageNumber: document.getElementById("pageNumber"),
|
||||
scaleSelect: document.getElementById("scaleSelect"),
|
||||
customScaleOption: document.getElementById("customScaleOption"),
|
||||
previous: document.getElementById("previous"),
|
||||
next: document.getElementById("next"),
|
||||
zoomIn: document.getElementById("zoomInButton"),
|
||||
zoomOut: document.getElementById("zoomOutButton"),
|
||||
print: document.getElementById("printButton"),
|
||||
editorFreeTextButton: document.getElementById("editorFreeTextButton"),
|
||||
editorFreeTextParamsToolbar: document.getElementById("editorFreeTextParamsToolbar"),
|
||||
editorHighlightButton: document.getElementById("editorHighlightButton"),
|
||||
editorHighlightParamsToolbar: document.getElementById("editorHighlightParamsToolbar"),
|
||||
editorHighlightColorPicker: document.getElementById("editorHighlightColorPicker"),
|
||||
editorInkButton: document.getElementById("editorInkButton"),
|
||||
editorInkParamsToolbar: document.getElementById("editorInkParamsToolbar"),
|
||||
editorStampButton: document.getElementById("editorStampButton"),
|
||||
editorStampParamsToolbar: document.getElementById("editorStampParamsToolbar"),
|
||||
editorSignatureButton: document.getElementById("editorSignatureButton"),
|
||||
editorSignatureParamsToolbar: document.getElementById("editorSignatureParamsToolbar"),
|
||||
download: document.getElementById("downloadButton")
|
||||
},
|
||||
secondaryToolbar: {
|
||||
toolbar: document.getElementById("secondaryToolbar"),
|
||||
toggleButton: document.getElementById("secondaryToolbarToggleButton"),
|
||||
presentationModeButton: document.getElementById("presentationMode"),
|
||||
openFileButton: document.getElementById("secondaryOpenFile"),
|
||||
printButton: document.getElementById("secondaryPrint"),
|
||||
downloadButton: document.getElementById("secondaryDownload"),
|
||||
viewBookmarkButton: document.getElementById("viewBookmark"),
|
||||
firstPageButton: document.getElementById("firstPage"),
|
||||
lastPageButton: document.getElementById("lastPage"),
|
||||
pageRotateCwButton: document.getElementById("pageRotateCw"),
|
||||
pageRotateCcwButton: document.getElementById("pageRotateCcw"),
|
||||
cursorSelectToolButton: document.getElementById("cursorSelectTool"),
|
||||
cursorHandToolButton: document.getElementById("cursorHandTool"),
|
||||
scrollPageButton: document.getElementById("scrollPage"),
|
||||
scrollVerticalButton: document.getElementById("scrollVertical"),
|
||||
scrollHorizontalButton: document.getElementById("scrollHorizontal"),
|
||||
scrollWrappedButton: document.getElementById("scrollWrapped"),
|
||||
spreadNoneButton: document.getElementById("spreadNone"),
|
||||
spreadOddButton: document.getElementById("spreadOdd"),
|
||||
spreadEvenButton: document.getElementById("spreadEven"),
|
||||
imageAltTextSettingsButton: document.getElementById("imageAltTextSettings"),
|
||||
imageAltTextSettingsSeparator: document.getElementById("imageAltTextSettingsSeparator"),
|
||||
documentPropertiesButton: document.getElementById("documentProperties")
|
||||
},
|
||||
sidebar: {
|
||||
outerContainer: document.getElementById("outerContainer"),
|
||||
sidebarContainer: document.getElementById("sidebarContainer"),
|
||||
toggleButton: document.getElementById("sidebarToggleButton"),
|
||||
resizer: document.getElementById("sidebarResizer"),
|
||||
thumbnailButton: document.getElementById("viewThumbnail"),
|
||||
outlineButton: document.getElementById("viewOutline"),
|
||||
attachmentsButton: document.getElementById("viewAttachments"),
|
||||
layersButton: document.getElementById("viewLayers"),
|
||||
thumbnailView: document.getElementById("thumbnailView"),
|
||||
outlineView: document.getElementById("outlineView"),
|
||||
attachmentsView: document.getElementById("attachmentsView"),
|
||||
layersView: document.getElementById("layersView"),
|
||||
currentOutlineItemButton: document.getElementById("currentOutlineItem")
|
||||
},
|
||||
findBar: {
|
||||
bar: document.getElementById("findbar"),
|
||||
toggleButton: document.getElementById("viewFindButton"),
|
||||
findField: document.getElementById("findInput"),
|
||||
highlightAllCheckbox: document.getElementById("findHighlightAll"),
|
||||
caseSensitiveCheckbox: document.getElementById("findMatchCase"),
|
||||
matchDiacriticsCheckbox: document.getElementById("findMatchDiacritics"),
|
||||
entireWordCheckbox: document.getElementById("findEntireWord"),
|
||||
findMsg: document.getElementById("findMsg"),
|
||||
findResultsCount: document.getElementById("findResultsCount"),
|
||||
findPreviousButton: document.getElementById("findPreviousButton"),
|
||||
findNextButton: document.getElementById("findNextButton")
|
||||
},
|
||||
passwordOverlay: {
|
||||
dialog: document.getElementById("passwordDialog"),
|
||||
label: document.getElementById("passwordText"),
|
||||
input: document.getElementById("password"),
|
||||
submitButton: document.getElementById("passwordSubmit"),
|
||||
cancelButton: document.getElementById("passwordCancel")
|
||||
},
|
||||
documentProperties: {
|
||||
dialog: document.getElementById("documentPropertiesDialog"),
|
||||
closeButton: document.getElementById("documentPropertiesClose"),
|
||||
fields: {
|
||||
fileName: document.getElementById("fileNameField"),
|
||||
fileSize: document.getElementById("fileSizeField"),
|
||||
title: document.getElementById("titleField"),
|
||||
author: document.getElementById("authorField"),
|
||||
subject: document.getElementById("subjectField"),
|
||||
keywords: document.getElementById("keywordsField"),
|
||||
creationDate: document.getElementById("creationDateField"),
|
||||
modificationDate: document.getElementById("modificationDateField"),
|
||||
creator: document.getElementById("creatorField"),
|
||||
producer: document.getElementById("producerField"),
|
||||
version: document.getElementById("versionField"),
|
||||
pageCount: document.getElementById("pageCountField"),
|
||||
pageSize: document.getElementById("pageSizeField"),
|
||||
linearized: document.getElementById("linearizedField")
|
||||
}
|
||||
},
|
||||
altTextDialog: {
|
||||
dialog: document.getElementById("altTextDialog"),
|
||||
optionDescription: document.getElementById("descriptionButton"),
|
||||
optionDecorative: document.getElementById("decorativeButton"),
|
||||
textarea: document.getElementById("descriptionTextarea"),
|
||||
cancelButton: document.getElementById("altTextCancel"),
|
||||
saveButton: document.getElementById("altTextSave")
|
||||
},
|
||||
newAltTextDialog: {
|
||||
dialog: document.getElementById("newAltTextDialog"),
|
||||
title: document.getElementById("newAltTextTitle"),
|
||||
descriptionContainer: document.getElementById("newAltTextDescriptionContainer"),
|
||||
textarea: document.getElementById("newAltTextDescriptionTextarea"),
|
||||
disclaimer: document.getElementById("newAltTextDisclaimer"),
|
||||
learnMore: document.getElementById("newAltTextLearnMore"),
|
||||
imagePreview: document.getElementById("newAltTextImagePreview"),
|
||||
createAutomatically: document.getElementById("newAltTextCreateAutomatically"),
|
||||
createAutomaticallyButton: document.getElementById("newAltTextCreateAutomaticallyButton"),
|
||||
downloadModel: document.getElementById("newAltTextDownloadModel"),
|
||||
downloadModelDescription: document.getElementById("newAltTextDownloadModelDescription"),
|
||||
error: document.getElementById("newAltTextError"),
|
||||
errorCloseButton: document.getElementById("newAltTextCloseButton"),
|
||||
cancelButton: document.getElementById("newAltTextCancel"),
|
||||
notNowButton: document.getElementById("newAltTextNotNow"),
|
||||
saveButton: document.getElementById("newAltTextSave")
|
||||
},
|
||||
altTextSettingsDialog: {
|
||||
dialog: document.getElementById("altTextSettingsDialog"),
|
||||
createModelButton: document.getElementById("createModelButton"),
|
||||
aiModelSettings: document.getElementById("aiModelSettings"),
|
||||
learnMore: document.getElementById("altTextSettingsLearnMore"),
|
||||
deleteModelButton: document.getElementById("deleteModelButton"),
|
||||
downloadModelButton: document.getElementById("downloadModelButton"),
|
||||
showAltTextDialogButton: document.getElementById("showAltTextDialogButton"),
|
||||
altTextSettingsCloseButton: document.getElementById("altTextSettingsCloseButton"),
|
||||
closeButton: document.getElementById("altTextSettingsCloseButton")
|
||||
},
|
||||
addSignatureDialog: {
|
||||
dialog: document.getElementById("addSignatureDialog"),
|
||||
panels: document.getElementById("addSignatureActionContainer"),
|
||||
typeButton: document.getElementById("addSignatureTypeButton"),
|
||||
typeInput: document.getElementById("addSignatureTypeInput"),
|
||||
drawButton: document.getElementById("addSignatureDrawButton"),
|
||||
drawSVG: document.getElementById("addSignatureDraw"),
|
||||
drawPlaceholder: document.getElementById("addSignatureDrawPlaceholder"),
|
||||
drawThickness: document.getElementById("addSignatureDrawThickness"),
|
||||
imageButton: document.getElementById("addSignatureImageButton"),
|
||||
imageSVG: document.getElementById("addSignatureImage"),
|
||||
imagePlaceholder: document.getElementById("addSignatureImagePlaceholder"),
|
||||
imagePicker: document.getElementById("addSignatureFilePicker"),
|
||||
imagePickerLink: document.getElementById("addSignatureImageBrowse"),
|
||||
description: document.getElementById("addSignatureDescription"),
|
||||
clearButton: document.getElementById("clearSignatureButton"),
|
||||
saveContainer: document.getElementById("addSignatureSaveContainer"),
|
||||
saveCheckbox: document.getElementById("addSignatureSaveCheckbox"),
|
||||
errorBar: document.getElementById("addSignatureError"),
|
||||
errorCloseButton: document.getElementById("addSignatureErrorCloseButton"),
|
||||
cancelButton: document.getElementById("addSignatureCancelButton"),
|
||||
addButton: document.getElementById("addSignatureAddButton")
|
||||
},
|
||||
editSignatureDialog: {
|
||||
dialog: document.getElementById("editSignatureDescriptionDialog"),
|
||||
description: document.getElementById("editSignatureDescription"),
|
||||
editSignatureView: document.getElementById("editSignatureView"),
|
||||
cancelButton: document.getElementById("editSignatureCancelButton"),
|
||||
updateButton: document.getElementById("editSignatureUpdateButton")
|
||||
},
|
||||
annotationEditorParams: {
|
||||
editorFreeTextFontSize: document.getElementById("editorFreeTextFontSize"),
|
||||
editorFreeTextColor: document.getElementById("editorFreeTextColor"),
|
||||
editorInkColor: document.getElementById("editorInkColor"),
|
||||
editorInkThickness: document.getElementById("editorInkThickness"),
|
||||
editorInkOpacity: document.getElementById("editorInkOpacity"),
|
||||
editorStampAddImage: document.getElementById("editorStampAddImage"),
|
||||
editorSignatureAddSignature: document.getElementById("editorSignatureAddSignature"),
|
||||
editorFreeHighlightThickness: document.getElementById("editorFreeHighlightThickness"),
|
||||
editorHighlightShowAll: document.getElementById("editorHighlightShowAll")
|
||||
},
|
||||
printContainer: document.getElementById("printContainer"),
|
||||
editorUndoBar: {
|
||||
container: document.getElementById("editorUndoBar"),
|
||||
message: document.getElementById("editorUndoBarMessage"),
|
||||
undoButton: document.getElementById("editorUndoBarUndoButton"),
|
||||
closeButton: document.getElementById("editorUndoBarCloseButton")
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Función para cargar viewer.js dinámicamente
|
||||
function loadViewerJS() {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (typeof PDFViewerApplication !== 'undefined') {
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
const script = document.createElement('script');
|
||||
script.src = 'viewer.js'; // Asegúrate de que la ruta sea correcta
|
||||
script.onload = resolve;
|
||||
script.onerror = reject;
|
||||
document.head.appendChild(script);
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
PDFViewerApplication.initializedPromise.then(() => {
|
||||
// Pasar un OBJETO con { url: TU_URL }
|
||||
PDFViewerApplication.open({
|
||||
url: encodeURI(PDF_URL), // Propiedad requerida
|
||||
originalUrl: PDF_URL // Opcional (para mostrar en la UI)
|
||||
}).catch(error => {
|
||||
console.error('Error cargando PDF:', error);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function webViewerLoad() {
|
||||
// Espera a que viewer.js esté cargado
|
||||
await loadViewerJS();
|
||||
|
||||
const config = getViewerConfiguration();
|
||||
const event = new CustomEvent("webviewerloaded", {
|
||||
bubbles: true,
|
||||
cancelable: true,
|
||||
detail: {
|
||||
source: window
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
parent.document.dispatchEvent(event);
|
||||
} catch (ex) {
|
||||
console.error("webviewerloaded:", ex);
|
||||
document.dispatchEvent(event);
|
||||
}
|
||||
|
||||
// Ahora PDFViewerApplication está disponible
|
||||
PDFViewerApplication.run(config);
|
||||
}
|
||||
|
||||
// Inicialización modificada
|
||||
document.blockUnblockOnload?.(true);
|
||||
|
||||
if (document.readyState === "interactive" || document.readyState === "complete") {
|
||||
webViewerLoad();
|
||||
} else {
|
||||
document.addEventListener("DOMContentLoaded", webViewerLoad, true);
|
||||
}
|
||||
|
||||
// Exporta desde el objeto global
|
||||
const PDFViewerApplication = window.PDFViewerApplication;
|
||||
const PDFViewerApplicationConstants = window.AppConstants;
|
||||
const PDFViewerApplicationOptions = window.AppOptions;
|
||||
|
||||
export {
|
||||
PDFViewerApplication,
|
||||
PDFViewerApplicationConstants,
|
||||
PDFViewerApplicationOptions
|
||||
};*/
|
||||
|
||||
</script>
|
||||
@endpush
|
||||
|
||||
</x-layouts.app>
|
||||
|
||||
|
||||
@@ -1,142 +1,309 @@
|
||||
<div>
|
||||
<!-- Header y Breadcrumbs -->
|
||||
<div class="p-4 bg-white border-b">
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
<nav class="flex space-x-2 text-sm">
|
||||
<a wire:click="currentFolder = null" class="cursor-pointer text-gray-600 hover:text-blue-600">
|
||||
Inicio
|
||||
</a>
|
||||
@foreach($this->breadcrumbs as $folder)
|
||||
<span class="text-gray-400">/</span>
|
||||
<a wire:click="selectFolder({{ $folder->id }})"
|
||||
class="cursor-pointer text-gray-600 hover:text-blue-600">
|
||||
{{ $folder->name }}
|
||||
</a>
|
||||
@endforeach
|
||||
</nav>
|
||||
<h1 class="mt-2 text-2xl font-bold">{{ $project->name }}</h1>
|
||||
<div class="bg-white mb-6 flex content-start justify-between">
|
||||
<!-- User Info Left -->
|
||||
<div class="flex space-x-6 content-start">
|
||||
<!-- Icono -->
|
||||
<flux:icon.bolt class="w-24 h-24 shadow-lg object-cover border-1 border-gray-600"/>
|
||||
|
||||
<!-- Project Details -->
|
||||
<div class="flex flex-col content-start">
|
||||
<h1 class="text-2xl font-bold text-gray-700">
|
||||
{{ $project->name }}
|
||||
</h1>
|
||||
|
||||
<!-- Contact Info -->
|
||||
<div class="mt-2 ">
|
||||
<div class="flex items-center text-gray-600">
|
||||
<p class="text-sm text-gray-700">
|
||||
{{ $project->reference }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@if($project->phone)
|
||||
<div class="flex items-center text-gray-600">
|
||||
<svg class="w-5 h-5 mr-2" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M6.62 10.79c1.44 2.83 3.76 5.14 6.59 6.59l2.2-2.2c.27-.27.67-.36 1.02-.24 1.12.37 2.33.57 3.57.57.55 0 1 .45 1 1V20c0 .55-.45 1-1 1-9.39 0-17-7.61-17-17 0-.55.45-1 1-1h3.5c.55 0 1 .45 1 1 0 1.25.2 2.45.57 3.57.11.35.03.74-.25 1.02l-2.2 2.2z"/>
|
||||
</svg>
|
||||
<a href="tel:{{ $project->phone }}" class="hover:text-blue-600">
|
||||
{{ $project->phone }}
|
||||
</a>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
<a href="{{ route('projects.edit', $project) }}"
|
||||
class="px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg flex items-center justify-center">
|
||||
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z"/>
|
||||
</svg>
|
||||
Editar
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Right Section -->
|
||||
<div class="flex flex-col items-end space-y-4">
|
||||
<!-- Navigation Toolbar -->
|
||||
<div class="flex space-x-2">
|
||||
<flux:button
|
||||
href="{{ route('projects.index') }}"
|
||||
icon:trailing="arrow-uturn-left"
|
||||
variant="ghost"
|
||||
>
|
||||
</flux:button>
|
||||
<flux:button
|
||||
href="{{ route('projects.index') }}"
|
||||
icon:trailing="chevron-left"
|
||||
variant="ghost"
|
||||
>
|
||||
</flux:button>
|
||||
<flux:button
|
||||
href="{{ route('projects.index') }}"
|
||||
icon:trailing="chevron-right"
|
||||
variant="ghost"
|
||||
>
|
||||
</flux:button>
|
||||
</div>
|
||||
|
||||
<!-- Status Badge -->
|
||||
<span class="px-4 py-2 w-30 rounded-lg text-sm text-center font-semibold
|
||||
{{ $project->is_active ? 'bg-green-600 text-white' : 'bg-red-100 text-red-800' }}">
|
||||
{{ $project->is_active ? 'Activo' : 'Inactivo' }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div wire:loading wire:target="files" class="fixed top-0 right-0 p-4 bg-blue-100 text-blue-800">
|
||||
Subiendo archivos...
|
||||
</div>
|
||||
|
||||
<!-- Contenedor principal con layout de explorador -->
|
||||
<div class="flex flex-col h-full">
|
||||
<!-- Barra de herramientas -->
|
||||
<div class="flex items-center justify-between p-4 bg-white border-b">
|
||||
<div class="flex items-center space-x-4">
|
||||
<!-- Botón Nueva Carpeta -->
|
||||
<button wire:click="showCreateFolderModal" class="flex items-center p-2 text-gray-600 hover:bg-gray-100 rounded">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5 mr-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 13h6m-3-3v6m-9 1V7a2 2 0 012-2h6l2 2h6a2 2 0 012 2v8a2 2 0 01-2 2H5a2 2 0 01-2-2z" />
|
||||
</svg>
|
||||
<span class="text-sm">Nueva carpeta</span>
|
||||
|
||||
<!-- Contend: -->
|
||||
<div x-data="{ activeTab: 'info' }" class="bg-white rounded-lg shadow-md border-1">
|
||||
<!-- Tab Headers -->
|
||||
<div class="border-b border-gray-200">
|
||||
<nav class="flex space-x-8 px-6">
|
||||
<button @click="activeTab = 'info'"
|
||||
:class="activeTab === 'info' ? 'border-blue-500 text-blue-600' : 'border-transparent text-gray-500 hover:text-gray-700'"
|
||||
class="py-4 px-1 border-b-2 font-medium">
|
||||
Project
|
||||
</button>
|
||||
|
||||
<!-- Botón Subir Archivos (versión con button) -->
|
||||
<div class="relative">
|
||||
<button
|
||||
wire:click="openUploadModal"
|
||||
class="flex items-center p-2 text-gray-600 hover:bg-gray-100 rounded">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M12 16.5V9.75m0 0 3 3m-3-3-3 3M6.75 19.5a4.5 4.5 0 0 1-1.41-8.775 5.25 5.25 0 0 1 10.233-2.33 3 3 0 0 1 3.758 3.848A3.752 3.752 0 0 1 18 19.5H6.75Z" />
|
||||
</svg>
|
||||
<span class="text-sm">Subir archivos</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<button @click="activeTab = 'contacts'"
|
||||
:class="activeTab === 'contacts' ? 'border-blue-500 text-blue-600' : 'border-transparent text-gray-500 hover:text-gray-700'"
|
||||
class="py-4 px-1 border-b-2 font-medium">
|
||||
Contactos
|
||||
</button>
|
||||
|
||||
<button @click="activeTab = 'documents'"
|
||||
:class="activeTab === 'documents' ? 'border-blue-500 text-blue-600' : 'border-transparent text-gray-500 hover:text-gray-700'"
|
||||
class="py-4 px-1 border-b-2 font-medium">
|
||||
Documentos
|
||||
</button>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
<!-- Contenido principal (treeview + documentos) -->
|
||||
<div class="flex flex-1 overflow-hidden">
|
||||
<!-- Treeview de Carpetas -->
|
||||
<div class="w-64 h-full overflow-y-auto border-r bg-white">
|
||||
<div class="p-4">
|
||||
<ul class="space-y-1">
|
||||
@foreach($project->rootFolders as $folder)
|
||||
<x-folder-item
|
||||
:folder="$folder"
|
||||
:currentFolder="$currentFolder"
|
||||
:expandedFolders="$expandedFolders"
|
||||
wire:key="folder-{{ $folder->id }}"
|
||||
:itemsCount="$this->documents->count()"
|
||||
/>
|
||||
@endforeach
|
||||
</ul>
|
||||
<!-- Tab Content -->
|
||||
<div class="p-6">
|
||||
<!-- Info Tab -->
|
||||
<div x-show="activeTab === 'info'">
|
||||
|
||||
<div class="flex flex-wrap gap-6">
|
||||
<!-- Columna Izquierda - Información -->
|
||||
<div class="w-full md:w-[calc(50%-12px)]">
|
||||
<div class="overflow-x-auto">
|
||||
<table class="min-w-full divide-y divide-gray-200">
|
||||
<tbody class="bg-white divide-y divide-gray-200">
|
||||
@foreach(['name' => 'Nombre', 'last_name' => 'Apellido', 'email' => 'Email', 'phone' => 'Teléfono', 'created_at' => 'Fecha Registro'] as $field => $label)
|
||||
<tr>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">{{ $label }}</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
||||
{{ $project->$field ?? 'N/A' }}
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Columna Derecha - Descripción del Proyecto -->
|
||||
<div class="w-full md:w-[calc(50%-12px)]"> <!-- 50% - gap/2 -->
|
||||
<div class="bg-white p-6 rounded-lg shadow-sm">
|
||||
<h3 class="whitespace-nowrap text-sm font-medium text-gray-900"">Descripción</h3>
|
||||
<div class="py-2 prose max-w-none text-gray-500">
|
||||
{!! $project->description ? $project->description : '<p class="text-gray-400">N/A</p>' !!}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Action Buttons -->
|
||||
<div class="mt-6 flex justify-end space-x-4">
|
||||
<a href="{{ route('projects.edit', $project) }}"
|
||||
class="w-[150px] px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg flex items-center justify-center">
|
||||
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z"/>
|
||||
</svg>
|
||||
Editar
|
||||
</a>
|
||||
|
||||
{{-- Formulario de Edición --}}
|
||||
<form method="POST" action="{{ route('projects.update', $project) }}">
|
||||
@csrf
|
||||
@method('PUT') <!-- Important! -->
|
||||
<button type="submit"
|
||||
class="w-[150px] px-4 py-2 bg-yellow-500 hover:bg-yellow-600 text-white rounded-lg flex items-center justify-center">
|
||||
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M18.364 18.364A9 9 0 005.636 5.636m12.728 12.728A9 9 0 015.636 5.636m12.728 12.728L5.636 5.636"/>
|
||||
</svg>
|
||||
{{ $project->is_active ? 'Desactivar' : 'Activar' }}
|
||||
</button>
|
||||
</form>
|
||||
|
||||
{{-- Formulario de Eliminación --}}
|
||||
<form method="POST" action="{{ route('projects.destroy', $project) }}">
|
||||
@csrf
|
||||
@method('DELETE') <!-- Important! -->
|
||||
<button type="submit"
|
||||
onclick="return confirm('¿Estás seguro de querer eliminar este usuario?')"
|
||||
class="px-4 py-2 w-[150px] bg-red-600 hover:bg-red-700 text-white rounded-lg flex items-center justify-center">
|
||||
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"/>
|
||||
</svg>
|
||||
Eliminar
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Documentos -->
|
||||
<div class="flex-1 overflow-auto bg-white">
|
||||
<div class="overflow-x-auto">
|
||||
<table class="min-w-full divide-y divide-gray-200">
|
||||
<thead class="bg-gray-50 sticky top-0">
|
||||
<tr>
|
||||
<th class="px-6 py-3 text-xs font-medium tracking-wider text-left text-gray-500 uppercase">Nombre - javi</th>
|
||||
<th class="px-6 py-3 text-xs font-medium tracking-wider text-left text-gray-500 uppercase">Versiones</th>
|
||||
<th class="px-6 py-3 text-xs font-medium tracking-wider text-left text-gray-500 uppercase">Última Actualización</th>
|
||||
<th class="px-6 py-3 text-xs font-medium tracking-wider text-left text-gray-500 uppercase">Estado</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="bg-white divide-y divide-gray-200">
|
||||
@forelse($this->documents as $document)
|
||||
<tr class="hover:bg-gray-50">
|
||||
<td class="px-6 py-4 whitespace-nowrap">
|
||||
<div class="flex items-center">
|
||||
<a href="{{ route('documents.show', $document) }}"
|
||||
target="_blank"
|
||||
class="flex items-center hover:text-blue-600 transition-colors">
|
||||
@php
|
||||
$type = App\Helpers\FileHelper::getFileType($document->name);
|
||||
$iconComponent = $iconComponent = "icons." . $type;
|
||||
<!-- Contact Tab -->
|
||||
<div x-show="activeTab === 'contacts'" x-cloak>
|
||||
</div>
|
||||
|
||||
$iconClass = [
|
||||
'pdf' => 'pdf text-red-500',
|
||||
'word' => 'word text-blue-500',
|
||||
'excel' => 'excel text-green-500',
|
||||
// ... agregar todos los tipos
|
||||
][$type] ?? 'document text-gray-400';
|
||||
@endphp
|
||||
<!-- Permissions Tab -->
|
||||
<div x-show="activeTab === 'documents'" x-cloak>
|
||||
<!-- Contenedor principal con layout de explorador -->
|
||||
<div class="flex flex-col h-full">
|
||||
<!-- Barra de herramientas -->
|
||||
<div class="flex items-center justify-between p-2 bg-white border-b">
|
||||
<div class="flex items-center space-x-4">
|
||||
<!-- Botón Nueva Carpeta -->
|
||||
<button wire:click="showCreateFolderModal" class="flex items-center p-2 text-gray-600 hover:bg-gray-100 rounded">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5 mr-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 13h6m-3-3v6m-9 1V7a2 2 0 012-2h6l2 2h6a2 2 0 012 2v8a2 2 0 01-2 2H5a2 2 0 01-2-2z" />
|
||||
</svg>
|
||||
<span class="text-sm">Nueva carpeta</span>
|
||||
</button>
|
||||
|
||||
<x-dynamic-component
|
||||
component="{{ $iconComponent }}"
|
||||
class="w-5 h-5 mr-2 {{ explode(' ', $iconClass)[1] }}"
|
||||
/>
|
||||
<!-- Botón Subir Archivos (versión con button) -->
|
||||
<div class="relative">
|
||||
<button
|
||||
wire:click="openUploadModal"
|
||||
class="flex items-center p-2 text-gray-600 hover:bg-gray-100 rounded">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M12 16.5V9.75m0 0 3 3m-3-3-3 3M6.75 19.5a4.5 4.5 0 0 1-1.41-8.775 5.25 5.25 0 0 1 10.233-2.33 3 3 0 0 1 3.758 3.848A3.752 3.752 0 0 1 18 19.5H6.75Z" />
|
||||
</svg>
|
||||
<span class="text-sm">Subir archivos</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{ $document->name }}
|
||||
</a>
|
||||
<!-- Contenido principal (treeview + documentos) -->
|
||||
<div class="flex flex-1 overflow-hidden">
|
||||
<!-- Treeview de Carpetas -->
|
||||
<div class="w-64 h-full overflow-y-auto border bg-white">
|
||||
<div class="">
|
||||
<ul class="space-y-1">
|
||||
@foreach($project->rootFolders as $folder)
|
||||
<x-folder-item
|
||||
:folder="$folder"
|
||||
:currentFolder="$currentFolder"
|
||||
:expandedFolders="$expandedFolders"
|
||||
wire:key="folder-{{ $folder->id }}"
|
||||
:itemsCount="$this->documents->count()"
|
||||
/>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Documentos -->
|
||||
<div class="flex-1 overflow-auto bg-white">
|
||||
<div class="p-2 bg-white border-b">
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
<nav class="flex space-x-2 text-sm">
|
||||
<a wire:click="currentFolder = null" class="flex cursor-pointer text-gray-600 hover:text-blue-600">
|
||||
<flux:icon.home class="w-4 h-4"/> Inicio
|
||||
</a>
|
||||
@foreach($this->breadcrumbs as $folder)
|
||||
<span class="text-gray-400">/</span>
|
||||
<a wire:click="selectFolder({{ $folder->id }})"
|
||||
class="cursor-pointer text-gray-600 hover:text-blue-600">
|
||||
{{ $folder->name }}
|
||||
</a>
|
||||
@endforeach
|
||||
</nav>
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap">
|
||||
{{ $document->versions_count }}
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap">
|
||||
{{ $document->updated_at->diffForHumans() }}
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap">
|
||||
<x-status-badge :status="$document->status" />
|
||||
</td>
|
||||
</tr>
|
||||
@empty
|
||||
<tr>
|
||||
<td colspan="4" class="px-6 py-4 text-center text-gray-500">
|
||||
No se encontraron documentos en esta carpeta
|
||||
</td>
|
||||
</tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="overflow-x-auto">
|
||||
<table class="min-w-full divide-y divide-gray-200">
|
||||
<thead class="bg-gray-50 sticky top-0">
|
||||
<tr>
|
||||
<th class="px-6 py-3 text-xs font-medium tracking-wider text-left text-gray-500 uppercase">Nombre - javi</th>
|
||||
<th class="px-6 py-3 text-xs font-medium tracking-wider text-left text-gray-500 uppercase">Versiones</th>
|
||||
<th class="px-6 py-3 text-xs font-medium tracking-wider text-left text-gray-500 uppercase">Última Actualización</th>
|
||||
<th class="px-6 py-3 text-xs font-medium tracking-wider text-left text-gray-500 uppercase">Estado</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="bg-white divide-y divide-gray-200">
|
||||
@forelse($this->documents as $document)
|
||||
<tr class="hover:bg-gray-50">
|
||||
<td class="px-6 py-4 whitespace-nowrap">
|
||||
<div class="flex items-center">
|
||||
<a href="{{ route('documents.show', $document) }}"
|
||||
target="_blank"
|
||||
class="flex items-center hover:text-blue-600 transition-colors">
|
||||
@php
|
||||
$type = App\Helpers\FileHelper::getFileType($document->name);
|
||||
$iconComponent = $iconComponent = "icons." . $type;
|
||||
|
||||
$iconClass = [
|
||||
'pdf' => 'pdf text-red-500',
|
||||
'word' => 'word text-blue-500',
|
||||
'excel' => 'excel text-green-500',
|
||||
// ... agregar todos los tipos
|
||||
][$type] ?? 'document text-gray-400';
|
||||
@endphp
|
||||
|
||||
<x-dynamic-component
|
||||
component="{{ $iconComponent }}"
|
||||
class="w-5 h-5 mr-2 {{ explode(' ', $iconClass)[1] }}"
|
||||
/>
|
||||
|
||||
{{ $document->name }}
|
||||
</a>
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap">
|
||||
{{ $document->versions_count }}
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap">
|
||||
{{ $document->updated_at->diffForHumans() }}
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap">
|
||||
<x-status-badge :status="$document->status" />
|
||||
</td>
|
||||
</tr>
|
||||
@empty
|
||||
<tr>
|
||||
<td colspan="4" class="px-6 py-4 text-center text-gray-500">
|
||||
No se encontraron documentos en esta carpeta
|
||||
</td>
|
||||
</tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -7,11 +7,11 @@
|
||||
</button>
|
||||
|
||||
<div x-show="open" @click.outside="open = false"
|
||||
class="absolute bg-white shadow-lg rounded-lg p-4 mt-2 min-w-[200px] z-10">
|
||||
class="absolute bg-white shadow-lg rounded-lg p-4 mt-2 min-w-[200px] z-10">
|
||||
@foreach($available_columns as $key => $label)
|
||||
<label class="flex items-center gap-2 mb-2">
|
||||
<input type="checkbox" wire:model.live="columns.{{ $key }}"
|
||||
class="rounded border-gray-300">
|
||||
class="rounded border-gray-300">
|
||||
{{ $label }}
|
||||
</label>
|
||||
@endforeach
|
||||
@@ -61,120 +61,96 @@
|
||||
@endif
|
||||
@endif
|
||||
@endforeach
|
||||
|
||||
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Acciones</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-gray-200">
|
||||
@foreach($users as $user)
|
||||
<tr>
|
||||
@if($columns['full_name'])
|
||||
<td class="px-6 py-4 whitespace-nowrap">
|
||||
<a href="{{ route('users.show', $user) }}" class="flex items-center hover:text-blue-600 hover:underline group">
|
||||
<!-- Foto del usuario -->
|
||||
@if($user->profile_photo_path)
|
||||
<div class="mr-3 flex-shrink-0">
|
||||
<img src="{{ asset('storage/' . $user->profile_photo_path) }}"
|
||||
alt="{{ $user->full_name }}"
|
||||
class="w-8 h-8 rounded-full object-cover transition-transform group-hover:scale-110">
|
||||
</div>
|
||||
@else
|
||||
<div class="w-8 h-8 rounded-full bg-gray-100 mr-3 flex items-center justify-center transition-colors group-hover:bg-blue-100">
|
||||
<flux:icon.user variant="solid" class="size-4" />
|
||||
</div>
|
||||
@endif
|
||||
<!-- Iteramos dinámicamente sobre las columnas disponibles -->
|
||||
@foreach($available_columns as $key => $label)
|
||||
@if($columns[$key])
|
||||
<td class="px-6 py-4 whitespace-nowrap">
|
||||
@switch($key)
|
||||
@case('full_name')
|
||||
<a href="{{ route('users.show', $user) }}" class="flex items-center hover:text-blue-600 hover:underline group">
|
||||
@if($user->profile_photo_path)
|
||||
<div class="mr-3 flex-shrink-0">
|
||||
<img src="{{ asset('storage/' . $user->profile_photo_path) }}"
|
||||
alt="{{ $user->full_name }}"
|
||||
class="w-8 h-8 rounded-full object-cover transition-transform group-hover:scale-110">
|
||||
</div>
|
||||
@else
|
||||
<div class="w-8 h-8 rounded-full bg-gray-100 mr-3 flex items-center justify-center transition-colors group-hover:bg-blue-100">
|
||||
<flux:icon.user variant="solid" class="size-4" />
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<!-- Nombre completo con efecto hover -->
|
||||
<span class="group-hover:text-blue-600 transition-colors">
|
||||
{{ $user->full_name }}
|
||||
@if(!$user->is_active)
|
||||
<span class="text-xs text-red-500 ml-2">(Inactivo)</span>
|
||||
@endif
|
||||
</span>
|
||||
<span class="group-hover:text-blue-600 transition-colors">
|
||||
{{ $user->full_name }}
|
||||
@if(!$user->is_active)
|
||||
<span class="text-xs text-red-500 ml-2">(Inactivo)</span>
|
||||
@endif
|
||||
</span>
|
||||
</a>
|
||||
@break
|
||||
|
||||
@case('email')
|
||||
<div class="flex items-center gap-2">
|
||||
<svg class="w-4 h-4 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"/>
|
||||
</svg>
|
||||
{{ $user->email }}
|
||||
</div>
|
||||
@break
|
||||
|
||||
@case('phone')
|
||||
<div class="flex items-center gap-2">
|
||||
<svg class="w-4 h-4 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 5a2 2 0 012-2h3.28a1 1 0 01.948.684l1.498 4.493a1 1 0 01-.502 1.21l-2.257 1.13a11.042 11.042 0 005.516 5.516l1.13-2.257a1 1 0 011.21-.502l4.493 1.498a1 1 0 01.684.949V19a2 2 0 01-2 2h-1C9.716 21 3 14.284 3 6V5z"/>
|
||||
</svg>
|
||||
{{ $user->phone ?? 'N/A' }}
|
||||
</div>
|
||||
@break
|
||||
|
||||
@case('access_start')
|
||||
{{ $user->access_start?->format('d/m/Y') ?? 'N/A' }}
|
||||
@break
|
||||
|
||||
@case('created_at')
|
||||
{{ $user->created_at->format('d/m/Y H:i') }}
|
||||
@break
|
||||
|
||||
@case('is_active')
|
||||
{{ $user->is_active ? 'Activo' : 'Inactivo' }}
|
||||
@break
|
||||
|
||||
@default
|
||||
{{ $user->$key ?? 'N/A' }}
|
||||
@endswitch
|
||||
</td>
|
||||
@endif
|
||||
@endforeach
|
||||
|
||||
<td class="px-6 py-4 whitespace-nowrap">
|
||||
<!-- Acciones -->
|
||||
<div class="flex items-center gap-2">
|
||||
<!-- Botón Editar -->
|
||||
<a href="{{ route('users.edit', $user) }}"
|
||||
class="text-blue-600 hover:text-blue-900"
|
||||
title="Editar usuario">
|
||||
<flux:icon.pencil class="size-5"/>
|
||||
</a>
|
||||
</td>
|
||||
@endif
|
||||
|
||||
<td class="px-6 py-4 whitespace-nowrap">
|
||||
@if($columns['username'])
|
||||
{{ $user->username }}
|
||||
@else
|
||||
N/A
|
||||
@endif
|
||||
</td>
|
||||
<!-- Botón Eliminar -->
|
||||
<button wire:click="confirmDelete({{ $user->id }})"
|
||||
class="text-red-600 hover:text-red-900"
|
||||
title="Eliminar usuario">
|
||||
<flux:icon.trash class="size-5"/>
|
||||
</button>
|
||||
|
||||
<td class="px-6 py-4 whitespace-nowrap">
|
||||
@if($columns['email'])
|
||||
|
||||
<div class="flex items-center gap-2">
|
||||
<svg class="w-4 h-4 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"/>
|
||||
</svg>
|
||||
{{ $user->email }}
|
||||
</div>
|
||||
@else
|
||||
N/A
|
||||
@endif
|
||||
</td>
|
||||
|
||||
<td class="px-6 py-4 whitespace-nowrap">
|
||||
@if($columns['phone'])
|
||||
|
||||
<div class="flex items-center gap-2">
|
||||
<svg class="w-4 h-4 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 5a2 2 0 012-2h3.28a1 1 0 01.948.684l1.498 4.493a1 1 0 01-.502 1.21l-2.257 1.13a11.042 11.042 0 005.516 5.516l1.13-2.257a1 1 0 011.21-.502l4.493 1.498a1 1 0 01.684.949V19a2 2 0 01-2 2h-1C9.716 21 3 14.284 3 6V5z"/>
|
||||
</svg>
|
||||
{{ $user->phone ?? 'N/A' }}
|
||||
</div>
|
||||
@else
|
||||
N/A
|
||||
@endif
|
||||
</td>
|
||||
|
||||
<td class="px-6 py-4 whitespace-nowrap">
|
||||
@if($columns['access_start'])
|
||||
{{ $user->access_start?->format('d/m/Y') }}
|
||||
@else
|
||||
N/A
|
||||
@endif
|
||||
</td>
|
||||
|
||||
<td class="px-6 py-4 whitespace-nowrap">
|
||||
@if($columns['created_at'])
|
||||
{{ $user->created_at->format('d/m/Y H:i') }}
|
||||
@else
|
||||
N/A
|
||||
@endif
|
||||
</td>
|
||||
|
||||
<td class="px-6 py-4 whitespace-nowrap">
|
||||
@if($columns['is_active'])
|
||||
{{ $user->is_active ? 'Activo' : 'Inactivo' }}
|
||||
@else
|
||||
N/A
|
||||
@endif
|
||||
</td>
|
||||
|
||||
<td class="px-6 py-4 whitespace-nowrap">
|
||||
<!-- Acciones -->
|
||||
<div class="flex items-center gap-2">
|
||||
<!-- Botón Editar -->
|
||||
<a href="{{ route('users.edit', $user) }}"
|
||||
class="text-blue-600 hover:text-blue-900"
|
||||
title="Editar usuario">
|
||||
<flux:icon.pencil class="size-5"/>
|
||||
</a>
|
||||
|
||||
<!-- Botón Eliminar -->
|
||||
<button wire:click="confirmDelete({{ $user->id }})"
|
||||
class="text-red-600 hover:text-red-900"
|
||||
title="Eliminar usuario">
|
||||
<flux:icon.trash class="size-5"/>
|
||||
</button>
|
||||
|
||||
<flux:button size="sm" icon="trash" variant="ghost" inset />
|
||||
</div>
|
||||
<flux:button size="sm" icon="trash" variant="ghost" inset />
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
|
||||
@@ -66,13 +66,35 @@
|
||||
<div class="bg-white py-6">
|
||||
<table class="w-full mb-8">
|
||||
<tbody>
|
||||
<!-- Empresa -->
|
||||
<tr>
|
||||
<td class="w-1/4 py-3 pr-4 align-top">
|
||||
<x-label for="company_id" :value="__('Empresa propietaria del Proyecto')" />
|
||||
</td>
|
||||
<td class="py-3">
|
||||
<select id="company_id" name="company_id"
|
||||
class="w-[250px] border-b-1 border-gray-300 focus:border-blue-500 focus:outline-none" required>
|
||||
<option value="">Seleccione una empresa...</option>
|
||||
@foreach($companies as $company)
|
||||
<option value="{{ $company->id }}"
|
||||
{{ old('company_id', $project->company_id ?? '') == $company->id ? 'selected' : '' }}>
|
||||
{{ $company->name }}
|
||||
</option>
|
||||
@endforeach
|
||||
</select>
|
||||
@error('company_id')
|
||||
<p class="mt-2 text-sm text-red-600">{{ $message }}</p>
|
||||
@enderror
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- Referencia -->
|
||||
<tr>
|
||||
<td class="w-1/4 py-3 pr-4 align-top">
|
||||
<x-label for="reference" :value="__('Referencia')" />
|
||||
</td>
|
||||
<td class="py-3">
|
||||
<input type="text" name="reference"
|
||||
<input type="text" name="reference" id="reference"
|
||||
value="{{ old('reference', $project->reference ?? '') }}"
|
||||
class="w-[250px] border-b-1 border-gray-300 focus:border-blue-500 focus:outline-none"
|
||||
autofocus
|
||||
@@ -87,13 +109,12 @@
|
||||
<!-- Nombre -->
|
||||
<tr>
|
||||
<td class="w-1/4 py-3 pr-4 align-top">
|
||||
<x-label for="name" :value="__('Etiqueta')" />
|
||||
<x-label for="name" :value="__('Nombre')" />
|
||||
</td>
|
||||
<td class="py-3">
|
||||
<input type="text" name="name"
|
||||
value="{{ old('name', $project->name ?? '') }}"
|
||||
class="w-[500px] border-b-1 border-gray-300 focus:border-blue-500 focus:outline-none"
|
||||
autofocus
|
||||
required>
|
||||
|
||||
@error('name')
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
<!-- Listado de proyectos -->
|
||||
<div class="grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-3">
|
||||
@forelse($projects as $project)
|
||||
<div class="overflow-hidden bg-white rounded-lg shadow">
|
||||
<div class="overflow-hidden bg-white rounded-lg shadow border-1 hover:shadow-lg transition duration-300">
|
||||
<!-- Imagen del proyecto -->
|
||||
@if($project->project_image_path)
|
||||
<img src="{{ asset('storage/' . $project->project_image_path) }}"
|
||||
@@ -33,7 +33,7 @@
|
||||
class="object-cover w-full h-48 border-b">
|
||||
@endif
|
||||
|
||||
<div class="p-6">
|
||||
<div class="p-4">
|
||||
<div class="flex items-start justify-between">
|
||||
<div class="flex-1">
|
||||
<h3 class="text-lg font-semibold text-gray-900">
|
||||
@@ -42,10 +42,15 @@
|
||||
{{ $project->name }}
|
||||
</a>
|
||||
</h3>
|
||||
<a href="{{ route('projects.show', $project) }}"
|
||||
class="hover:text-blue-600 hover:underline">
|
||||
{{ $project->reference }}
|
||||
</a>
|
||||
<p class="mt-2 text-sm text-gray-500">
|
||||
{{ Str::limit($project->description, 100) }}
|
||||
{{ Str::limit(strip_tags($project->description), 200) }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<x-dropdown align="right" width="48">
|
||||
<x-slot name="trigger">
|
||||
<button class="p-1 text-gray-400 hover:text-gray-600">
|
||||
@@ -83,17 +88,14 @@
|
||||
<div class="mt-4">
|
||||
<div class="flex items-center justify-between mt-3 text-sm">
|
||||
<span class="flex items-center text-gray-500">
|
||||
<x-icons icon="document" class="w-4 h-4 mr-1" />
|
||||
<flux:icon.document class="w-4 h-4 mr-1 inline" />
|
||||
{{ $project->documents_count }} documentos
|
||||
</span>
|
||||
<span class="px-2 py-1 text-sm rounded-full
|
||||
{{ $project->status === 'active' ? 'bg-green-100 text-green-800' : 'bg-gray-100 text-gray-800' }}">
|
||||
{{ __(Str::ucfirst($project->status)) }}
|
||||
</span>
|
||||
<flux:badge variant="solid" color="{{ $project->status === 'Activo' ? 'emerald' : 'red'}}">{{ __(Str::ucfirst($project->status)) }}</flux:badge>
|
||||
</div>
|
||||
|
||||
<div class="mt-2 text-sm text-gray-500">
|
||||
<x-icons icon="calendar" class="w-4 h-4 mr-1 inline" />
|
||||
<flux:icon.calendar class="w-4 h-4 mr-1 inline" />
|
||||
Creado {{ $project->created_at->diffForHumans() }}
|
||||
</div>
|
||||
</div>
|
||||
@@ -112,27 +114,6 @@
|
||||
<!-- Sidebar menu -->
|
||||
@push('sidebar-menu')
|
||||
<flux:navlist variant="outline">
|
||||
<!-- Sección de Usuarios -->
|
||||
<flux:navlist.group :heading="__('User')">
|
||||
<flux:navlist.item
|
||||
icon="users"
|
||||
:href="route('users.index')"
|
||||
wire:navigate
|
||||
>
|
||||
{{ __('List Users') }}
|
||||
</flux:navlist.item>
|
||||
|
||||
<flux:navlist.item
|
||||
icon="user-plus"
|
||||
:href="route('users.create')"
|
||||
wire:navigate
|
||||
>
|
||||
{{ __('Create User') }}
|
||||
</flux:navlist.item>
|
||||
</flux:navlist.group>
|
||||
|
||||
<flux:separator />
|
||||
|
||||
<!-- Sección de Proyectos -->
|
||||
<flux:navlist.group :heading="__('Projects')">
|
||||
<flux:navlist.item
|
||||
|
||||
@@ -37,9 +37,9 @@
|
||||
|
||||
<form method="POST" action="{{ (isset($user) && $user->id) ? route('users.update', $user) : route('users.store') }}">
|
||||
@csrf
|
||||
@isset($user)
|
||||
@if(isset($user) && $user->id)
|
||||
@method('PUT')
|
||||
@endisset
|
||||
@endif
|
||||
|
||||
<!-- Separador -->
|
||||
<div class="relative">
|
||||
@@ -257,6 +257,23 @@
|
||||
<div class="bg-white py-6">
|
||||
<table class="w-full">
|
||||
<tbody>
|
||||
<!-- tipo de usuario -->
|
||||
<tr>
|
||||
<td class="py-2 pr-4 w-1/3">
|
||||
<label class="block text-sm font-bold text-gray-700">
|
||||
Tipo de usuario
|
||||
</label>
|
||||
</td>
|
||||
<td class="py-2">
|
||||
<div class="flex items-center gap-2">
|
||||
<select name="user_type" class="w-[200px] border-b-1 border-gray-300 focus:border-blue-500 focus:outline-none">
|
||||
<option value="0">Interno</option>
|
||||
<option value="1">Externo</option>
|
||||
</select>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- Estado -->
|
||||
<tr>
|
||||
<td class="py-2 pr-4 w-1/3">
|
||||
@@ -291,7 +308,7 @@
|
||||
<input type="hidden" name="profile_photo_path" id="profilePhotoPathInput" value="{{ old('profile_photo_path', optional($user)->profile_photo_path ?? '') }}">
|
||||
</div>
|
||||
</td>
|
||||
</tr>php
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
<x-layouts.app :title="__('Show User')" :showSidebar={{ $showSidebar }}>
|
||||
|
||||
<!-- Header Section -->
|
||||
<div class="bg-white p-6 mb-6 flex items-center justify-between">
|
||||
<div class="bg-white p-6 mb-6 flex content-start justify-between">
|
||||
<!-- User Info Left -->
|
||||
<div class="flex items-center space-x-6">
|
||||
<div class="flex content-start space-x-6">
|
||||
<!-- User Photo -->
|
||||
<flux:avatar
|
||||
class="w-24 h-24 rounded-lg shadow-lg object-cover border-2 border-gray-600"
|
||||
@@ -55,28 +55,30 @@
|
||||
<div class="flex flex-col items-end space-y-4">
|
||||
<!-- Navigation Toolbar -->
|
||||
<div class="flex space-x-2">
|
||||
<a href="{{ route('users.index') }}"
|
||||
class="px-4 py-2 bg-gray-100 hover:bg-gray-200 rounded-lg flex items-center">
|
||||
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 10h10a8 8 0 018 8v2M3 10l6 6m-6-6l6-6"/>
|
||||
</svg>
|
||||
</a>
|
||||
|
||||
<flux:button
|
||||
href="{{ route('users.index') }}"
|
||||
icon:trailing="arrow-uturn-left"
|
||||
variant="ghost"
|
||||
>
|
||||
</flux:button>
|
||||
|
||||
@if($previousUser)
|
||||
<a href="{{ route('users.show', $previousUser) }}" class="px-4 py-2 bg-gray-100 hover:bg-gray-200 rounded-lg flex items-center">
|
||||
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7"/>
|
||||
</svg>
|
||||
</a>
|
||||
<flux:button
|
||||
href="{{ route('users.show', $previousUser) }}"
|
||||
icon:trailing="chevron-left"
|
||||
variant="ghost"
|
||||
>
|
||||
</flux:button>
|
||||
@endif
|
||||
|
||||
@if($nextUser)
|
||||
<a href="{{ route('users.show', $nextUser) }}"
|
||||
class="px-4 py-2 bg-gray-100 hover:bg-gray-200 rounded-lg flex items-center">
|
||||
<svg class="w-4 h-4 ml-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"/>
|
||||
</svg>
|
||||
</a>
|
||||
<flux:button
|
||||
href="{{ route('users.show', $nextUser) }}"
|
||||
icon:trailing="chevron-right"
|
||||
variant="ghost"
|
||||
>
|
||||
</flux:button>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<?php
|
||||
|
||||
use App\Http\Controllers\CompanyController;
|
||||
use App\Http\Controllers\DashboardController;
|
||||
use App\Http\Controllers\DocumentController;
|
||||
use App\Http\Controllers\FolderController;
|
||||
@@ -38,7 +39,6 @@ Route::middleware(['auth', 'verified'])->group(function () {
|
||||
// Usuarios:
|
||||
Route::get('users/{user}/edit', [UserController::class, 'edit'])->name('users.edit');
|
||||
Route::get('/users/create', [UserController::class, 'create'])->name('users.create')->middleware('can:create-users');
|
||||
// Procesar creación de usuario
|
||||
Route::post('/users', [UserController::class, 'store'])->name('users.store')->middleware('can:create-users');
|
||||
Route::put('/usuarios/{user}', [UserController::class, 'update'])->name('users.update')->middleware('can:update,user'); // Opcional: si usas políticas
|
||||
Route::post('/users', [UserController::class, 'store'])->name('users.store');
|
||||
@@ -47,6 +47,10 @@ Route::middleware(['auth', 'verified'])->group(function () {
|
||||
Route::delete('users/{user}', [UserController::class, 'destroy'])->name('users.destroy');
|
||||
Route::get('users/{user}', [UserController::class, 'show'])->name('users.show');
|
||||
|
||||
// compañías:
|
||||
// Gestión de empresas
|
||||
Route::resource('companies', CompanyController::class)->middleware('auth'); // Si necesitas autenticación
|
||||
|
||||
// Proyectos
|
||||
Route::resource('projects', ProjectController::class)->name('projects.index', 'projects');
|
||||
//Route::get('/projects/{project}', ProjectController::class)->name('projects.show');
|
||||
|
||||
Reference in New Issue
Block a user