update: admin scan

main
marszayn 2025-08-06 09:48:31 +07:00
parent b9431a67b1
commit 6080584ac5
7 changed files with 1107 additions and 263 deletions

View File

@ -25,4 +25,11 @@ public class AdminController : Controller
{
return View("~/Views/Admin/Transport/SpjAdmin/History/Index.cshtml");
}
[HttpGet("history/details/{id}")]
public IActionResult Details(int id)
{
ViewData["Id"] = id;
return View("~/Views/Admin/Transport/SpjAdmin/History/Details.cshtml");
}
}

View File

@ -23,8 +23,8 @@
<i class="w-5 h-5 text-orange-600" data-lucide="file-text"></i>
</div>
<div>
<h2 class="text-lg font-bold text-gray-900">Data SPJ</h2>
<p class="text-xs text-gray-500">Surat Perintah Jalan</p>
<h2 class="text-lg font-bold text-gray-900">Muhammad Yusuf</h2>
<p class="text-xs text-gray-500">Data SPJ</p>
</div>
</div>

View File

@ -6,10 +6,10 @@
<div class="max-w-sm mx-auto bg-gray-50 min-h-screen">
<div class="bg-gradient-to-r from-orange-500 to-orange-600 text-white px-4 py-4 sticky top-0 z-10 shadow-lg">
<div class="flex items-center justify-between">
<a href="@Url.Action("Index", "Home")" class="p-2 hover:bg-white/10 rounded-full transition-all duration-200">
<a href="@Url.Action("Index", "Admin")" class="p-2 hover:bg-white/10 rounded-full transition-all duration-200">
<i class="w-5 h-5" data-lucide="chevron-left"></i>
</a>
<h1 class="text-lg font-bold">Riwayat Perjalanan</h1>
<h1 class="text-lg font-bold">Riwayat SPJ</h1>
<div class="w-9"></div>
</div>
</div>
@ -19,6 +19,7 @@
{
new {
Id = 1,
Nama = "Yusuf",
NoSpj = "SPJ/07-2025/PKM/000478",
Plat = "B 5678 ABC",
Kode = "JRC 007",
@ -29,6 +30,7 @@
},
new {
Id = 2,
Nama = "Ahmad Rizki",
NoSpj = "SPJ/07-2025/PKM/000476",
Plat = "B 9632 TOR",
Kode = "JRC 005",
@ -39,6 +41,7 @@
},
new {
Id = 3,
Nama = "Siti Aminah",
NoSpj = "SPJ/07-2025/PKM/000477",
Plat = "B 1234 XYZ",
Kode = "JRC 006",
@ -49,6 +52,7 @@
},
new {
Id = 4,
Nama = "Budi Santoso",
NoSpj = "SPJ/07-2025/PKM/000479",
Plat = "B 9876 DEF",
Kode = "JRC 008",
@ -59,6 +63,7 @@
},
new {
Id = 5,
Nama = "Dewi Lestari",
NoSpj = "SPJ/07-2025/PKM/000480",
Plat = "B 4321 GHI",
Kode = "JRC 009",
@ -73,15 +78,15 @@
<div class="px-4 py-4 space-y-3">
@foreach (var spj in spjList)
{
<a href="@Url.Action("Details", "History", new { id = spj.Id })" class="block">
<a href="@Url.Action("Details", "Admin", new { id = spj.Id })" class="block">
<div class="bg-white rounded-2xl p-4 shadow-sm border border-gray-100 hover:shadow-lg hover:border-orange-200 transition-all duration-300 relative overflow-hidden">
<div class="absolute top-0 left-0 w-full h-1 bg-gradient-to-r from-orange-400 to-orange-500"></div>
<div class="flex items-start justify-between mb-3">
<div class="flex-1 min-w-0">
<div class="flex items-center gap-2 mb-1">
<div class="w-2 h-2 bg-orange-400 rounded-full"></div>
<span class="text-xs font-medium text-gray-500 uppercase tracking-wider">No. SPJ</span>
<i class="w-4 h-4 text-green-600" data-lucide="user"></i>
<span class="text-xs font-medium text-gray-500 uppercase tracking-wider">@spj.Nama</span>
</div>
<div class="font-bold text-gray-900 text-sm">@spj.NoSpj</div>
</div>

View File

@ -1,220 +1,183 @@
@{
Layout = "~/Views/Admin/Transport/SpjAdmin/Shared/_Layout.cshtml";
ViewData["Title"] = "Home Page";
ViewData["Title"] = "Admin Dashboard";
}
<div class="container max-w-sm mx-auto bg-white min-h-screen">
<div class="container max-w-sm mx-auto bg-gradient-to-br from-gray-50 to-gray-100 min-h-screen relative overflow-hidden">
<div class="absolute top-0 max-w-sm container mx-auto bg-orange-500 text-white rounded-br-[125px] h-[250px] flex flex-row justify-between items-start px-6 py-6 shadow-lg z-20">
<div class="flex flex-col">
<h1 class="text-md font-bold leading-tight text-white">Bonny Agung Putra</h1>
<p class="text-xs opacity-90 font-medium text-orange-100">Driver UPST</span></p>
<div class="mt-5 flex items-center gap-2">
<i class="w-4 h-4 text-white" data-lucide="map-pin"></i>
<span class="text-sm opacity-90">Lokasi Anda:</span>
</div>
<p id="userLocation" class="font-semibold text-xs tracking-wide cursor-pointer underline text-white hover:text-orange-200 transition">
Mendeteksi lokasi...
</p>
</div>
<div class="flex items-center justify-center">
<div class="relative flex flex-col items-center justify-center">
<div class="w-12 h-12 rounded-full border-3 border-white overflow-hidden shadow-md flex items-center justify-center cursor-pointer group" id="profileMenuButton">
<i class="w-8 h-8 text-white" data-lucide="user"></i>
</div>
<div id="profileMenuDropdown" class="absolute top-12 right-0 mt-2 w-32 bg-white rounded shadow-lg py-2 z-50 hidden">
<form method="post" asp-controller="Auth" asp-action="Logout">
<button type="submit" class="hover:cursor-pointer flex items-center gap-2 w-full text-left px-4 py-2 text-sm font-semibold text-red-600 hover:bg-red-50 transition rounded-md">
<i class="w-4 h-4" data-lucide="log-out"></i>
Logout
</button>
</form>
</div>
</div>
</div>
</div>
<div class="bg-gradient-to-br from-slate-50 via-blue-50 to-indigo-100 mx-4 px-6 py-12 mt-40 rounded-3xl relative overflow-hidden shadow-2xl z-21 border border-slate-200">
<div class="absolute top-0 left-0 w-full h-full pointer-events-none">
<div class="absolute top-4 right-8 w-6 h-6 bg-orange-300 rounded-full opacity-60 animate-bounce" style="animation-delay: 0.5s;"></div>
<div class="absolute top-12 left-12 w-4 h-4 bg-blue-400 rounded-full opacity-40 animate-pulse" style="animation-delay: 1s;"></div>
<div class="absolute bottom-8 left-8 w-5 h-5 bg-indigo-300 rounded-full opacity-50 animate-bounce" style="animation-delay: 1.5s;"></div>
<div class="absolute bottom-16 right-16 w-3 h-3 bg-slate-400 rounded-full opacity-30 animate-pulse" style="animation-delay: 2s;"></div>
</div>
<div class="relative z-10">
<div class="bg-gradient-to-br from-orange-500 via-orange-600 to-red-500 rounded-b-[2rem] shadow-2xl p-6 mb-6">
<div class="relative z-10 text-center">
<div class="w-24 h-24 mx-auto mb-6 relative">
<div class="w-full h-full bg-gradient-to-br from-orange-400 to-orange-600 rounded-full flex items-center justify-center shadow-xl animate-pulse">
<div class="w-20 h-20 bg-white rounded-full flex items-center justify-center">
<i class="w-10 h-10 text-orange-500" data-lucide="clipboard-list"></i>
</div>
</div>
<div class="absolute inset-0 border-4 border-orange-300 rounded-full animate-ping opacity-30"></div>
</div>
<div class="relative z-10 pt-8 pb-4">
<div class="space-y-4">
<h2 class="text-xl font-bold bg-gradient-to-r from-slate-700 to-slate-900 bg-clip-text text-transparent">
Belum Ada SPJ
</h2>
<p class="text-sm text-slate-600 leading-relaxed px-4 mb-2">
Anda belum memiliki <span class="font-semibold text-orange-600">Surat Perintah Jalan</span> yang aktif saat ini.
</p>
</div>
<div class="bg-white/10 backdrop-blur-sm rounded-2xl p-6 border border-white/20 shadow-lg">
<div class="flex items-center justify-between">
<div class="flex items-center space-x-4">
<div class="relative">
<div class="w-16 h-16 rounded-2xl bg-gradient-to-br from-white to-orange-100 p-1 shadow-lg">
<div class="w-full h-full rounded-xl bg-gradient-to-br from-orange-400 to-orange-600 flex items-center justify-center shadow-inner">
<i class="w-8 h-8 text-white" data-lucide="user"></i>
</div>
</div>
<div class="absolute -bottom-1 -right-1 w-5 h-5 bg-green-400 rounded-full border-2 border-white shadow-sm">
<div class="w-full h-full bg-green-500 rounded-full animate-pulse"></div>
</div>
</div>
<div class="bg-white/70 backdrop-blur-sm border border-white/30 rounded-2xl p-5 mb-6 text-left">
<div class="space-y-2 text-xs text-slate-600">
<div class="flex items-start gap-2">
<div class="w-1 h-1 bg-orange-400 rounded-full mt-1.5 flex-shrink-0"></div>
<p>SPJ akan diterbitkan oleh admin sesuai jadwal kerja</p>
<div class="flex flex-col">
<h1 class="text-xl font-bold text-white leading-tight">Yusuf</h1>
<div class="flex items-center space-x-2">
<span class="bg-orange-700/30 text-orange-100 px-3 py-1 rounded-full text-sm font-base backdrop-blur-sm border border-orange-400/20">
Administrator
</span>
</div>
</div>
</div>
<div class="flex items-start gap-2">
<div class="w-1 h-1 bg-orange-400 rounded-full mt-1.5 flex-shrink-0"></div>
<p>Periksa koneksi internet dan aktifkan lokasi GPS</p>
<div class="relative">
<button id="profileMenuButton" class="w-12 h-12 rounded-xl bg-white/20 backdrop-blur-sm border border-white/30 flex items-center justify-center hover:bg-white/30 transition-all duration-300 group shadow-lg hover:shadow-xl hover:scale-105">
<i class="w-5 h-5 text-white group-hover:rotate-180 transition-transform duration-300" data-lucide="settings"></i>
</button>
<div id="profileMenuDropdown" class="absolute top-14 right-0 w-48 bg-white rounded-xl shadow-2xl py-2 z-50 hidden border border-gray-100 overflow-hidden">
<div class="px-4 py-3 border-b border-gray-100">
<p class="text-sm font-semibold text-gray-900">Yusuf</p>
<p class="text-xs text-gray-500">Administrator</p>
</div>
<div class="py-1">
<div class="border-t border-gray-100 mt-1"></div>
<form method="post" asp-controller="Auth" asp-action="Logout">
<button type="submit" class="flex items-center gap-3 w-full text-left px-4 py-2 text-sm font-semibold text-red-600 hover:bg-red-50 transition-colors">
<i class="w-4 h-4 text-red-500" data-lucide="log-out"></i>
<span>Logout</span>
</button>
</form>
</div>
</div>
</div>
</div>
</div>
<button id="refreshButton" class="bg-gradient-to-r from-orange-500 to-orange-600 hover:from-orange-600 hover:to-orange-700 text-white px-6 py-3 rounded-2xl text-sm font-bold shadow-lg hover:shadow-xl transition-all duration-300 flex items-center gap-2 mx-auto transform hover:scale-105">
<i class="w-4 h-4" data-lucide="refresh-cw" id="refreshIcon"></i>
<span id="refreshText">Refresh Halaman</span>
</button>
<div class="mt-4 text-center">
<h2 class="text-white/90 text-lg font-semibold">Selamat Datang!</h2>
<p class="text-orange-100/70 text-sm">Siap kelola sistem eSPJ dengan efisien</p>
</div>
</div>
</div>
<div class="px-6 mb-6">
<div class="grid grid-cols-2 gap-4">
<div class="bg-white rounded-xl p-4 shadow-sm border border-gray-100 hover:shadow-md transition-shadow">
<div class="flex items-center justify-between">
<div>
<p class="text-gray-500 text-xs font-medium">Total Driver</p>
<p class="text-2xl font-bold text-gray-900">10</p>
</div>
<div class="w-10 h-10 rounded-lg bg-green-100 flex items-center justify-center">
<i class="w-5 h-5 text-green-600" data-lucide="users"></i>
</div>
</div>
</div>
<div class="bg-white rounded-xl p-4 shadow-sm border border-gray-100 hover:shadow-md transition-shadow">
<div class="flex items-center justify-between">
<div>
<p class="text-gray-500 text-xs font-medium">Total SPJ</p>
<p class="text-2xl font-bold text-gray-900">15</p>
</div>
<div class="w-10 h-10 rounded-lg bg-blue-100 flex items-center justify-center">
<i class="w-5 h-5 text-blue-600" data-lucide="map"></i>
</div>
</div>
</div>
</div>
</div>
<partial name="~/Views/Admin/Transport/SpjAdmin/Shared/Components/_Navigation.cshtml" />
</div>
<partial name="~/Views/Admin/Transport/SpjAdmin/Shared/Components/_Navigation.cshtml" />
</div>
<register-block dynamic-section="scripts" key="jsHomeKosong">
<register-block dynamic-section="scripts" key="jsHomeAdmin">
<style>
@@keyframes float {
0%, 100% { transform: translateY(0px); }
50% { transform: translateY(-10px); }
}
@@keyframes shimmer {
0% { background-position: -200px 0; }
100% { background-position: calc(200px + 100%) 0; }
0%, 100% { transform: translateY(0) rotate(0deg); }
50% { transform: translateY(-10px) rotate(2deg); }
}
.float-animation {
animation: float 3s ease-in-out infinite;
}
.shimmer {
background: linear-gradient(90deg, transparent, rgba(255,255,255,0.4), transparent);
background-size: 200px 100%;
animation: shimmer 2s infinite;
}
.refresh-spin {
animation: spin 1s linear infinite;
}
@@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
.float-animation-delayed {
animation: float 4s ease-in-out infinite;
}
</style>
<script>
document.addEventListener("DOMContentLoaded", function () {
const userLocationEl = document.getElementById("userLocation");
function reverseGeocode(lat, lng) {
fetch(`https://nominatim.openstreetmap.org/reverse?format=json&lat=${lat}&lon=${lng}`)
.then(res => res.json())
.then(data => {
const address = data.display_name || `${lat}, ${lng}`;
userLocationEl.textContent = address;
localStorage.setItem("user_latitude", lat);
localStorage.setItem("user_longitude", lng);
localStorage.setItem("user_address", address);
})
.catch(() => {
userLocationEl.textContent = `${lat}, ${lng}`;
});
}
function getLocationUpdate() {
if ("geolocation" in navigator) {
userLocationEl.textContent = "Mendeteksi lokasi baru...";
navigator.geolocation.getCurrentPosition(
function (position) {
const lat = position.coords.latitude.toFixed(6);
const lng = position.coords.longitude.toFixed(6);
reverseGeocode(lat, lng);
},
function () {
userLocationEl.textContent = "Lokasi tidak diizinkan";
}
);
} else {
userLocationEl.textContent = "Browser tidak mendukung lokasi";
}
}
const savedAddress = localStorage.getItem("user_address");
if (savedAddress) {
userLocationEl.textContent = savedAddress;
} else {
getLocationUpdate();
}
userLocationEl.addEventListener("click", function () {
getLocationUpdate();
});
const refreshBtn = document.getElementById('refreshButton');
const refreshIcon = document.getElementById('refreshIcon');
const refreshText = document.getElementById('refreshText');
if (refreshBtn) {
refreshBtn.addEventListener("click", function() {
refreshIcon.style.animation = 'spin 1s linear infinite';
refreshText.textContent = 'Memuat...';
refreshBtn.disabled = true;
refreshBtn.style.opacity = '0.8';
setTimeout(() => {
location.reload();
}, 1000);
});
}
const mainIcon = document.querySelector('[data-lucide="clipboard-list"]');
if (mainIcon) {
mainIcon.closest('.w-24').classList.add('float-animation');
}
const mainCard = document.querySelector('.bg-gradient-to-br');
if (mainCard) {
mainCard.style.opacity = '0';
mainCard.style.transform = 'translateY(20px)';
mainCard.style.transition = 'all 0.6s ease-out';
setTimeout(() => {
mainCard.style.opacity = '1';
mainCard.style.transform = 'translateY(0)';
}, 100);
}
});
</script>
<script>
document.addEventListener("DOMContentLoaded", function () {
const btn = document.getElementById("profileMenuButton");
const dropdown = document.getElementById("profileMenuDropdown");
btn.addEventListener("click", function (e) {
e.stopPropagation();
dropdown.classList.toggle("hidden");
});
if (btn && dropdown) {
btn.addEventListener("click", function (e) {
e.stopPropagation();
e.preventDefault();
if (dropdown.classList.contains("hidden")) {
dropdown.classList.remove("hidden");
dropdown.style.opacity = "0";
dropdown.style.transform = "translateY(-10px) scale(0.95)";
setTimeout(() => {
dropdown.style.transition = "all 0.2s ease-out";
dropdown.style.opacity = "1";
dropdown.style.transform = "translateY(0) scale(1)";
}, 10);
} else {
dropdown.style.transition = "all 0.15s ease-in";
dropdown.style.opacity = "0";
dropdown.style.transform = "translateY(-10px) scale(0.95)";
setTimeout(() => {
dropdown.classList.add("hidden");
}, 150);
}
});
document.addEventListener("click", function () {
dropdown.classList.add("hidden");
document.addEventListener("click", function (e) {
if (!btn.contains(e.target) && !dropdown.contains(e.target)) {
dropdown.style.transition = "all 0.15s ease-in";
dropdown.style.opacity = "0";
dropdown.style.transform = "translateY(-10px) scale(0.95)";
setTimeout(() => {
dropdown.classList.add("hidden");
}, 150);
}
});
dropdown.addEventListener("click", function (e) {
e.stopPropagation();
});
}
const statCards = document.querySelectorAll('.grid > div');
statCards.forEach((card, index) => {
card.style.opacity = "0";
card.style.transform = "translateY(20px)";
setTimeout(() => {
card.style.transition = "all 0.3s ease-out";
card.style.opacity = "1";
card.style.transform = "translateY(0)";
}, 300 + (index * 100));
});
});
</script>

View File

@ -93,26 +93,12 @@
</div>
</div>
<div class="bg-gray-50 border border-gray-200 rounded-lg p-3 text-sm">
<div class="flex items-start">
<i class="w-4 h-4 text-gray-600 mr-2 mt-0.5" data-lucide="lightbulb"></i>
<div class="text-gray-700">
<p class="font-medium mb-1">Tips Scanning:</p>
<ul class="text-xs space-y-1">
<li>• Pastikan QR code dalam pencahayaan yang cukup</li>
<li>• Jaga jarak 15-30cm dari kamera</li>
<li>• Arahkan kamera secara tegak lurus ke QR code</li>
<li>• Pastikan QR code tidak buram atau rusak</li>
<li>• <strong>Klik "Izinkan/Allow" saat browser meminta akses kamera</strong></li>
</ul>
</div>
</div>
</div>
</div>
<div class="border-t pt-4">
<h3 class="text-gray-700 font-medium mb-3">Atau input manual:</h3>
<form id="manual-form" method="post" action="@Url.Action("ProcessScan", "Scan")">
@Html.AntiForgeryToken()
<div class="flex gap-2">
<input type="text"
id="manual-barcode"
@ -152,7 +138,23 @@
<partial name="~/Views/Admin/Transport/SpjAdmin/Shared/Components/_Navigation.cshtml" />
</div>
<div id="scan-modal" class="fixed inset-0 bg-black/50 backdrop-blur-sm z-50 hidden flex items-center justify-center">
<div class="bg-white py-4 rounded-2xl shadow-2xl max-w-sm w-full border border-gray-100">
<div class="p-8 text-center">
<div id="modal-icon" class="mx-auto mb-6">
</div>
<h3 id="modal-title" class="text-xl font-bold mb-3 text-gray-800"></h3>
<p id="modal-message" class="text-gray-600 mb-6 leading-relaxed"></p>
<button id="modal-close" class="bg-orange-500 hover:bg-orange-600 text-white px-8 py-3 rounded-xl transition-all duration-200 font-medium shadow-lg hover:shadow-xl transform hover:-translate-y-0.5">
OK
</button>
</div>
</div>
</div>
<register-block dynamic-section="scripts" key="jsScan">
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://unpkg.com/html5-qrcode@2.3.8/html5-qrcode.min.js" type="text/javascript"></script>
<script>
@ -196,6 +198,13 @@
this.confirmBtn.addEventListener('click', () => this.confirmScan());
this.retryBtn.addEventListener('click', () => this.retryScan());
this.manualForm.addEventListener('submit', (e) => this.handleManualSubmit(e));
$('#modal-close').on('click', () => this.hideModal());
$('#scan-modal').on('click', (e) => {
if (e.target.id === 'scan-modal') {
this.hideModal();
}
});
}
checkBrowserSupport() {
@ -326,13 +335,13 @@
handleBarcodeDetected(decodedText, decodedResult) {
if (decodedText && decodedText.length >= 5) {
this.flashSuccess();
this.playSuccessSound();
this.vibrate();
this.detectedCode = decodedText;
this.showResult(decodedText);
this.stopScanner();
this.playSuccessSound();
this.stopScanner();
this.vibrate();
this.processScanCode(decodedText);
}
}
@ -368,11 +377,46 @@
confirmScan() {
if (this.detectedCode) {
this.manualInput.value = this.detectedCode;
this.manualForm.submit();
this.processScanCode(this.detectedCode);
}
}
processScanCode(code) {
this.showModal('loading', 'Memproses...', 'Sedang memverifikasi kode SPJ...', false);
$.ajax({
url: '@Url.Action("ProcessScan", "Scan")', // nanti tinggal ganti aja yaa
type: 'POST',
data: {
barcode: code
},
success: (response) => {
if (response.success) {
this.showModal('success', 'Scan Berhasil!', 'SPJ berhasil ditemukan dan diproses.', true);
setTimeout(() => {
this.hideResult();
this.manualInput.value = '';
}, 2000);
} else {
this.showModal('error', 'SPJ Tidak Ditemukan', response.message || 'Kode SPJ tidak ditemukan dalam database.', true);
}
},
error: (xhr, status, error) => {
let errorMessage = 'Terjadi kesalahan saat memproses scan.';
if (xhr.responseJSON && xhr.responseJSON.message) {
errorMessage = xhr.responseJSON.message;
} else if (xhr.status === 404) {
errorMessage = 'SPJ tidak ditemukan dalam database.';
} else if (xhr.status === 500) {
errorMessage = 'Terjadi kesalahan server. Silakan coba lagi.';
}
this.showModal('error', 'Error', errorMessage, true);
}
});
}
async retryScan() {
this.hideResult();
this.hideError();
@ -389,18 +433,20 @@
}
handleManualSubmit(e) {
e.preventDefault();
const code = this.manualInput.value.trim();
if (!code) {
e.preventDefault();
this.showError('Silakan masukkan kode SPJ.');
this.showModal('error', 'Input Kosong', 'Silakan masukkan kode SPJ.', true);
return;
}
if (code.length < 5) {
e.preventDefault();
this.showError('Kode SPJ minimal 5 karakter.');
this.showModal('error', 'Kode Tidak Valid', 'Kode SPJ minimal 5 karakter.', true);
return;
}
this.processScanCode(code);
}
showLoading() {
@ -454,9 +500,54 @@
} catch (e) {
}
}
showModal(type, title, message, showCloseButton = true) {
const iconHtml = {
'success': '<div class="w-20 h-20 mx-auto bg-green-100 rounded-full flex items-center justify-center shadow-lg"><i class="w-10 h-10 text-green-600" data-lucide="check-circle"></i></div>',
'error': '<div class="w-20 h-20 mx-auto bg-red-100 rounded-full flex items-center justify-center shadow-lg"><i class="w-10 h-10 text-red-600" data-lucide="x-circle"></i></div>',
'loading': '<div class="w-20 h-20 mx-auto bg-blue-100 rounded-full flex items-center justify-center shadow-lg"><div class="loading-spinner-modal"></div></div>'
};
$('#modal-icon').html(iconHtml[type] || iconHtml['error']);
$('#modal-title').text(title);
$('#modal-message').text(message);
if (showCloseButton) {
$('#modal-close').show();
} else {
$('#modal-close').hide();
}
$('#scan-modal').removeClass('hidden');
$('#scan-modal').css('opacity', '0').animate({'opacity': '1'}, 300);
$('#scan-modal .bg-white').css('transform', 'scale(0.8)').animate({
'transform': 'scale(1)'
}, 300);
if (typeof lucide !== 'undefined') {
lucide.createIcons();
}
}
hideModal() {
$('#scan-modal').animate({'opacity': '0'}, 200, function() {
$('#scan-modal').addClass('hidden');
$('#scan-modal').css('opacity', '');
$('#scan-modal .bg-white').css('transform', '');
});
}
}
document.addEventListener('DOMContentLoaded', function() {
$.ajaxSetup({
beforeSend: function(xhr, settings) {
if (!/^(GET|HEAD|OPTIONS|TRACE)$/i.test(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("RequestVerificationToken", $('input[name="__RequestVerificationToken"]').val());
}
}
});
function waitForLibrary() {
if (typeof Html5Qrcode !== 'undefined') {
new BarcodeScanner();

View File

@ -86,6 +86,15 @@
animation: spin 1s linear infinite;
}
.loading-spinner-modal {
border: 3px solid rgba(59, 130, 246, 0.3);
border-top: 3px solid #3b82f6;
border-radius: 50%;
width: 24px;
height: 24px;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% {
transform: rotate(0deg);

File diff suppressed because it is too large Load Diff