[Update] Durasi alert halaman nampan

This commit is contained in:
Baghaztra 2025-09-29 11:18:49 +07:00
parent 9c00f3db7d
commit 9323eb2700
2 changed files with 87 additions and 96 deletions

View File

@ -82,7 +82,6 @@
</div> </div>
</div> </div>
</div> </div>
</div>
<!-- Pop-up pindah item --> <!-- Pop-up pindah item -->
<div v-if="isPopupVisible" class="fixed inset-0 bg-black/50 flex items-center justify-center p-4 z-50"> <div v-if="isPopupVisible" class="fixed inset-0 bg-black/50 flex items-center justify-center p-4 z-50">
@ -118,7 +117,6 @@
</div> </div>
<div class="flex justify-end gap-2"> <div class="flex justify-end gap-2">
<button @click="closePopup" class="px-4 py-2 rounded bg-gray-400 hover:bg-gray-500 text-white transition"> <button @click="closePopup" class="px-4 py-2 rounded bg-gray-400 hover:bg-gray-500 text-white transition">
{{ isAdmin ? 'Batal' : 'Tutup' }} {{ isAdmin ? 'Batal' : 'Tutup' }}
</button> </button>
@ -135,15 +133,10 @@
</div> </div>
<!-- Modal Konfirmasi Hapus --> <!-- Modal Konfirmasi Hapus -->
<ConfirmDeleteModal <ConfirmDeleteModal :isOpen="showDeleteConfirm" title="Konfirmasi Hapus Item"
:isOpen="showDeleteConfirm" message="Apakah kamu yakin ingin menghapus item ini?" confirmText="Ya, Hapus" cancelText="Batal"
title="Konfirmasi Hapus Item" @confirm="confirmDelete" @cancel="cancelDelete" />
message="Apakah kamu yakin ingin menghapus item ini?" </div>
confirmText="Ya, Hapus"
cancelText="Batal"
@confirm="confirmDelete"
@cancel="cancelDelete"
/>
</template> </template>
<script setup> <script setup>
@ -159,6 +152,7 @@ const props = defineProps({
}); });
const emit = defineEmits(["edit", "delete"]); const emit = defineEmits(["edit", "delete"]);
const trays = ref([]); const trays = ref([]);
const loading = ref(true); const loading = ref(true);
const error = ref(null); const error = ref(null);
@ -167,6 +161,7 @@ const error = ref(null);
const isPopupVisible = ref(false); const isPopupVisible = ref(false);
const selectedItem = ref(null); const selectedItem = ref(null);
const selectedTrayId = ref(""); const selectedTrayId = ref("");
const showDeleteConfirm = ref(false);
// QR Code generator // QR Code generator
const qrCodeUrl = computed(() => { const qrCodeUrl = computed(() => {
@ -235,44 +230,23 @@ const printQR = () => {
} }
}; };
const showDeleteConfirm = ref(false);
const confirmDelete = async () => { const confirmDelete = async () => {
if (!selectedItem.value) return; if (!selectedItem.value) return;
try { try {
// Panggil API hapus item
await axios.delete(`/api/item/${selectedItem.value.id}`, { await axios.delete(`/api/item/${selectedItem.value.id}`, {
headers: { Authorization: `Bearer ${localStorage.getItem("token")}` }, headers: { Authorization: `Bearer ${localStorage.getItem("token")}` },
}); });
// Tampilkan alert sukses
alert.value = { success: `Item ${selectedItem.value.kode_item} berhasil dihapus.` };
// Refresh data
await refreshData(); await refreshData();
// Tutup modal & popup
showDeleteConfirm.value = false; showDeleteConfirm.value = false;
closePopup(); closePopup();
// Auto hide alert
clearTimeout(timer.value);
timer.value = setTimeout(() => { alert.value = null; }, 3000);
} catch (err) { } catch (err) {
console.error("Gagal menghapus item:", err.response?.data || err); console.error("Gagal menghapus item:", err.response?.data || err);
alert.value = { error: err.response?.data?.message || "Gagal menghapus item. Silakan coba lagi." }; error.value = err.response?.data?.message || "Gagal menghapus item. Silakan coba lagi.";
// Auto hide alert error
clearTimeout(timer.value);
timer.value = setTimeout(() => { alert.value = null; }, 5000);
} }
}; };
const cancelDelete = () => { const cancelDelete = () => {
showDeleteConfirm.value = false; showDeleteConfirm.value = false;
}; };
@ -307,6 +281,7 @@ const saveMove = async () => {
closePopup(); closePopup();
} catch (err) { } catch (err) {
console.error("Gagal memindahkan item:", err.response?.data || err); console.error("Gagal memindahkan item:", err.response?.data || err);
error.value = err.response?.data?.message || "Gagal memindahkan item. Silakan coba lagi.";
} }
}; };
@ -345,7 +320,7 @@ const emptyTrays = computed(() => {
return trays.value.filter(tray => parseFloat(totalWeight(tray)) === 0).length; return trays.value.filter(tray => parseFloat(totalWeight(tray)) === 0).length;
}); });
// --- Ambil data nampan + item --- // Ambil data nampan + item
const refreshData = async () => { const refreshData = async () => {
try { try {
const nampanRes = await axios.get("/api/nampan", { const nampanRes = await axios.get("/api/nampan", {
@ -370,4 +345,7 @@ const filteredTrays = computed(() => {
onMounted(() => { onMounted(() => {
refreshData(); refreshData();
}); });
// Expose refreshData to parent
defineExpose({ refreshData });
</script> </script>

View File

@ -9,7 +9,8 @@
<button @click="openModal" class="px-4 py-2 sm:px-2 sm:py-1 hover:bg-B bg-C rounded-md shadow w-full"> <button @click="openModal" class="px-4 py-2 sm:px-2 sm:py-1 hover:bg-B bg-C rounded-md shadow w-full">
Tambah Nampan Tambah Nampan
</button> </button>
<button @click="promptEmptyAllTrays" class="px-4 py-2 sm:px-2 sm:py-1 bg-red-500 hover:bg-red-600 text-white rounded-md w-full"> <button @click="promptEmptyAllTrays"
class="px-4 py-2 sm:px-2 sm:py-1 bg-red-500 hover:bg-red-600 text-white rounded-md w-full">
Kosongkan Semua Nampan Kosongkan Semua Nampan
</button> </button>
</div> </div>
@ -17,21 +18,24 @@
</div> </div>
<div class="px-6" v-if="alert"> <div class="px-6" v-if="alert">
<div v-if="alert.error" class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative mb-4" role="alert"> <div v-if="alert.error" class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative mb-4"
role="alert">
<strong class="font-bold">Error!</strong> <strong class="font-bold">Error!</strong>
<span class="block sm:inline">{{ alert.error }}</span> <span class="block sm:inline">{{ alert.error }}</span>
</div> </div>
<div v-if="alert.success" class="bg-green-100 border border-green-400 text-green-700 px-4 py-3 rounded relative mb-4" role="alert"> <div v-if="alert.success"
class="bg-green-100 border border-green-400 text-green-700 px-4 py-3 rounded relative mb-4" role="alert">
<strong class="font-bold">Success!</strong> <strong class="font-bold">Success!</strong>
<span class="block sm:inline">{{ alert.success }}</span> <span class="block sm:inline">{{ alert.success }}</span>
</div> </div>
</div> </div>
<TrayList :search="searchQuery" @edit="editTray" @delete="promptDeleteTray" /> <TrayList ref="trayList" :search="searchQuery" @edit="editTray" @delete="promptDeleteTray" />
<!-- Modal untuk tambah/edit nampan --> <!-- Modal untuk tambah/edit nampan -->
<div v-if="showModal" class="fixed inset-0 bg-black/75 flex justify-center items-center z-50 backdrop-blur-sm"> <div v-if="showModal" class="fixed inset-0 bg-black/75 flex justify-center items-center z-50 backdrop-blur-sm">
<div class="bg-white rounded-lg shadow-lg p-6 w-96 transform transition-all duration-300 scale-95 opacity-0 animate-fadeIn"> <div
class="bg-white rounded-lg shadow-lg p-6 w-96 transform transition-all duration-300 scale-95 opacity-0 animate-fadeIn">
<h2 class="text-lg font-semibold mb-4 text-D"> <h2 class="text-lg font-semibold mb-4 text-D">
{{ editingTrayId ? "Edit Nampan" : "Tambah Nampan" }} {{ editingTrayId ? "Edit Nampan" : "Tambah Nampan" }}
</h2> </h2>
@ -39,22 +43,16 @@
<InputField id="tray-name" v-model="trayName" type="text" placeholder="Contoh: A1" class="mb-1" /> <InputField id="tray-name" v-model="trayName" type="text" placeholder="Contoh: A1" class="mb-1" />
<p v-if="errorCreate" class="text-red-500 text-sm mb-4">{{ errorCreate }}</p> <p v-if="errorCreate" class="text-red-500 text-sm mb-4">{{ errorCreate }}</p>
<div class="flex justify-end mt-3 gap-2"> <div class="flex justify-end mt-3 gap-2">
<button @click="closeModal" class="px-4 py-2 bg-gray-400 hover:bg-gray-500 text-white rounded-md">Batal</button> <button @click="closeModal"
class="px-4 py-2 bg-gray-400 hover:bg-gray-500 text-white rounded-md">Batal</button>
<button @click="saveTray" class="px-4 py-2 bg-C hover:bg-C/80 rounded-md text-D">Simpan</button> <button @click="saveTray" class="px-4 py-2 bg-C hover:bg-C/80 rounded-md text-D">Simpan</button>
</div> </div>
</div> </div>
</div> </div>
<!-- Komponen ConfirmDeleteModal yang diperbaiki --> <!-- Komponen ConfirmDeleteModal yang diperbaiki -->
<ConfirmDeleteModal <ConfirmDeleteModal :isOpen="isConfirmModalVisible" :title="confirmModalTitle" :message="confirmModalMessage"
:isOpen="isConfirmModalVisible" :confirmText="confirmText" :cancelText="cancelText" @confirm="handleConfirmAction" @cancel="closeConfirmModal" />
:title="confirmModalTitle"
:message="confirmModalMessage"
:confirmText="confirmText"
:cancelText="cancelText"
@confirm="handleConfirmAction"
@cancel="closeConfirmModal"
/>
</mainLayout> </mainLayout>
</template> </template>
@ -75,6 +73,7 @@ const editingTrayId = ref(null);
const errorCreate = ref(""); const errorCreate = ref("");
const timer = ref(null); const timer = ref(null);
const alert = ref(null); const alert = ref(null);
const trayList = ref(null); // Add ref for TrayList
// State untuk modal konfirmasi // State untuk modal konfirmasi
const isConfirmModalVisible = ref(false); const isConfirmModalVisible = ref(false);
@ -109,7 +108,9 @@ const saveTray = async () => {
alert.value = { success: "Nampan berhasil ditambahkan" }; alert.value = { success: "Nampan berhasil ditambahkan" };
} }
closeModal(); closeModal();
location.reload(); if (trayList.value) {
await trayList.value.refreshData(); // Call refreshData on TrayList
}
} catch (error) { } catch (error) {
console.error(error); console.error(error);
errorCreate.value = error.response?.data?.message || "Gagal menyimpan nampan."; errorCreate.value = error.response?.data?.message || "Gagal menyimpan nampan.";
@ -153,7 +154,9 @@ const handleConfirmAction = async () => {
headers: { Authorization: `Bearer ${localStorage.getItem("token")}` }, headers: { Authorization: `Bearer ${localStorage.getItem("token")}` },
}); });
alert.value = { success: "Nampan berhasil dihapus" }; alert.value = { success: "Nampan berhasil dihapus" };
location.reload(); if (trayList.value) {
await trayList.value.refreshData(); // Call refreshData on TrayList
}
} catch (error) { } catch (error) {
console.error(error); console.error(error);
alert.value = { error: "Gagal menghapus nampan. Silakan coba lagi." }; alert.value = { error: "Gagal menghapus nampan. Silakan coba lagi." };
@ -165,7 +168,9 @@ const handleConfirmAction = async () => {
headers: { Authorization: `Bearer ${localStorage.getItem("token")}` }, headers: { Authorization: `Bearer ${localStorage.getItem("token")}` },
}); });
alert.value = { success: "Semua nampan berhasil dikosongkan" }; alert.value = { success: "Semua nampan berhasil dikosongkan" };
location.reload(); if (trayList.value) {
await trayList.value.refreshData(); // Call refreshData on TrayList
}
} catch (error) { } catch (error) {
console.error(error); console.error(error);
alert.value = { error: "Gagal mengosongkan nampan. Silakan coba lagi." }; alert.value = { error: "Gagal mengosongkan nampan. Silakan coba lagi." };
@ -187,9 +192,17 @@ const editTray = (tray) => {
<style scoped> <style scoped>
@keyframes fadeIn { @keyframes fadeIn {
from { opacity: 0; transform: scale(0.95); } from {
to { opacity: 1; transform: scale(1); } opacity: 0;
transform: scale(0.95);
}
to {
opacity: 1;
transform: scale(1);
}
} }
.animate-fadeIn { .animate-fadeIn {
animation: fadeIn 0.25s ease-out forwards; animation: fadeIn 0.25s ease-out forwards;
} }