projectTA/resources/views/photos.blade.php

264 lines
14 KiB
PHP

@extends('layouts.app')
@section('title', 'Semua Foto')
@section('content')
<div class="py-8 max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="bg-white rounded-lg shadow-lg overflow-hidden">
<div class="p-6">
<div class="flex justify-between items-center mb-6">
<h2 class="text-2xl font-bold text-gray-800">Semua Foto ESP32-CAM</h2>
<a href="{{ route('dashboard') }}" class="px-4 py-2 bg-gray-500 text-white rounded-md hover:bg-gray-600 transition duration-300">
Kembali ke Dashboard
</a>
</div>
@if(count($photos) > 0)
<div id="photos-grid" class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4">
@foreach($photos as $photo)
<div class="bg-gray-50 rounded-lg overflow-hidden shadow-sm hover:shadow-md transition duration-300 photo-item">
<div class="relative pt-[75%]">
<img src="{{ asset($photo['path']) }}"
alt="{{ $photo['name'] }}"
class="absolute inset-0 w-full h-full object-cover"
onclick="openPhotoModal('{{ asset($photo['path']) }}', '{{ $photo['time'] }}', '{{ $photo['size'] }}', '{{ $photo['name'] }}')">
<div class="absolute top-2 right-2">
<button class="delete-photo p-1.5 bg-red-500 text-white rounded-full hover:bg-red-600 focus:outline-none"
data-filename="{{ $photo['name'] }}">
<svg xmlns="http://www.w3.org/2000/svg" class="h-3.5 w-3.5" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd" />
</svg>
</button>
</div>
</div>
<div class="p-3">
<p class="text-gray-600 text-sm mb-1">
<span class="font-semibold">Waktu:</span> {{ $photo['time'] }}
</p>
<p class="text-gray-600 text-sm">
<span class="font-semibold">Ukuran:</span> {{ $photo['size'] }}
</p>
</div>
</div>
@endforeach
</div>
@else
<div class="text-center py-12 bg-gray-50 rounded-lg">
<svg class="w-16 h-16 text-gray-400 mx-auto mb-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" />
</svg>
<p class="text-gray-500 text-lg">Belum ada foto yang tersedia</p>
</div>
@endif
</div>
</div>
</div>
@push('scripts')
<script>
document.addEventListener('DOMContentLoaded', function() {
// Konfigurasi SweetAlert2 untuk menggunakan warna Tailwind
const mySwal = Swal.mixin({
customClass: {
confirmButton: 'bg-blue-600 text-white font-medium px-4 py-2 rounded-md shadow-sm hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 mr-2',
cancelButton: 'bg-red-500 text-white font-medium px-4 py-2 rounded-md shadow-sm hover:bg-red-600 focus:outline-none focus:ring-2 focus:ring-red-500'
},
buttonsStyling: false
});
// Tambahkan event listener untuk tombol hapus
document.querySelectorAll('.delete-photo').forEach(button => {
button.addEventListener('click', function() {
const filename = this.getAttribute('data-filename');
const photoElement = this.closest('.photo-item');
mySwal.fire({
title: 'Apakah Anda yakin?',
text: "Foto yang dihapus tidak dapat dikembalikan!",
icon: 'warning',
showCancelButton: true,
confirmButtonText: 'Ya, hapus!',
cancelButtonText: 'Batal'
}).then((result) => {
if (result.isConfirmed) {
// Tampilkan loading
mySwal.fire({
title: 'Menghapus...',
html: 'Mohon tunggu sebentar...',
allowOutsideClick: false,
didOpen: () => {
mySwal.showLoading();
}
});
// Kirim permintaan AJAX untuk menghapus foto
fetch('/api/esp32cam/delete', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content')
},
body: JSON.stringify({
filename: filename,
delete_storage: true // Tambahkan flag untuk menghapus file di storage
})
})
.then(response => response.json())
.then(data => {
if (data.status === 'success') {
// Tambahkan animasi sebelum menghapus
photoElement.style.transition = 'all 0.5s ease';
photoElement.style.opacity = '0';
photoElement.style.transform = 'scale(0.8)';
setTimeout(() => {
photoElement.remove();
// Periksa apakah masih ada foto
if (document.querySelectorAll('.photo-item').length === 0) {
const photosGrid = document.getElementById('photos-grid');
photosGrid.innerHTML = `
<div class="text-center py-12 bg-gray-50 rounded-lg col-span-full">
<svg class="w-16 h-16 text-gray-400 mx-auto mb-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" />
</svg>
<p class="text-gray-500 text-lg">Belum ada foto yang tersedia</p>
</div>
`;
}
mySwal.fire({
title: 'Terhapus!',
text: 'Foto berhasil dihapus.',
icon: 'success',
timer: 1500,
showConfirmButton: false
});
}, 500);
} else {
mySwal.fire({
title: 'Error!',
text: 'Gagal menghapus foto: ' + data.message,
icon: 'error'
});
}
})
.catch(error => {
console.error('Error:', error);
mySwal.fire({
title: 'Error!',
text: 'Terjadi kesalahan saat menghapus foto.',
icon: 'error'
});
});
}
});
});
});
});
// Variabel untuk zoom
let currentScale = 1;
// Fungsi zoom
function zoomIn() {
currentScale += 0.25;
document.getElementById('modal-photo').style.transform = `scale(${currentScale})`;
}
function zoomOut() {
if (currentScale > 0.5) {
currentScale -= 0.25;
document.getElementById('modal-photo').style.transform = `scale(${currentScale})`;
}
}
function zoomReset() {
currentScale = 1;
document.getElementById('modal-photo').style.transform = 'scale(1)';
}
// Fungsi untuk modal foto
function openPhotoModal(src, timestamp, filesize, filename) {
const modal = document.getElementById('photoModal');
const modalPhoto = document.getElementById('modal-photo');
const modalTimestamp = document.getElementById('modal-timestamp');
const modalFilesize = document.getElementById('modal-filesize');
const modalFilename = document.getElementById('modal-filename');
modalPhoto.src = src;
modalTimestamp.textContent = timestamp;
modalFilesize.textContent = filesize;
modalFilename.textContent = filename;
// Reset zoom setiap kali membuka modal
currentScale = 1;
modalPhoto.style.transform = 'scale(1)';
modal.classList.remove('hidden');
}
function closePhotoModal() {
const modal = document.getElementById('photoModal');
modal.classList.add('hidden');
}
// Tutup modal dengan escape key
document.addEventListener('keydown', function(e) {
if (e.key === 'Escape') {
closePhotoModal();
}
});
// Tutup modal dengan click di luar content
document.getElementById('photoModal')?.addEventListener('click', function(e) {
if (e.target === this) {
closePhotoModal();
}
});
</script>
@endpush
<!-- Modal untuk Photo Zoom -->
<div id="photoModal" class="fixed inset-0 z-50 hidden overflow-auto bg-black bg-opacity-80 flex items-center justify-center p-4">
<div class="relative bg-white rounded-lg shadow-xl max-w-4xl w-full">
<div class="flex justify-between items-center p-4 border-b">
<h3 class="text-lg font-semibold text-gray-900" id="modal-title">Detail Foto</h3>
<button type="button" class="text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm p-1.5 ml-auto inline-flex items-center" onclick="closePhotoModal()">
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd"></path>
</svg>
</button>
</div>
<div class="p-4 space-y-6">
<div class="relative">
<div id="zoom-container" class="overflow-hidden relative">
<img id="modal-photo" src="" alt="Photo" class="w-full transform transition-transform duration-300">
</div>
<div class="flex justify-center mt-4 space-x-2">
<button id="zoom-in" class="bg-gray-200 p-2 rounded-full hover:bg-gray-300 transition-colors" onclick="zoomIn()">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M10 5a1 1 0 011 1v3h3a1 1 0 110 2h-3v3a1 1 0 11-2 0v-3H6a1 1 0 110-2h3V6a1 1 0 011-1z" clip-rule="evenodd" />
</svg>
</button>
<button id="zoom-out" class="bg-gray-200 p-2 rounded-full hover:bg-gray-300 transition-colors" onclick="zoomOut()">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M5 10a1 1 0 011-1h8a1 1 0 110 2H6a1 1 0 01-1-1z" clip-rule="evenodd" />
</svg>
</button>
<button id="zoom-reset" class="bg-gray-200 p-2 rounded-full hover:bg-gray-300 transition-colors" onclick="zoomReset()">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M4 2a1 1 0 011 1v2.101a7.002 7.002 0 0111.601 2.566 1 1 0 11-1.885.666A5.002 5.002 0 005.999 7H9a1 1 0 010 2H4a1 1 0 01-1-1V3a1 1 0 011-1zm.008 9.057a1 1 0 011.276.61A5.002 5.002 0 0014.001 13H11a1 1 0 110-2h5a1 1 0 011 1v5a1 1 0 11-2 0v-2.101a7.002 7.002 0 01-11.601-2.566 1 1 0 01.61-1.276z" clip-rule="evenodd" />
</svg>
</button>
</div>
</div>
<div class="mt-4">
<p class="text-sm text-gray-600"><span class="font-medium">Nama File:</span> <span id="modal-filename"></span></p>
<p class="text-sm text-gray-600"><span class="font-medium">Waktu Pengambilan:</span> <span id="modal-timestamp"></span></p>
<p class="text-sm text-gray-600"><span class="font-medium">Ukuran File:</span> <span id="modal-filesize"></span></p>
</div>
</div>
</div>
</div>
@endsection