diff --git a/components/Home.vue b/components/Home.vue
index 667b987..0cdbd0c 100644
--- a/components/Home.vue
+++ b/components/Home.vue
@@ -377,7 +377,7 @@ const loadCarouselItems = async () => {
);
carouselItems.value = itemsWithRatio;
- console.log('Carousel items loaded:', carouselItems.value);
+ // console.log('Carousel items loaded:', carouselItems.value);
} catch (error) {
console.error('Error loading carousel items:', error);
} finally {
diff --git a/components/PembayaranSukses.vue b/components/PembayaranSukses.vue
index 4ee4e53..83f7c2f 100644
--- a/components/PembayaranSukses.vue
+++ b/components/PembayaranSukses.vue
@@ -48,46 +48,45 @@
-
-
-
-
- Nomor RM:
- {{
- paymentStore.qrData.display_norm || '-'
- }}
-
+
+
+
+ Nomor RM:
+ {{
+ paymentStore.qrData.display_norm || "-"
+ }}
+
-
- No. Billing:
- {{
- paymentStore.qrData.display_nobill || '-'
- }}
-
+
+ No. Billing:
+ {{
+ paymentStore.qrData.display_nobill || "-"
+ }}
+
-
-
Pasien:
-
{{
+
+ Pasien:
+ {{
paymentStore.patientInfo.name
- }}
-
-
-
- Nominal:
- {{
+ }}
+
+
+
+ Nominal:
+ {{
formatCurrency(paymentStore.patientInfo.amount)
- }}
-
-
-
- Status:
-
+ }}
+
+
+
+ Status:
+
mdi-check
Berhasil
-
+
+
+
-
-
@@ -292,5 +291,10 @@ const formatCurrency = (amountString) => {
.success-container {
max-width: 650px;
}
+
+ .logo-section-contact {
+ display: none;
+ }
+
}
diff --git a/components/QRISPayment.vue b/components/QRISPayment.vue
index 24db124..a8e1da2 100644
--- a/components/QRISPayment.vue
+++ b/components/QRISPayment.vue
@@ -159,7 +159,7 @@
-
+
diff --git a/composables/useFileSync.ts b/composables/useFileSync.ts
index 33c06f7..774513c 100644
--- a/composables/useFileSync.ts
+++ b/composables/useFileSync.ts
@@ -124,6 +124,39 @@ export function useFileSync() {
}
+ // const tampilFileBrowser = async () => {
+
+ // await syncFiles();
+ // if (isSyncing.value) {
+ // try {
+ // const localStoreKeys = await localStore.keys()
+ // // console.log('localStore Keys:', localStoreKeys)
+ // const files: { name: string; blob: Blob; type: string; url: string }[] = []
+
+ // for (const key of localStoreKeys) {
+ // if (!key.endsWith('-meta')) {
+ // const fileBlob = await localStore.getItem(key)
+
+ // if (fileBlob instanceof Blob) {
+ // const url = URL.createObjectURL(fileBlob)
+ // files.push({ name: key, blob: fileBlob, type: fileBlob.type, url: url })
+
+ // }
+ // }
+ // }
+ // // console.log('Files in IndexedDB:',fileLocal.value)
+ // return fileLocal.value = files
+
+ // } catch (err) {
+ // console.error('Gagal memuat file dari IndexedDB:', err)
+ // } finally {
+ // isSyncing.value = false
+ // }
+
+
+ // }
+ // }
+
const tampilFileBrowser = async () => {
await syncFiles();
@@ -144,7 +177,16 @@ export function useFileSync() {
}
}
}
- // console.log('Files in IndexedDB:',fileLocal.value)
+ // console.log('Files in IndexedDB:',files)
+ // console.log('File Server:', fileServer.value)
+ const fileTidaksama = files.filter(local => !fileServer.value.some(fs => fs.name === local.name))
+ // console.log('File tidak sama dengan server:', fileTidaksama)
+ for (const namaFile of fileTidaksama) {
+ const firstNamePart = namaFile.name.split('.')[0];
+ console.log('file lokal yang tidak ada di server:', firstNamePart);
+ await removeFiles(firstNamePart)
+ }
+
return fileLocal.value = files
} catch (err) {
@@ -156,7 +198,6 @@ export function useFileSync() {
}
}
-
// Bersihkan object URL biar gak bocor memori
onBeforeUnmount(() => {
fileLocal.value.forEach(f => URL.revokeObjectURL(f.url))
diff --git a/nuxt.config.ts b/nuxt.config.ts
index 5ed84ad..d84a28c 100644
--- a/nuxt.config.ts
+++ b/nuxt.config.ts
@@ -2,7 +2,19 @@
import vuetify, { transformAssetUrls } from 'vite-plugin-vuetify'
export default defineNuxtConfig({
compatibilityDate: '2025-07-15',
- devtools: { enabled: true },
+ devtools: {
+ enabled: false, // Enable Nuxt DevTools untuk debugging
+ timeline: {
+ enabled: false, // Enable timeline untuk performance monitoring
+ },
+ },
+ runtimeConfig: {
+ public: {
+ folder_path: "\\\\10.10.123.49\\qris",
+ url_base: "ws://10.10.150.222:8080/api/v1/ws",
+ query: "user_id=QRIS&room=BANKJATIM"
+ }
+ },
ssr:false,
modules: [
'@nuxt/content',
diff --git a/pages/index.vue b/pages/index.vue
index d127207..2e63e41 100644
--- a/pages/index.vue
+++ b/pages/index.vue
@@ -47,9 +47,10 @@ import { useWebSocket } from "~/composables/useWebSocket";
const paymentStore = usePaymentStore();
const router = useRouter();
const localIpAddress = ref(null);
+const config = useRuntimeConfig()
-const WS_URL_BASE = "ws://10.10.150.45:8080/api/v1/ws";
-const WS_QUERY = "user_id=QRIS&room=BANKJATIM";
+const WS_URL_BASE = config.public.url_base;
+const WS_QUERY = config.public.query;
const fullWsUrl = `${WS_URL_BASE}?${WS_QUERY}`;
const {
diff --git a/server/api/serverFile/[name].get.ts b/server/api/serverFile/[name].get.ts
index 8954bfe..8fb4829 100644
--- a/server/api/serverFile/[name].get.ts
+++ b/server/api/serverFile/[name].get.ts
@@ -2,8 +2,8 @@ import fs from 'fs'
import path from 'path'
import { lookup } from 'mime-types'
import { createError, setHeader, sendStream } from 'h3'
-
-const FOLDER_PATH = '\\\\10.10.150.129\\Shared'
+const config = useRuntimeConfig()
+const FOLDER_PATH = config.public.folder_path;
export default defineEventHandler(async (event) => {
const rawName = event.context.params?.name as string | undefined
diff --git a/server/api/serverFile/files.get.ts b/server/api/serverFile/files.get.ts
index 7f41186..12f5d42 100644
--- a/server/api/serverFile/files.get.ts
+++ b/server/api/serverFile/files.get.ts
@@ -5,9 +5,11 @@ import { promisify } from "util"
const readdir = promisify(fs.readdir)
const stat = promisify(fs.stat)
+const config = useRuntimeConfig()
// Lokasi folder network share (pastikan sudah di-mount / accessible dari server)
-const FOLDER_PATH = "\\\\10.10.150.129\\Shared"
+// const FOLDER_PATH = "\\\\10.10.123.49\\qris"
+const FOLDER_PATH = config.public.folder_path;
export default defineEventHandler(async (event) => {
try {
diff --git a/stores/payment.ts b/stores/payment.ts
index 2b04453..3fdb3a7 100644
--- a/stores/payment.ts
+++ b/stores/payment.ts
@@ -1,68 +1,68 @@
// src/stores/payment.ts
-import { defineStore } from 'pinia';
+import { defineStore } from "pinia";
-// 1. Definisikan Tipe Data untuk qrData (penting untuk properti expired_at yang di-spread)
+// definisi tipe data
interface QrData {
- qrvalue: string | null;
- display_nobill: string | null;
- display_name: string | null;
- display_amount: string | null;
- status: '1' | '2' | '0' | null; // "1": Pending, "2": Sukses, "0": Gagal/Expired
- ip: string | null;
- // Tambahkan properti yang di-spread dari API, termasuk expired_at
- expired_at?: string; // Tambahkan expired_at sebagai properti opsional
- [key: string]: any; // Indeks signature untuk properti dinamis (misal: transaction_id, reason)
+ qrvalue: string | null;
+ display_nobill: string | null;
+ display_name: string | null;
+ display_amount: string | null;
+ status: "1" | "2" | "0" | null; // "1": Pending, "2": Sukses, "0": Gagal/Pending
+ ip: string | null;
+ expired_at?: string;
+ [key: string]: any; // Indeks signature untuk properti dinamis (misal: transaction_id, reason)
}
-// 2. Definisikan Tipe Data untuk State
+// definisi tipe data untuk State
interface PaymentState {
- currentStep: 1 | 2 | 3 | 4;
- patientInfo: {
- name: string;
- amount: string;
- expiry: string;
- };
- qrData: QrData;
+ currentStep: 1 | 2 | 3 | 4;
+ patientInfo: {
+ name: string;
+ amount: string;
+ expiry: string;
+ };
+ qrData: QrData;
}
-// Variabel di luar store untuk menyimpan timer, agar persistensi di luar state Pinia
-let autoResetTimer: number | null = null;
+let autoResetTimer: number | null = null;
-export const usePaymentStore = defineStore('payment', {
- state: (): PaymentState => ({ // Gunakan tipedata PaymentState
- currentStep: 1, // 1: Menunggu Data, 2: Tampilkan QRIS, 3: Sukses, 4: Gagal
+export const usePaymentStore = defineStore("payment", {
+ state: (): PaymentState => ({
+ currentStep: 1, // 1: Menunggu Data, 2: Tampilkan QRIS, 3: Sukses, 4: Gagal/Pending
patientInfo: {
- name: '',
- amount: '',
- expiry: '', // Waktu kedaluwarsa diambil dari qrData (via spread)
+ name: "",
+ amount: "",
+ expiry: "",
},
qrData: {
qrvalue: null,
display_nobill: null,
display_name: null,
display_amount: null,
- status: null,
+ status: null,
ip: null,
- // created_at DIHAPUS
- } as QrData, // Type casting untuk QrData
+ } as QrData,
}),
-
+
getters: {
hasQrData: (state): boolean => !!state.qrData.qrvalue,
- safeQrValue: (state): string => state.qrData.qrvalue || 'https://www.google.com',
-
+ safeQrValue: (state): string =>
+ state.qrData.qrvalue || "https://www.google.com",
+
isReadyForStatusCheck: (state): boolean => {
return !!(state.qrData.display_nobill && state.qrData.display_name);
},
-
+
debugInfo: (state) => ({
step: state.currentStep,
- hasIdentifiers: !!(state.qrData.display_nobill && state.qrData.display_name),
+ hasIdentifiers: !!(
+ state.qrData.display_nobill && state.qrData.display_name
+ ),
qrData: state.qrData,
patientInfo: state.patientInfo,
- })
+ }),
},
-
+
actions: {
nextStep() {
this.currentStep++;
@@ -70,32 +70,31 @@ export const usePaymentStore = defineStore('payment', {
prevStep() {
this.currentStep--;
},
-
+
setStep(step: 1 | 2 | 3 | 4) {
console.log(`[STORE] Setting step from ${this.currentStep} to ${step}`);
this.currentStep = step;
},
startAutoReset() {
- if (autoResetTimer) {
- clearTimeout(autoResetTimer);
- }
- console.log('🏠 [STORE] Starting auto return timer (50s) for reset.');
-
- // Di TypeScript, setTimeout mengembalikan number
- autoResetTimer = setTimeout(() => {
- console.log('🏠 [STORE] Auto return to home triggered');
- this.reset();
- }, 10000);
+ if (autoResetTimer) {
+ clearTimeout(autoResetTimer);
+ }
+ console.log("🏠 [STORE] Starting auto return timer (10s) for reset.");
+
+ autoResetTimer = setTimeout(() => {
+ console.log("🏠 [STORE] Auto return to home triggered");
+ this.reset();
+ }, 10000);
},
-
+
reset() {
- console.log('--- [STORE] Resetting payment store ---');
+ console.log("--- [STORE] Resetting payment store ---");
this.currentStep = 1;
this.patientInfo = {
- name: '',
- amount: '',
- expiry: '',
+ name: "",
+ amount: "",
+ expiry: "",
};
this.qrData = {
qrvalue: null,
@@ -105,40 +104,43 @@ export const usePaymentStore = defineStore('payment', {
status: null,
ip: null,
} as QrData; // Pastikan tipe kembali ke QrData
- if (autoResetTimer) {
- clearTimeout(autoResetTimer);
- autoResetTimer = null;
- }
+ if (autoResetTimer) {
+ clearTimeout(autoResetTimer);
+ autoResetTimer = null;
+ }
},
-
+
// Definisikan tipe untuk apiResponse
updatePayment(apiResponse: { data: QrData[] }) {
console.log("=== [STORE] UPDATE PAYMENT ===");
-
+
if (!apiResponse?.data || apiResponse.data.length === 0) {
console.error("Invalid API response structure or empty data array");
return;
}
-
+
const apiData = apiResponse.data[0];
const oldStatus = this.qrData.status;
-
+
// Update qrData dengan semua properti dari API
this.qrData = {
qrvalue: apiData.qrvalue || apiData.qr_code || this.qrData.qrvalue,
display_nobill: apiData.display_nobill || this.qrData.display_nobill,
display_name: apiData.display_name || this.qrData.display_name,
- display_amount: apiData.display_amount || apiData.nominal || this.qrData.display_amount,
- status: apiData.status as QrData['status'] || this.qrData.status, // Type casting untuk status
+ display_amount:
+ apiData.display_amount ||
+ apiData.nominal ||
+ this.qrData.display_amount,
+ status: (apiData.status as QrData["status"]) || this.qrData.status, // Type casting untuk status
ip: apiData.ip || this.qrData.ip,
- // created_at DIHAPUS
- ...apiData // expired_at akan masuk di sini
+
+ ...apiData, // expired_at akan masuk di sini
};
-
+
// Update patientInfo
this.patientInfo = {
- name: this.qrData.display_name || this.patientInfo.name || 'Unknown',
- amount: this.qrData.display_amount || this.patientInfo.amount || '0',
+ name: this.qrData.display_name || this.patientInfo.name || "Unknown",
+ amount: this.qrData.display_amount || this.patientInfo.amount || "0",
expiry: this.patientInfo.expiry,
};
@@ -150,22 +152,26 @@ export const usePaymentStore = defineStore('payment', {
}
if (this.currentStep === 2 && oldStatus !== newStatus) {
- if (newStatus === "2") {
- console.log('🎉 [STORE] Status 2 (SUKSES) diterima. Pindah ke Step 3.');
- this.currentStep = 3;
- this.startAutoReset();
- } else if (newStatus === "0") {
- console.log('❌ [STORE] Status 0 (GAGAL) diterima. Pindah ke Step 4.');
- this.currentStep = 4;
- this.startAutoReset();
- }
+ if (newStatus === "2") {
+ console.log(
+ "🎉 [STORE] Status 2 (SUKSES) diterima. Pindah ke Step 3."
+ );
+ this.currentStep = 3;
+ this.startAutoReset();
+ } else if (newStatus === "0") {
+ console.log(
+ "❌ [STORE] Status 0 (GAGAL) diterima. Pindah ke Step 4."
+ );
+ this.currentStep = 4;
+ this.startAutoReset();
+ }
}
-
+
console.log("Updated qrData:", this.qrData);
console.log("Updated patientInfo:", this.patientInfo);
console.log("===================");
},
-
+
// Method untuk debug
debugCurrentState() {
console.log("=== PAYMENT STORE DEBUG ===");
@@ -177,30 +183,29 @@ export const usePaymentStore = defineStore('payment', {
console.log("Safe QR Value:", this.safeQrValue);
console.log("==========================");
},
-
+
// Method untuk validasi data
validateData(): boolean {
const issues: string[] = [];
-
+
if (!this.qrData.display_nobill) {
- issues.push('display_nobill missing');
+ issues.push("display_nobill missing");
}
-
+
if (!this.qrData.display_name) {
- issues.push('display_name missing');
+ issues.push("display_name missing");
}
-
- // Perlu pengecekan properti qr_code pada apiData, bukan state
- if (!this.qrData.qrvalue) {
- issues.push('QR code missing');
+
+ if (!this.qrData.qrvalue) {
+ issues.push("QR code missing");
}
-
+
if (issues.length > 0) {
- console.warn('Data validation issues:', issues);
+ console.warn("Data validation issues:", issues);
return false;
}
-
+
return true;
- }
+ },
},
-});
\ No newline at end of file
+});