96 lines
4.4 KiB
PHP
96 lines
4.4 KiB
PHP
<!-- resources/views/livewire/user-photo-upload.blade.php -->
|
|
|
|
<div class="mb-6" x-data="{ isUploading: false, previewUrl: '{{ $existingPhoto ? asset('storage/photos/'.$existingPhoto) : '' }}'}" }">
|
|
<!-- Foto existente -->
|
|
@if($existingPhoto)
|
|
<div class="mb-4 relative group">
|
|
<img src="{{ asset('storage/photos/' . $existingPhoto) }}"
|
|
alt="Foto actual"
|
|
class="w-32 h-32 rounded-full object-cover shadow-md">
|
|
|
|
<button type="button"
|
|
wire:click="deletePhoto"
|
|
class="absolute top-0 right-0 bg-red-500 text-white rounded-full p-1 opacity-0 group-hover:opacity-100 transition-opacity"
|
|
title="Eliminar foto">
|
|
<svg class="w-5 h-5" 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>
|
|
</button>
|
|
</div>
|
|
@endif
|
|
|
|
<!-- Zona de carga -->
|
|
<div x-on:livewire-upload-start="isUploading = true"
|
|
x-on:livewire-upload-finish="isUploading = false"
|
|
x-on:livewire-upload-error="isUploading = false"
|
|
class="border-2 border-dashed border-gray-300 rounded-lg p-6 text-center cursor-pointer hover:border-blue-500 transition-colors">
|
|
|
|
<input type="file"
|
|
wire:model="photo"
|
|
id="photoInput"
|
|
class="hidden"
|
|
accept="image/*"
|
|
@if($existingPhoto) disabled @endif>
|
|
|
|
<label for="photoInput" class="cursor-pointer">
|
|
<div class="space-y-2">
|
|
<svg class="mx-auto h-12 w-12 text-gray-400"
|
|
stroke="currentColor"
|
|
fill="none"
|
|
viewBox="0 0 48 48">
|
|
<path d="M28 8H12a4 4 0 00-4 4v20m32-12v8m0 0v8a4 4 0 01-4 4H12a4 4 0 01-4-4v-4m32-4l-3.172-3.172a4 4 0 00-5.656 0L28 28M8 32l9.172-9.172a4 4 0 015.656 0L28 28m0 0l4 4m4-24h8m-4-4v8m-12 4h.02"
|
|
stroke-width="2"
|
|
stroke-linecap="round"
|
|
stroke-linejoin="round"/>
|
|
</svg>
|
|
|
|
<div class="text-sm text-gray-600">
|
|
<span class="font-medium text-blue-600">Sube una foto</span>
|
|
o arrastra y suelta
|
|
</div>
|
|
<div class="text-xs text-gray-500">
|
|
PNG, JPG, GIF hasta 2MB
|
|
</div>
|
|
|
|
<!-- Vista previa temporal -->
|
|
@if($tempPhoto)
|
|
<div class="mt-4">
|
|
<img src="{{ $tempPhoto }}"
|
|
alt="Vista previa"
|
|
class="w-32 h-32 rounded-full object-cover mx-auto shadow-md">
|
|
</div>
|
|
@endif
|
|
|
|
<!-- Loading state -->
|
|
<div x-show="isUploading" class="mt-2">
|
|
<div class="inline-flex items-center text-sm text-gray-500">
|
|
<svg class="animate-spin -ml-1 mr-3 h-5 w-5 text-blue-500"
|
|
xmlns="http://www.w3.org/2000/svg"
|
|
fill="none"
|
|
viewBox="0 0 24 24">
|
|
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
|
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
|
</svg>
|
|
Subiendo...
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</label>
|
|
</div>
|
|
|
|
<!-- Botones de acción -->
|
|
@if($photo || $tempPhoto)
|
|
<div class="mt-4 flex justify-center gap-2">
|
|
<button type="button"
|
|
wire:click="removePhoto"
|
|
class="px-4 py-2 bg-red-100 text-red-700 rounded-md hover:bg-red-200 transition-colors">
|
|
Borrar
|
|
</button>
|
|
</div>
|
|
@endif
|
|
|
|
<!-- Mensajes de error -->
|
|
@error('photo')
|
|
<div class="mt-2 text-sm text-red-600">{{ $message }}</div>
|
|
@enderror
|
|
</div>
|