Merge branch 'main' of https://homehud.duckdns.org/javier/Nexora
This commit is contained in:
@@ -57,8 +57,12 @@ class UserController extends Controller
|
|||||||
'end_date' => 'nullable|date|after_or_equal:start_date',
|
'end_date' => 'nullable|date|after_or_equal:start_date',
|
||||||
'email' => 'required|email|unique:users',
|
'email' => 'required|email|unique:users',
|
||||||
'phone' => 'nullable|string|max:20',
|
'phone' => 'nullable|string|max:20',
|
||||||
|
<<<<<<< HEAD
|
||||||
'address' => 'nullable|string|max:255',
|
'address' => 'nullable|string|max:255',
|
||||||
'profile_photo_path' => 'nullable|string' // Ruta de la imagen subida por Livewire
|
'profile_photo_path' => 'nullable|string' // Ruta de la imagen subida por Livewire
|
||||||
|
=======
|
||||||
|
'address' => 'nullable|string|max:255'
|
||||||
|
>>>>>>> f97a7a84985ea300216ba3ea2ab4c31306e1659a
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Creación del usuario
|
// Creación del usuario
|
||||||
@@ -73,12 +77,20 @@ class UserController extends Controller
|
|||||||
'address' => $validated['address'],
|
'address' => $validated['address'],
|
||||||
'access_start' => $validated['start_date'],
|
'access_start' => $validated['start_date'],
|
||||||
'access_end' => $validated['end_date'],
|
'access_end' => $validated['end_date'],
|
||||||
|
<<<<<<< HEAD
|
||||||
'is_active' => true,
|
'is_active' => true,
|
||||||
'profile_photo_path' => $validated['profile_photo_path'] ?? null
|
'profile_photo_path' => $validated['profile_photo_path'] ?? null
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if ($request->hasFile('image_path')) {
|
if ($request->hasFile('image_path')) {
|
||||||
$path = $request->file('image_path')->store('public/photos');
|
$path = $request->file('image_path')->store('public/photos');
|
||||||
|
=======
|
||||||
|
'is_active' => true
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($request->hasFile('photo')) {
|
||||||
|
$path = $request->file('photo')->store('public/photos');
|
||||||
|
>>>>>>> f97a7a84985ea300216ba3ea2ab4c31306e1659a
|
||||||
$user->profile_photo_path = basename($path);
|
$user->profile_photo_path = basename($path);
|
||||||
$user->save();
|
$user->save();
|
||||||
}
|
}
|
||||||
@@ -130,11 +142,17 @@ class UserController extends Controller
|
|||||||
Rule::unique('users')->ignore($user->id)
|
Rule::unique('users')->ignore($user->id)
|
||||||
],
|
],
|
||||||
'phone' => 'nullable|string|max:20',
|
'phone' => 'nullable|string|max:20',
|
||||||
|
<<<<<<< HEAD
|
||||||
'address' => 'nullable|string|max:255',
|
'address' => 'nullable|string|max:255',
|
||||||
'profile_photo_path' => 'nullable|string', // Añadido para la ruta de la imagen
|
'profile_photo_path' => 'nullable|string', // Añadido para la ruta de la imagen
|
||||||
//'is_active' => 'nullable|boolean' // Añadido para el estado activo
|
//'is_active' => 'nullable|boolean' // Añadido para el estado activo
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
=======
|
||||||
|
'address' => 'nullable|string|max:255'
|
||||||
|
]);
|
||||||
|
|
||||||
|
>>>>>>> f97a7a84985ea300216ba3ea2ab4c31306e1659a
|
||||||
// Preparar datos para actualización
|
// Preparar datos para actualización
|
||||||
$updateData = [
|
$updateData = [
|
||||||
'title' => $validated['title'],
|
'title' => $validated['title'],
|
||||||
@@ -146,14 +164,21 @@ class UserController extends Controller
|
|||||||
'address' => $validated['address'],
|
'address' => $validated['address'],
|
||||||
'access_start' => $validated['start_date'],
|
'access_start' => $validated['start_date'],
|
||||||
'access_end' => $validated['end_date'],
|
'access_end' => $validated['end_date'],
|
||||||
|
<<<<<<< HEAD
|
||||||
'is_active' => $validated['is_active'] ?? false,
|
'is_active' => $validated['is_active'] ?? false,
|
||||||
'profile_photo_path' => $validated['profile_photo_path'] ?? $user->profile_photo_path
|
'profile_photo_path' => $validated['profile_photo_path'] ?? $user->profile_photo_path
|
||||||
];
|
];
|
||||||
|
|
||||||
|
=======
|
||||||
|
'is_active' => $request->has('is_active') // Si usas un checkbox
|
||||||
|
];
|
||||||
|
|
||||||
|
>>>>>>> f97a7a84985ea300216ba3ea2ab4c31306e1659a
|
||||||
// Actualizar contraseña solo si se proporciona
|
// Actualizar contraseña solo si se proporciona
|
||||||
if (!empty($validated['password'])) {
|
if (!empty($validated['password'])) {
|
||||||
$updateData['password'] = Hash::make($validated['password']);
|
$updateData['password'] = Hash::make($validated['password']);
|
||||||
}
|
}
|
||||||
|
<<<<<<< HEAD
|
||||||
|
|
||||||
// Eliminar imagen anterior si se está actualizando
|
// Eliminar imagen anterior si se está actualizando
|
||||||
if (isset($validated['profile_photo_path']) && $user->profile_photo_path) {
|
if (isset($validated['profile_photo_path']) && $user->profile_photo_path) {
|
||||||
@@ -171,6 +196,32 @@ class UserController extends Controller
|
|||||||
return redirect()->back()->withErrors($e->validator)->withInput();
|
return redirect()->back()->withErrors($e->validator)->withInput();
|
||||||
|
|
||||||
} catch (QueryException $e) {
|
} catch (QueryException $e) {
|
||||||
|
=======
|
||||||
|
|
||||||
|
if ($request->hasFile('photo')) {
|
||||||
|
// Eliminar foto anterior si existe
|
||||||
|
if ($user->prfile_photo_path) {
|
||||||
|
Storage::delete('public/photos/'.$user->profile_photo_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
$path = $request->file('photo')->store('public/photos');
|
||||||
|
$user->update(['profile_photo_path' => basename($path)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Actualizar el usuario
|
||||||
|
$user->update($updateData);
|
||||||
|
|
||||||
|
// Redireccionar con mensaje de éxito
|
||||||
|
return redirect()->route('users.show', $user)
|
||||||
|
->with('success', 'Usuario actualizado exitosamente');
|
||||||
|
|
||||||
|
} catch (ValidationException $e) {
|
||||||
|
// Redireccionar con errores de validación
|
||||||
|
return redirect()->back()->withErrors($e->validator)->withInput();
|
||||||
|
|
||||||
|
} catch (QueryException $e) {
|
||||||
|
// Manejar errores de base de datos
|
||||||
|
>>>>>>> f97a7a84985ea300216ba3ea2ab4c31306e1659a
|
||||||
$errorCode = $e->errorInfo[1];
|
$errorCode = $e->errorInfo[1];
|
||||||
$errorMessage = 'Error al actualizar el usuario: ';
|
$errorMessage = 'Error al actualizar el usuario: ';
|
||||||
|
|
||||||
@@ -179,11 +230,20 @@ class UserController extends Controller
|
|||||||
} else {
|
} else {
|
||||||
$errorMessage .= 'Error en la base de datos';
|
$errorMessage .= 'Error en la base de datos';
|
||||||
}
|
}
|
||||||
|
<<<<<<< HEAD
|
||||||
|
|
||||||
Log::error("Error actualizando usuario ID {$user->id}: " . $e->getMessage());
|
Log::error("Error actualizando usuario ID {$user->id}: " . $e->getMessage());
|
||||||
return redirect()->back()->with('error', $errorMessage)->withInput();
|
return redirect()->back()->with('error', $errorMessage)->withInput();
|
||||||
|
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
|
=======
|
||||||
|
|
||||||
|
Log::error("Error actualizando usuario ID {$user->id}: " . $e->getMessage());
|
||||||
|
return redirect()->back()->with('error', $errorMessage)->withInput();
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
// Manejar otros errores
|
||||||
|
>>>>>>> f97a7a84985ea300216ba3ea2ab4c31306e1659a
|
||||||
Log::error("Error general actualizando usuario ID {$user->id}: " . $e->getMessage());
|
Log::error("Error general actualizando usuario ID {$user->id}: " . $e->getMessage());
|
||||||
return redirect()->back()->with('error', 'Ocurrió un error inesperado al actualizar el usuario')->withInput();
|
return redirect()->back()->with('error', 'Ocurrió un error inesperado al actualizar el usuario')->withInput();
|
||||||
}
|
}
|
||||||
@@ -193,13 +253,20 @@ class UserController extends Controller
|
|||||||
{
|
{
|
||||||
$previousUser = User::where('id', '<', $user->id)->latest('id')->first();
|
$previousUser = User::where('id', '<', $user->id)->latest('id')->first();
|
||||||
$nextUser = User::where('id', '>', $user->id)->oldest('id')->first();
|
$nextUser = User::where('id', '>', $user->id)->oldest('id')->first();
|
||||||
|
<<<<<<< HEAD
|
||||||
$permissionGroups = $this->getPermissionGroups($user);
|
$permissionGroups = $this->getPermissionGroups($user);
|
||||||
|
=======
|
||||||
|
>>>>>>> f97a7a84985ea300216ba3ea2ab4c31306e1659a
|
||||||
|
|
||||||
return view('users.show', [
|
return view('users.show', [
|
||||||
'user' => $user,
|
'user' => $user,
|
||||||
'previousUser' => $previousUser,
|
'previousUser' => $previousUser,
|
||||||
'nextUser' => $nextUser,
|
'nextUser' => $nextUser,
|
||||||
|
<<<<<<< HEAD
|
||||||
'permissionGroups' => $permissionGroups,
|
'permissionGroups' => $permissionGroups,
|
||||||
|
=======
|
||||||
|
'permissionGroups' => Permission::all()->groupBy('group')
|
||||||
|
>>>>>>> f97a7a84985ea300216ba3ea2ab4c31306e1659a
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ class ImageUploader extends Component
|
|||||||
{
|
{
|
||||||
use WithFileUploads;
|
use WithFileUploads;
|
||||||
|
|
||||||
|
<<<<<<< HEAD
|
||||||
public $image;
|
public $image;
|
||||||
public $imagePath;
|
public $imagePath;
|
||||||
public $fieldName; // Nombre del campo para el formulario
|
public $fieldName; // Nombre del campo para el formulario
|
||||||
@@ -46,10 +47,41 @@ class ImageUploader extends Component
|
|||||||
field: $this->fieldName,
|
field: $this->fieldName,
|
||||||
path: $this->imagePath
|
path: $this->imagePath
|
||||||
);
|
);
|
||||||
|
=======
|
||||||
|
public $photo;
|
||||||
|
public $currentImage;
|
||||||
|
public $fieldName;
|
||||||
|
public $placeholder;
|
||||||
|
public $storagePath = 'tmp/uploads';
|
||||||
|
|
||||||
|
protected $rules = [
|
||||||
|
'photo' => 'nullable|image|max:2048', // 2MB Max
|
||||||
|
];
|
||||||
|
|
||||||
|
public function mount($fieldName = 'photo', $currentImage = null, $placeholder = null)
|
||||||
|
{
|
||||||
|
$this->fieldName = $fieldName;
|
||||||
|
$this->currentImage = $currentImage;
|
||||||
|
$this->placeholder = $placeholder ?? asset('images/default-avatar.png');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function updatedPhoto()
|
||||||
|
{
|
||||||
|
$this->validate([
|
||||||
|
'photo' => 'image|max:2048', // 2MB Max
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function removePhoto()
|
||||||
|
{
|
||||||
|
$this->photo = null;
|
||||||
|
$this->currentImage = null;
|
||||||
|
>>>>>>> f97a7a84985ea300216ba3ea2ab4c31306e1659a
|
||||||
}
|
}
|
||||||
|
|
||||||
public function save()
|
public function save()
|
||||||
{
|
{
|
||||||
|
<<<<<<< HEAD
|
||||||
$this->validate([
|
$this->validate([
|
||||||
'image' => 'required|image|max:2048',
|
'image' => 'required|image|max:2048',
|
||||||
]);
|
]);
|
||||||
@@ -79,6 +111,38 @@ class ImageUploader extends Component
|
|||||||
$this->hover = $status;
|
$this->hover = $status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
=======
|
||||||
|
$this->validate();
|
||||||
|
|
||||||
|
if ($this->photo) {
|
||||||
|
$path = $this->photo->store($this->storagePath);
|
||||||
|
|
||||||
|
if ($this->model) {
|
||||||
|
// Eliminar imagen anterior si existe
|
||||||
|
if ($this->model->{$this->fieldName}) {
|
||||||
|
Storage::delete($this->model->{$this->fieldName});
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->model->{$this->fieldName} = $path;
|
||||||
|
$this->model->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->currentUrl = Storage::url($path);
|
||||||
|
$this->showSavedMessage = true;
|
||||||
|
$this->photo = null; // Limpiar el input de subida
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getCurrentImageUrl()
|
||||||
|
{
|
||||||
|
if ($this->model && $this->model->{$this->fieldName}) {
|
||||||
|
return Storage::url($this->model->{$this->fieldName});
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->placeholder;
|
||||||
|
}
|
||||||
|
|
||||||
|
>>>>>>> f97a7a84985ea300216ba3ea2ab4c31306e1659a
|
||||||
public function render()
|
public function render()
|
||||||
{
|
{
|
||||||
return view('livewire.image-uploader');
|
return view('livewire.image-uploader');
|
||||||
|
|||||||
@@ -240,6 +240,7 @@ class ProjectShow extends Component
|
|||||||
|
|
||||||
public function render()
|
public function render()
|
||||||
{
|
{
|
||||||
|
<<<<<<< HEAD
|
||||||
return view('livewire.project.show')->layout('components.layouts.documents', [
|
return view('livewire.project.show')->layout('components.layouts.documents', [
|
||||||
'title' => __('Project: :name', ['name' => $this->project->name]),
|
'title' => __('Project: :name', ['name' => $this->project->name]),
|
||||||
'breadcrumbs' => [
|
'breadcrumbs' => [
|
||||||
@@ -247,5 +248,8 @@ class ProjectShow extends Component
|
|||||||
['name' => $this->project->name, 'url' => route('projects.show', $this->project)],
|
['name' => $this->project->name, 'url' => route('projects.show', $this->project)],
|
||||||
],
|
],
|
||||||
]);
|
]);
|
||||||
|
=======
|
||||||
|
return view('livewire.project-show');
|
||||||
|
>>>>>>> f97a7a84985ea300216ba3ea2ab4c31306e1659a
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
<<<<<<< HEAD
|
||||||
<div x-data="{ isUploading: false }"
|
<div x-data="{ isUploading: false }"
|
||||||
x-on:livewire-upload-start="isUploading = true"
|
x-on:livewire-upload-start="isUploading = true"
|
||||||
x-on:livewire-upload-finish="isUploading = false"
|
x-on:livewire-upload-finish="isUploading = false"
|
||||||
@@ -54,4 +55,49 @@
|
|||||||
<div class="alert alert-danger mt-2">{{ $message }}</div>
|
<div class="alert alert-danger mt-2">{{ $message }}</div>
|
||||||
@enderror
|
@enderror
|
||||||
</div>
|
</div>
|
||||||
|
=======
|
||||||
|
<div>
|
||||||
|
<!-- Preview de imagen -->
|
||||||
|
<div class="relative mb-4">
|
||||||
|
<img src="{{ $photo ? $photo->temporaryUrl() : ($currentImage ?? $placeholder) }}"
|
||||||
|
alt="Preview"
|
||||||
|
class="w-32 h-32 rounded-full object-cover border-2 border-gray-300">
|
||||||
|
|
||||||
|
@if($photo || $currentImage)
|
||||||
|
<button type="button"
|
||||||
|
wire:click="removePhoto"
|
||||||
|
class="absolute top-0 right-0 bg-red-500 text-white rounded-full p-1 hover:bg-red-600 transition"
|
||||||
|
title="Eliminar foto">
|
||||||
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Input de archivo -->
|
||||||
|
<label class="cursor-pointer bg-white px-4 py-2 rounded-md shadow-sm border border-gray-300 hover:bg-gray-50 inline-block">
|
||||||
|
<span class="text-sm font-medium text-gray-700">
|
||||||
|
{{ $photo || $currentImage ? 'Cambiar imagen' : 'Seleccionar imagen' }}
|
||||||
|
</span>
|
||||||
|
<input type="file"
|
||||||
|
wire:model="photo"
|
||||||
|
class="hidden"
|
||||||
|
accept="image/*"
|
||||||
|
name="{{ $fieldName }}_input"> <!-- Input oculto para Livewire -->
|
||||||
|
|
||||||
|
<!-- Input real para el formulario -->
|
||||||
|
@if($photo)
|
||||||
|
<input type="hidden" name="{{ $fieldName }}" value="{{ $photo->getFilename() }}">
|
||||||
|
@elseif($currentImage)
|
||||||
|
<input type="hidden" name="{{ $fieldName }}" value="current">
|
||||||
|
@endif
|
||||||
|
</label>
|
||||||
|
|
||||||
|
@error('photo')
|
||||||
|
<p class="mt-2 text-sm text-red-600">{{ $message }}</p>
|
||||||
|
@enderror
|
||||||
|
|
||||||
|
<p class="mt-1 text-xs text-gray-500">PNG, JPG o JPEG (Max. 2MB)</p>
|
||||||
|
>>>>>>> f97a7a84985ea300216ba3ea2ab4c31306e1659a
|
||||||
</div>
|
</div>
|
||||||
117
resources/views/livewire/project-show.blade.php
Normal file
117
resources/views/livewire/project-show.blade.php
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
<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>
|
||||||
|
<a href="{{ route('projects.edit', $project) }}"
|
||||||
|
class="px-4 py-2 text-white bg-blue-600 rounded-lg hover:bg-blue-700">
|
||||||
|
Editar Proyecto
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Barra de Herramientas y Contenido -->
|
||||||
|
<div class="grid grid-cols-1 gap-6 p-4 lg:grid-cols-4">
|
||||||
|
<!-- Treeview de Carpetas -->
|
||||||
|
<div class="col-span-1 bg-white rounded-lg shadow">
|
||||||
|
<div class="p-4 border-b">
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<h3 class="font-medium">Carpetas</h3>
|
||||||
|
<button wire:click="createFolder" class="p-1 text-gray-600 hover:bg-gray-100 rounded">
|
||||||
|
<x-icons icon="plus" class="w-5 h-5" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<input type="text"
|
||||||
|
wire:model.live="folderName"
|
||||||
|
placeholder="Nueva carpeta"
|
||||||
|
class="w-full p-2 mt-2 border rounded"
|
||||||
|
@keyup.enter="createFolder">
|
||||||
|
</div>
|
||||||
|
<div class="p-4">
|
||||||
|
<ul class="space-y-2">
|
||||||
|
@foreach($project->rootFolders as $folder)
|
||||||
|
<x-folder-item
|
||||||
|
:folder="$folder"
|
||||||
|
:currentFolder="$currentFolder"
|
||||||
|
:expandedFolders="$expandedFolders"
|
||||||
|
wire:key="folder-{{ $folder->id }}"
|
||||||
|
/>
|
||||||
|
@endforeach
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Documentos y Subida de Archivos -->
|
||||||
|
<div class="col-span-3">
|
||||||
|
<div class="bg-white rounded-lg shadow">
|
||||||
|
<div class="p-4 border-b">
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<h3 class="font-medium">Documentos</h3>
|
||||||
|
<input type="file"
|
||||||
|
wire:model="files"
|
||||||
|
multiple
|
||||||
|
class="hidden"
|
||||||
|
id="file-upload">
|
||||||
|
<label for="file-upload" class="px-4 py-2 text-sm text-white bg-green-600 rounded-lg cursor-pointer hover:bg-green-700">
|
||||||
|
Subir Archivos
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</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-xs font-medium tracking-wider text-left text-gray-500 uppercase">Nombre</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">
|
||||||
|
<x-icons icon="document" class="w-5 h-5 mr-2 text-gray-400" />
|
||||||
|
{{ $document->name }}
|
||||||
|
</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
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
@endforelse
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
@@ -75,7 +75,11 @@
|
|||||||
<!-- Foto del usuario -->
|
<!-- Foto del usuario -->
|
||||||
@if($user->profile_photo_path)
|
@if($user->profile_photo_path)
|
||||||
<div class="mr-3 flex-shrink-0">
|
<div class="mr-3 flex-shrink-0">
|
||||||
|
<<<<<<< HEAD
|
||||||
<img src="{{ asset('storage/' . $user->profile_photo_path) }}"
|
<img src="{{ asset('storage/' . $user->profile_photo_path) }}"
|
||||||
|
=======
|
||||||
|
<img src="{{ asset($user->profile_photo_path) }}"
|
||||||
|
>>>>>>> f97a7a84985ea300216ba3ea2ab4c31306e1659a
|
||||||
alt="{{ $user->full_name }}"
|
alt="{{ $user->full_name }}"
|
||||||
class="w-8 h-8 rounded-full object-cover transition-transform group-hover:scale-110">
|
class="w-8 h-8 rounded-full object-cover transition-transform group-hover:scale-110">
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -197,9 +197,15 @@
|
|||||||
<div>
|
<div>
|
||||||
<x-label for="longitude" :value="__('Longitud')" />
|
<x-label for="longitude" :value="__('Longitud')" />
|
||||||
<input type="number"
|
<input type="number"
|
||||||
|
<<<<<<< HEAD
|
||||||
id="longitude"
|
id="longitude"
|
||||||
name="longitude"
|
name="longitude"
|
||||||
value="{{ old('longitude') }}"
|
value="{{ old('longitude') }}"
|
||||||
|
=======
|
||||||
|
id="latitude"
|
||||||
|
name="latitude"
|
||||||
|
value="{{ old('latitude') }}"
|
||||||
|
>>>>>>> f97a7a84985ea300216ba3ea2ab4c31306e1659a
|
||||||
step="any"
|
step="any"
|
||||||
class="border-b-1 border-gray-300 focus:border-blue-500 focus:outline-none">
|
class="border-b-1 border-gray-300 focus:border-blue-500 focus:outline-none">
|
||||||
</div>
|
</div>
|
||||||
@@ -308,7 +314,11 @@
|
|||||||
|
|
||||||
<template x-if="files.length === 0">
|
<template x-if="files.length === 0">
|
||||||
<div>
|
<div>
|
||||||
|
<<<<<<< HEAD
|
||||||
<x-icons icon="upload" class="mx-auto h-12 w-12 text-gray-400" />
|
<x-icons icon="upload" class="mx-auto h-12 w-12 text-gray-400" />
|
||||||
|
=======
|
||||||
|
<x-icons.upload class="mx-auto h-12 w-12 text-gray-400" />
|
||||||
|
>>>>>>> f97a7a84985ea300216ba3ea2ab4c31306e1659a
|
||||||
<p class="mt-1 text-sm text-gray-600">
|
<p class="mt-1 text-sm text-gray-600">
|
||||||
Arrastra archivos o haz clic para subir
|
Arrastra archivos o haz clic para subir
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -17,7 +17,10 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Barra de herramientas principal -->
|
<!-- Barra de herramientas principal -->
|
||||||
|
<<<<<<< HEAD
|
||||||
javi
|
javi
|
||||||
|
=======
|
||||||
|
>>>>>>> f97a7a84985ea300216ba3ea2ab4c31306e1659a
|
||||||
|
|
||||||
|
|
||||||
<!-- Componente principal Livewire -->
|
<!-- Componente principal Livewire -->
|
||||||
|
|||||||
@@ -291,12 +291,21 @@
|
|||||||
</td>
|
</td>
|
||||||
<td class="py-2">
|
<td class="py-2">
|
||||||
<div class="mb-6">
|
<div class="mb-6">
|
||||||
|
<<<<<<< HEAD
|
||||||
@livewire('image-uploader', [
|
@livewire('image-uploader', [
|
||||||
'fieldName' => 'image_path', // Nombre del campo en la BD
|
'fieldName' => 'image_path', // Nombre del campo en la BD
|
||||||
'label' => 'Imagen principal' // Etiqueta personalizada
|
'label' => 'Imagen principal' // Etiqueta personalizada
|
||||||
])
|
])
|
||||||
<!-- Campo oculto para la ruta de la imagen -->
|
<!-- Campo oculto para la ruta de la imagen -->
|
||||||
<input type="hidden" name="profile_photo_path" id="profilePhotoPathInput" value="{{ old('profile_photo_path', $user->profile_photo_path) }}">
|
<input type="hidden" name="profile_photo_path" id="profilePhotoPathInput" value="{{ old('profile_photo_path', $user->profile_photo_path) }}">
|
||||||
|
=======
|
||||||
|
|
||||||
|
@livewire('image-uploader', [
|
||||||
|
'fieldName' => 'profile_photo_path',
|
||||||
|
'currentImage' => $user->profile_photo_path ?? null,
|
||||||
|
'placeholder' => asset('images/default-user.png')
|
||||||
|
])
|
||||||
|
>>>>>>> f97a7a84985ea300216ba3ea2ab4c31306e1659a
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>php
|
</tr>php
|
||||||
@@ -317,6 +326,7 @@
|
|||||||
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
<<<<<<< HEAD
|
||||||
// Escuchar el evento de Livewire y actualizar el campo oculto
|
// Escuchar el evento de Livewire y actualizar el campo oculto
|
||||||
document.addEventListener('imageUploaded', (event) => {
|
document.addEventListener('imageUploaded', (event) => {
|
||||||
document.getElementById('profilePhotoPathInput').value = event.detail.path;
|
document.getElementById('profilePhotoPathInput').value = event.detail.path;
|
||||||
@@ -326,6 +336,8 @@
|
|||||||
document.getElementById('profilePhotoPathInput').value = '';
|
document.getElementById('profilePhotoPathInput').value = '';
|
||||||
});
|
});
|
||||||
|
|
||||||
|
=======
|
||||||
|
>>>>>>> f97a7a84985ea300216ba3ea2ab4c31306e1659a
|
||||||
function generatePassword() {
|
function generatePassword() {
|
||||||
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()';
|
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()';
|
||||||
let password = '';
|
let password = '';
|
||||||
|
|||||||
@@ -6,8 +6,14 @@
|
|||||||
<!-- User Info Left -->
|
<!-- User Info Left -->
|
||||||
<div class="flex items-center space-x-6">
|
<div class="flex items-center space-x-6">
|
||||||
<!-- User Photo -->
|
<!-- User Photo -->
|
||||||
|
<<<<<<< HEAD
|
||||||
<img src="{{ $user->profile_photo_path ? asset('storage/' . $user->profile_photo_path) : 'https://via.placeholder.com/150' }}"
|
<img src="{{ $user->profile_photo_path ? asset('storage/' . $user->profile_photo_path) : 'https://via.placeholder.com/150' }}"
|
||||||
class="w-24 h-24 rounded-full object-cover border-2 border-blue-100">
|
class="w-24 h-24 rounded-full object-cover border-2 border-blue-100">
|
||||||
|
=======
|
||||||
|
<img src="{{ $user->photo_url ?? 'https://via.placeholder.com/150' }}"
|
||||||
|
class="w-24 h-24 rounded-full object-cover border-4 border-blue-100">
|
||||||
|
|
||||||
|
>>>>>>> f97a7a84985ea300216ba3ea2ab4c31306e1659a
|
||||||
<!-- User Details -->
|
<!-- User Details -->
|
||||||
<div>
|
<div>
|
||||||
<h1 class="text-2xl font-bold text-gray-700">
|
<h1 class="text-2xl font-bold text-gray-700">
|
||||||
@@ -127,9 +133,15 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Action Buttons -->
|
<!-- Action Buttons -->
|
||||||
|
<<<<<<< HEAD
|
||||||
<div class="mt-6 flex justify-end space-x-4">
|
<div class="mt-6 flex justify-end space-x-4">
|
||||||
<a href="{{ route('users.edit', $user) }}"
|
<a href="{{ route('users.edit', $user) }}"
|
||||||
class="w-[150px] px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg flex items-center justify-center">
|
class="w-[150px] px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg flex items-center justify-center">
|
||||||
|
=======
|
||||||
|
<div class="mt-6 flex space-x-4">
|
||||||
|
<a href="{{ route('users.edit', $user) }}"
|
||||||
|
class="px-4 py-2 w-[150px] bg-blue-600 hover:bg-blue-700 text-white rounded-lg flex items-center">
|
||||||
|
>>>>>>> f97a7a84985ea300216ba3ea2ab4c31306e1659a
|
||||||
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<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"/>
|
<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>
|
</svg>
|
||||||
@@ -141,7 +153,11 @@
|
|||||||
@csrf
|
@csrf
|
||||||
@method('PUT') <!-- Important! -->
|
@method('PUT') <!-- Important! -->
|
||||||
<button type="submit"
|
<button type="submit"
|
||||||
|
<<<<<<< HEAD
|
||||||
class="w-[150px] px-4 py-2 bg-yellow-500 hover:bg-yellow-600 text-white rounded-lg flex items-center justify-center">
|
class="w-[150px] px-4 py-2 bg-yellow-500 hover:bg-yellow-600 text-white rounded-lg flex items-center justify-center">
|
||||||
|
=======
|
||||||
|
class="px-4 py-2 w-[150px] {{ $user->is_active ? 'bg-red-600 hover:bg-red-700' : 'bg-green-600 hover:bg-green-700' }} text-white rounded-lg flex items-center">
|
||||||
|
>>>>>>> f97a7a84985ea300216ba3ea2ab4c31306e1659a
|
||||||
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<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"/>
|
<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>
|
</svg>
|
||||||
@@ -155,7 +171,11 @@
|
|||||||
@method('DELETE') <!-- Important! -->
|
@method('DELETE') <!-- Important! -->
|
||||||
<button type="submit"
|
<button type="submit"
|
||||||
onclick="return confirm('¿Estás seguro de querer eliminar este usuario?')"
|
onclick="return confirm('¿Estás seguro de querer eliminar este usuario?')"
|
||||||
|
<<<<<<< HEAD
|
||||||
class="px-4 py-2 w-[150px] bg-red-600 hover:bg-red-700 text-white rounded-lg flex items-center justify-center">
|
class="px-4 py-2 w-[150px] bg-red-600 hover:bg-red-700 text-white rounded-lg flex items-center justify-center">
|
||||||
|
=======
|
||||||
|
class="px-4 py-2 w-[150px] bg-red-600 hover:bg-red-700 text-white rounded-lg flex items-center">
|
||||||
|
>>>>>>> f97a7a84985ea300216ba3ea2ab4c31306e1659a
|
||||||
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<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"/>
|
<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>
|
</svg>
|
||||||
@@ -166,6 +186,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Permissions Tab -->
|
<!-- Permissions Tab -->
|
||||||
|
<<<<<<< HEAD
|
||||||
<div class="space-y-4">
|
<div class="space-y-4">
|
||||||
@foreach($permissionGroups as $groupName => $group)
|
@foreach($permissionGroups as $groupName => $group)
|
||||||
<div class="border rounded-lg overflow-hidden">
|
<div class="border rounded-lg overflow-hidden">
|
||||||
@@ -225,6 +246,22 @@
|
|||||||
wire:change="togglePermission('{{ $permission['name'] }}')"
|
wire:change="togglePermission('{{ $permission['name'] }}')"
|
||||||
class="sr-only peer">
|
class="sr-only peer">
|
||||||
<div class="w-11 h-6 bg-gray-200 peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-blue-600"></div>
|
<div class="w-11 h-6 bg-gray-200 peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-blue-600"></div>
|
||||||
|
=======
|
||||||
|
<div x-show="activeTab === 'permissions'" x-cloak>
|
||||||
|
<div class="space-y-6">
|
||||||
|
@foreach($permissionGroups as $group => $permissions)
|
||||||
|
<div class="border rounded-lg p-4">
|
||||||
|
<h3 class="text-lg font-semibold mb-4">{{ ucfirst($group) }}</h3>
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||||
|
@foreach($permissions as $permission)
|
||||||
|
<div class="flex items-center justify-between p-3 bg-gray-50 rounded-lg">
|
||||||
|
<span class="text-sm">{{ $permission->name }}</span>
|
||||||
|
<label class="switch">
|
||||||
|
<input type="checkbox"
|
||||||
|
@if($user->hasPermissionTo($permission)) checked @endif
|
||||||
|
wire:change="togglePermission('{{ $permission->name }}')">
|
||||||
|
<span class="slider round"></span>
|
||||||
|
>>>>>>> f97a7a84985ea300216ba3ea2ab4c31306e1659a
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
@endforeach
|
@endforeach
|
||||||
@@ -234,7 +271,11 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<<<<<<< HEAD
|
||||||
<!-- Pestaña de Proyectos -->
|
<!-- Pestaña de Proyectos -->
|
||||||
|
=======
|
||||||
|
<!-- Nueva Pestaña de Proyectos -->
|
||||||
|
>>>>>>> f97a7a84985ea300216ba3ea2ab4c31306e1659a
|
||||||
<div x-show="activeTab === 'projects'" x-cloak>
|
<div x-show="activeTab === 'projects'" x-cloak>
|
||||||
<div class="space-y-6">
|
<div class="space-y-6">
|
||||||
<!-- Proyectos Actuales -->
|
<!-- Proyectos Actuales -->
|
||||||
@@ -300,6 +341,7 @@
|
|||||||
transform: translateX(26px);
|
transform: translateX(26px);
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
<<<<<<< HEAD
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
document.addEventListener('alpine:init', () => {
|
document.addEventListener('alpine:init', () => {
|
||||||
@@ -318,4 +360,6 @@
|
|||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
=======
|
||||||
|
>>>>>>> f97a7a84985ea300216ba3ea2ab4c31306e1659a
|
||||||
</x-layouts.app>
|
</x-layouts.app>
|
||||||
@@ -49,9 +49,16 @@ Route::middleware(['auth', 'verified'])->group(function () {
|
|||||||
|
|
||||||
// Proyectos
|
// Proyectos
|
||||||
Route::resource('projects', ProjectController::class);
|
Route::resource('projects', ProjectController::class);
|
||||||
|
<<<<<<< HEAD
|
||||||
//Route::get('/projects/{project}', ProjectController::class)->name('projects.show');
|
//Route::get('/projects/{project}', ProjectController::class)->name('projects.show');
|
||||||
//Route::get('/projects/{project}', ProjectController::class)->name('projects.show')->middleware('can:view,project'); // Opcional: política de acceso
|
//Route::get('/projects/{project}', ProjectController::class)->name('projects.show')->middleware('can:view,project'); // Opcional: política de acceso
|
||||||
Route::get('/projects/{project}', ProjectShow::class)->name('projects.show')->middleware('auth');
|
Route::get('/projects/{project}', ProjectShow::class)->name('projects.show')->middleware('auth');
|
||||||
|
=======
|
||||||
|
Route::get('/projects/{project}', ProjectController::class)->name('projects.show');
|
||||||
|
//Route::get('/projects/{project}', ProjectController::class)->name('projects.show')->middleware('can:view,project'); // Opcional: política de acceso
|
||||||
|
//Route::get('/projects/{project}', ProjectShow::class)->name('projects.show');
|
||||||
|
|
||||||
|
>>>>>>> f97a7a84985ea300216ba3ea2ab4c31306e1659a
|
||||||
|
|
||||||
// Documentos
|
// Documentos
|
||||||
Route::resource('documents', DocumentController::class);
|
Route::resource('documents', DocumentController::class);
|
||||||
|
|||||||
Reference in New Issue
Block a user