diff --git a/resources/js/components/BrankasList.vue b/resources/js/components/BrankasList.vue index 9c3fd4a..af0ee7c 100644 --- a/resources/js/components/BrankasList.vue +++ b/resources/js/components/BrankasList.vue @@ -46,20 +46,20 @@ @click="openMovePopup(item)">
-
-

{{ item.produk.nama }}

+

{{ item.produk?.nama }}

{{ item.kode_item }}

- {{ item.produk.berat }}g + {{ item.produk?.berat }}g @@ -191,7 +191,9 @@ const qrCodeUrl = computed(() => { // Computed untuk statistik const totalWeight = computed(() => { - const total = filteredItems.value.reduce((sum, item) => sum + (item.produk.berat || 0), 0); + const total = filteredItems.value.reduce((sum, item) => { + return sum + (item?.produk?.berat || 0); + }, 0); return total.toFixed(2); }); @@ -331,8 +333,7 @@ const refreshData = async () => { // Filter hanya item yang ada di brankas (id_nampan = null atau tidak ada) items.value = itemRes.data.filter(item => !item.id_nampan); - trays.value = trayRes.data; - + trays.value = trayRes.data; } catch (err) { console.error("Error fetching data:", err); alert.value = { error: err.response?.data?.message || "Gagal mengambil data" }; diff --git a/resources/js/components/KasirForm.vue b/resources/js/components/KasirForm.vue index 2c7c8ba..8e15c27 100644 --- a/resources/js/components/KasirForm.vue +++ b/resources/js/components/KasirForm.vue @@ -31,7 +31,14 @@
- +
@@ -120,6 +127,7 @@ const kodeItem = ref(""); const info = ref(""); const error = ref(""); const hargaJual = ref(null); +const hargaJualFormatted = ref(""); const item = ref(null); const loadingItem = ref(false); const pesanan = ref([]); @@ -131,6 +139,45 @@ const showStruk = ref(false); let errorTimeout = null; let infoTimeout = null; +// Format angka dengan pemisah ribuan +const formatNumber = (num) => { + if (!num) return ""; + return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, "."); +}; + +// Menghapus format dan mengambil angka asli +const unformatNumber = (str) => { + if (!str) return null; + const cleaned = str.replace(/\./g, ""); + const number = parseInt(cleaned); + return isNaN(number) ? null : number; +}; + +// Handler untuk format input harga +const formatHargaInput = (event) => { + const value = event.target.value; + // Hapus semua karakter selain angka + const cleanValue = value.replace(/\D/g, ""); + + if (cleanValue) { + // Format dengan pemisah ribuan + const formatted = formatNumber(cleanValue); + hargaJualFormatted.value = formatted; + hargaJual.value = parseInt(cleanValue); + } else { + hargaJualFormatted.value = ""; + hargaJual.value = null; + } +}; + +// Hanya izinkan angka saat mengetik +const onlyNumbers = (event) => { + const char = String.fromCharCode(event.which); + if (!/[0-9]/.test(char)) { + event.preventDefault(); + } +}; + const inputItem = async () => { if (!kodeItem.value) return; @@ -149,6 +196,8 @@ const inputItem = async () => { }); item.value = response.data; hargaJual.value = item.value.produk.harga_jual; + // Format harga untuk tampilan + hargaJualFormatted.value = formatNumber(item.value.produk.harga_jual); console.log(item.value); @@ -167,6 +216,7 @@ const inputItem = async () => { error.value = "Item tidak ditemukan"; info.value = ""; hargaJual.value = null; + hargaJualFormatted.value = ""; item.value = null; errorTimeout = setTimeout(() => { @@ -201,6 +251,7 @@ const tambahItem = () => { // Reset input fields kodeItem.value = ""; hargaJual.value = null; + hargaJualFormatted.value = ""; item.value = null; info.value = ""; clearTimeout(infoTimeout); diff --git a/resources/js/components/StrukOverlay.vue b/resources/js/components/StrukOverlay.vue index 5f85bb6..583fd29 100644 --- a/resources/js/components/StrukOverlay.vue +++ b/resources/js/components/StrukOverlay.vue @@ -2,9 +2,9 @@
-
-
-
+
+
+
@@ -19,50 +19,40 @@ 08158851178

{{ generateTransactionCode() }}

-
-
Logo
-
Tanggal :
-

{{ getCurrentDate() }}

Nama :
- -
Alamat :
-
No.Hp :
-
- -
-
- Logo_bca - Logo_bri - Logo_bni -
-
- Logo_mastercard - Logo_visa - Logo_mandiri -
+
+ Logo_bca + Logo_bri + Logo_bni +
+
+ Logo_mastercard + Logo_visa + Logo_mandiri +
- +
@@ -88,7 +78,7 @@ {{ item.produk?.nama || '' }} - + @@ -132,15 +122,10 @@

diluar harga jual

-

Rp

- -
- +

Rp

+ + @@ -170,7 +155,30 @@

Terima kasih sudah berbelanja dengan kami

+ + + +
+
+ +
+ + + + + + + + + +
+ + +

{{ toastMessage }}

@@ -204,7 +212,6 @@ const props = defineProps({ } }) - const emit = defineEmits(['close', 'confirm']) const namaPembeli = ref('') @@ -213,7 +220,22 @@ const alamat = ref('') const ongkosBikin = ref(0) const selectedSales = ref(null) const salesOptions = ref([]) -const ongkosBikinFormatted = ref(""); +const ongkosBikinFormatted = ref("") + +// Simple Toast State +const showToast = ref(false) +const toastType = ref('error') // 'error', 'success', 'info' +const toastMessage = ref('') + +const toastClasses = computed(() => { + const baseClasses = 'text-white' + const typeClasses = { + error: 'bg-red-500', + success: 'bg-green-500', + info: 'bg-blue-500' + } + return `${baseClasses} ${typeClasses[toastType.value]}` +}) const grandTotal = computed(() => { return props.total + (ongkosBikin.value || 0) @@ -238,6 +260,17 @@ const generateTransactionCode = () => { return `TRS-${timestamp}` } +// Simple Toast Function +const showSimpleToast = (type, message, duration = 3000) => { + toastType.value = type + toastMessage.value = message + showToast.value = true + + setTimeout(() => { + showToast.value = false + }, duration) +} + const fetchSales = async () => { try { const response = await axios.get('/api/sales', { @@ -251,7 +284,6 @@ const fetchSales = async () => { label: sales.nama })) - if (salesOptions.value.length > 0) { selectedSales.value = salesOptions.value[0].value } @@ -261,28 +293,26 @@ const fetchSales = async () => { } const handleSimpan = () => { - if (!namaPembeli.value.trim()) { - alert('Nama pembeli harus diisi!') + showSimpleToast('error', 'Nama pembeli harus diisi!') return } if (!nomorTelepon.value.trim()) { - alert('Nomor telepon harus diisi!') + showSimpleToast('error', 'Nomor telepon harus diisi!') return } if (!alamat.value.trim()) { - alert('Alamat harus diisi!') + showSimpleToast('error', 'Alamat harus diisi!') return } if (!selectedSales.value) { - alert('Sales harus dipilih!') + showSimpleToast('error', 'Sales harus dipilih!') return } - simpanTransaksi({ id_sales: selectedSales.value, nama_pembeli: namaPembeli.value, @@ -294,7 +324,6 @@ const handleSimpan = () => { }) } - const simpanTransaksi = async (dataTransaksi) => { console.log('Data transaksi yang akan disimpan:', dataTransaksi); @@ -305,15 +334,19 @@ const simpanTransaksi = async (dataTransaksi) => { }, }); - - props.pesanan.value = []; - props.isOpen = false; - - window.location.reload(); + showSimpleToast('success', 'Transaksi berhasil disimpan!', 2000) + + // Delay untuk memberikan waktu user membaca notifikasi + setTimeout(() => { + props.pesanan.value = []; + props.isOpen = false; + window.location.reload(); + }, 2200); } catch (error) { console.error('Error saving transaksi:', error); - alert('Error menyimpan transaksi: ' + (error.response?.data?.message || error.message)); + const errorMessage = error.response?.data?.message || error.message || 'Terjadi kesalahan saat menyimpan transaksi'; + showSimpleToast('error', `Error: ${errorMessage}`, 4000); } }; @@ -332,18 +365,12 @@ const pesananMinimal = computed(() => { }) function formatInput(e) { - let value = e.target.value.replace(/\D/g, ""); - - ongkosBikin.value = value ? parseInt(value, 10) : null; - - ongkosBikinFormatted.value = value ? new Intl.NumberFormat("id-ID").format(value) : ""; } - + \ No newline at end of file diff --git a/resources/js/components/TrayList.vue b/resources/js/components/TrayList.vue index 8274aa0..27cae7c 100644 --- a/resources/js/components/TrayList.vue +++ b/resources/js/components/TrayList.vue @@ -61,18 +61,18 @@ >
foto produk
-

{{ item.produk.nama }}

+

{{ item.produk?.nama }}

{{ item.kode_item }}

- {{ item.produk.berat }}g + {{ item.produk?.berat }}g
@@ -107,7 +107,7 @@ {{ selectedItem.kode_item }}
- {{ selectedItem.produk.nama }} + {{ selectedItem.produk?.nama }}
@@ -248,7 +248,7 @@ const saveMove = async () => { // Hitung total berat const totalWeight = (tray) => { if (!tray.items) return 0; - const total = tray.items.reduce((sum, item) => sum + (item.produk.berat || 0), 0); + const total = tray.items.reduce((sum, item) => sum + (item.produk?.berat || 0), 0); return total.toFixed(2); };
Jml{{ item.nampan?.nama || 'Brankas' }}{{ item.produk.nama ? (item.nampan?.nama || 'Brankas') : '' }} {{ item.produk.berat }}g