Files
qris-bank-jatim/stores/payment.ts
T

206 lines
6.5 KiB
TypeScript

// src/stores/payment.ts
import { defineStore } from 'pinia';
// 1. Definisikan Tipe Data untuk qrData (penting untuk properti expired_at yang di-spread)
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)
}
// 2. Definisikan Tipe Data untuk State
interface PaymentState {
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;
export const usePaymentStore = defineStore('payment', {
state: (): PaymentState => ({ // Gunakan tipedata PaymentState
currentStep: 1, // 1: Menunggu Data, 2: Tampilkan QRIS, 3: Sukses, 4: Gagal
patientInfo: {
name: '',
amount: '',
expiry: '', // Waktu kedaluwarsa diambil dari qrData (via spread)
},
qrData: {
qrvalue: null,
display_nobill: null,
display_name: null,
display_amount: null,
status: null,
ip: null,
// created_at DIHAPUS
} as QrData, // Type casting untuk QrData
}),
getters: {
hasQrData: (state): boolean => !!state.qrData.qrvalue,
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),
qrData: state.qrData,
patientInfo: state.patientInfo,
})
},
actions: {
nextStep() {
this.currentStep++;
},
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);
},
reset() {
console.log('--- [STORE] Resetting payment store ---');
this.currentStep = 1;
this.patientInfo = {
name: '',
amount: '',
expiry: '',
};
this.qrData = {
qrvalue: null,
display_nobill: null,
display_name: null,
display_amount: null,
status: null,
ip: null,
} as QrData; // Pastikan tipe kembali ke QrData
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
ip: apiData.ip || this.qrData.ip,
// created_at DIHAPUS
...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',
expiry: this.patientInfo.expiry,
};
// --- LOGIKA TRANSISI STATUS OTOMATIS (SUCCESS/FAIL) ---
const newStatus = this.qrData.status;
if (oldStatus !== newStatus) {
console.log(`[STORE] Status changed: ${oldStatus} -> ${newStatus}`);
}
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();
}
}
console.log("Updated qrData:", this.qrData);
console.log("Updated patientInfo:", this.patientInfo);
console.log("===================");
},
// Method untuk debug
debugCurrentState() {
console.log("=== PAYMENT STORE DEBUG ===");
console.log("Current Step:", this.currentStep);
console.log("Patient Info:", this.patientInfo);
console.log("QR Data:", this.qrData);
console.log("Has QR Data:", this.hasQrData);
console.log("Ready for Status Check:", this.isReadyForStatusCheck);
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');
}
if (!this.qrData.display_name) {
issues.push('display_name missing');
}
// Perlu pengecekan properti qr_code pada apiData, bukan state
if (!this.qrData.qrvalue) {
issues.push('QR code missing');
}
if (issues.length > 0) {
console.warn('Data validation issues:', issues);
return false;
}
return true;
}
},
});