197 lines
7.1 KiB
Vue
197 lines
7.1 KiB
Vue
<template>
|
|
<mainLayout>
|
|
<div class="p-6 flex flex-col sm:flex-row justify-between items-start gap-3">
|
|
<p class="font-serif italic text-[25px] text-D">NAMPAN</p>
|
|
|
|
<div class="flex flex-col gap-3 justify-end w-full sm:w-auto">
|
|
<Searchbar v-model:search="searchQuery" />
|
|
<div class="flex w-full gap-2" v-if="isAdmin">
|
|
<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
|
|
</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">
|
|
Kosongkan Semua Nampan
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<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">
|
|
<strong class="font-bold">Error!</strong>
|
|
<span class="block sm:inline">{{ alert.error }}</span>
|
|
</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">
|
|
<strong class="font-bold">Success!</strong>
|
|
<span class="block sm:inline">{{ alert.success }}</span>
|
|
</div>
|
|
</div>
|
|
|
|
<TrayList :search="searchQuery" @edit="editTray" @delete="promptDeleteTray" />
|
|
|
|
<!-- 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 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">
|
|
{{ editingTrayId ? "Edit Nampan" : "Tambah Nampan" }}
|
|
</h2>
|
|
<label class="block mb-2 text-sm font-medium text-D" for="tray-name">Nama Nampan</label>
|
|
<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>
|
|
<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="saveTray" class="px-4 py-2 bg-C hover:bg-C/80 rounded-md text-D">Simpan</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Komponen ConfirmDeleteModal yang diperbaiki -->
|
|
<ConfirmDeleteModal
|
|
:isOpen="isConfirmModalVisible"
|
|
:title="confirmModalTitle"
|
|
:message="confirmModalMessage"
|
|
:confirmText="confirmText"
|
|
:cancelText="cancelText"
|
|
@confirm="handleConfirmAction"
|
|
@cancel="closeConfirmModal"
|
|
/>
|
|
</mainLayout>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref } from "vue";
|
|
import axios from "axios";
|
|
import mainLayout from "../layouts/mainLayout.vue";
|
|
import Searchbar from "../components/Searchbar.vue";
|
|
import TrayList from "../components/TrayList.vue";
|
|
import InputField from "../components/InputField.vue";
|
|
import ConfirmDeleteModal from "../components/ConfirmDeleteModal.vue";
|
|
|
|
const isAdmin = localStorage.getItem("role") === "owner";
|
|
const searchQuery = ref("");
|
|
const showModal = ref(false);
|
|
const trayName = ref("");
|
|
const editingTrayId = ref(null);
|
|
const errorCreate = ref("");
|
|
const timer = ref(null);
|
|
const alert = ref(null);
|
|
|
|
// State untuk modal konfirmasi
|
|
const isConfirmModalVisible = ref(false);
|
|
const confirmModalTitle = ref("");
|
|
const confirmModalMessage = ref("");
|
|
const confirmText = ref("Ya, Konfirmasi");
|
|
const cancelText = ref("Batal");
|
|
const trayToDeleteId = ref(null);
|
|
|
|
const openModal = () => { showModal.value = true; };
|
|
const closeModal = () => {
|
|
trayName.value = "";
|
|
editingTrayId.value = null;
|
|
showModal.value = false;
|
|
};
|
|
|
|
const saveTray = async () => {
|
|
if (!trayName.value.trim()) {
|
|
errorCreate.value = "Nama nampan tidak boleh kosong.";
|
|
clearTimeout(timer.value);
|
|
timer.value = setTimeout(() => { errorCreate.value = ""; }, 3000);
|
|
return;
|
|
}
|
|
try {
|
|
const token = localStorage.getItem("token");
|
|
const headers = { Authorization: `Bearer ${token}` };
|
|
if (editingTrayId.value) {
|
|
await axios.put(`/api/nampan/${editingTrayId.value}`, { nama: trayName.value }, { headers });
|
|
alert.value = { success: "Nampan berhasil diperbarui" };
|
|
} else {
|
|
await axios.post("/api/nampan", { nama: trayName.value }, { headers });
|
|
alert.value = { success: "Nampan berhasil ditambahkan" };
|
|
}
|
|
closeModal();
|
|
location.reload();
|
|
} catch (error) {
|
|
console.error(error);
|
|
errorCreate.value = error.response?.data?.message || "Gagal menyimpan nampan.";
|
|
clearTimeout(timer.value);
|
|
timer.value = setTimeout(() => { errorCreate.value = ""; }, 3000);
|
|
}
|
|
};
|
|
|
|
const closeConfirmModal = () => {
|
|
isConfirmModalVisible.value = false;
|
|
trayToDeleteId.value = null;
|
|
confirmModalTitle.value = "";
|
|
confirmModalMessage.value = "";
|
|
confirmText.value = "Ya, Konfirmasi";
|
|
cancelText.value = "Batal";
|
|
};
|
|
|
|
const promptEmptyAllTrays = () => {
|
|
confirmModalTitle.value = "Kosongkan semua nampan?";
|
|
confirmModalMessage.value = `Semua item akan dimasukkan ke <span class="font-semibold">Brankas</span>.<br />Masuk ke menu <b>Brankas</b> untuk mengembalikan item ke nampan.`;
|
|
confirmText.value = "Ya, Kosongkan";
|
|
cancelText.value = "Batal";
|
|
trayToDeleteId.value = null;
|
|
isConfirmModalVisible.value = true;
|
|
};
|
|
|
|
const promptDeleteTray = (tray) => {
|
|
confirmModalTitle.value = `Hapus Nampan "${tray.nama}"?`;
|
|
confirmModalMessage.value = "Semua item di dalam nampan ini juga akan dipindahkan ke Brankas. Aksi ini tidak dapat dibatalkan.";
|
|
confirmText.value = "Ya, Hapus";
|
|
cancelText.value = "Batal";
|
|
trayToDeleteId.value = tray.id;
|
|
isConfirmModalVisible.value = true;
|
|
};
|
|
|
|
const handleConfirmAction = async () => {
|
|
if (trayToDeleteId.value) {
|
|
// Hapus nampan spesifik
|
|
try {
|
|
await axios.delete(`/api/nampan/${trayToDeleteId.value}`, {
|
|
headers: { Authorization: `Bearer ${localStorage.getItem("token")}` },
|
|
});
|
|
alert.value = { success: "Nampan berhasil dihapus" };
|
|
location.reload();
|
|
} catch (error) {
|
|
console.error(error);
|
|
alert.value = { error: "Gagal menghapus nampan. Silakan coba lagi." };
|
|
}
|
|
} else {
|
|
// Kosongkan semua nampan
|
|
try {
|
|
await axios.delete("/api/kosongkan-nampan", {
|
|
headers: { Authorization: `Bearer ${localStorage.getItem("token")}` },
|
|
});
|
|
alert.value = { success: "Semua nampan berhasil dikosongkan" };
|
|
location.reload();
|
|
} catch (error) {
|
|
console.error(error);
|
|
alert.value = { error: "Gagal mengosongkan nampan. Silakan coba lagi." };
|
|
}
|
|
}
|
|
|
|
closeConfirmModal();
|
|
clearTimeout(timer.value);
|
|
timer.value = setTimeout(() => { alert.value = null }, 3000);
|
|
};
|
|
|
|
// Fungsi untuk edit nampan
|
|
const editTray = (tray) => {
|
|
trayName.value = tray.nama;
|
|
editingTrayId.value = tray.id;
|
|
showModal.value = true;
|
|
};
|
|
</script>
|
|
|
|
<style scoped>
|
|
@keyframes fadeIn {
|
|
from { opacity: 0; transform: scale(0.95); }
|
|
to { opacity: 1; transform: scale(1); }
|
|
}
|
|
.animate-fadeIn {
|
|
animation: fadeIn 0.25s ease-out forwards;
|
|
}
|
|
</style>
|