diff --git a/assets/qrislogo.png b/assets/qrislogo.png new file mode 100644 index 0000000..80723ff Binary files /dev/null and b/assets/qrislogo.png differ diff --git a/assets/rssalogo.png b/assets/rssalogo.png new file mode 100644 index 0000000..7f0842d Binary files /dev/null and b/assets/rssalogo.png differ diff --git a/components/Home.vue b/components/Home.vue index 44219b7..da91ec5 100644 --- a/components/Home.vue +++ b/components/Home.vue @@ -83,11 +83,7 @@ @error="onVideoError" > -
+
Video thumbnail
-
+
@@ -175,7 +171,7 @@ const carouselItems = ref([ isImage: false, }, { - src: "https://scontent.fcgk22-2.fna.fbcdn.net/v/t39.30808-6/481267190_3904366386504845_1409667601717073976_n.jpg?stp=dst-jpg_s960x960_tt6&_nc_cat=110&ccb=1-7&_nc_sid=cc71e4&_nc_ohc=w6wAp5Df1lAQ7kNvwHL8Snq&_nc_oc=Adnq0LOV2vro6n7DGZu9GfUYGx3iBXzZ7LlUk7oWYi_lZ_OYDD7LVYe5zogYKxEEJdU&_nc_zt=23&_nc_ht=scontent.fcgk22-2.fna&_nc_gid=Dir3R7zaEbm2b0HPtrmGiQ&oh=00_AfaERSA1GyvNKkfajBF5yIv_JrijpizdmUqgy9528oAszQ&oe=68D12398", + src: "https://rsusaifulanwar.jatimprov.go.id/wp-content/uploads/2023/08/siam-2-scaled.jpg", alt: "Medical Services", title: "Pelayanan Terbaik", description: "Tim medis profesional siap melayani 24 jam", @@ -184,31 +180,30 @@ const carouselItems = ref([ ]); const getYouTubeEmbedUrl = (videoId) => { - const baseUrl = 'https://www.youtube.com/embed/'; + const baseUrl = "https://www.youtube.com/embed/"; const params = new URLSearchParams({ - autoplay: '1', - mute: '0', - controls: '1', - modestbranding: '1', - rel: '0', - showinfo: '0', - fs: '1', - cc_load_policy: '0', - iv_load_policy: '3', - autohide: '0' + autoplay: "1", + mute: "0", + controls: "1", + modestbranding: "1", + rel: "0", + showinfo: "0", + fs: "1", + cc_load_policy: "0", + iv_load_policy: "3", + autohide: "0", }); return `${baseUrl}${videoId}?${params.toString()}`; }; const onVideoLoad = () => { - console.log('Video iframe loaded successfully'); + console.log("Video iframe loaded successfully"); }; const onVideoError = (error) => { - console.error('Video iframe error:', error); + console.error("Video iframe error:", error); }; -// Fungsi untuk memulai carousel otomatis const startCarousel = () => { if (carouselInterval.value) { clearInterval(carouselInterval.value); @@ -216,10 +211,9 @@ const startCarousel = () => { carouselInterval.value = setInterval(() => { const nextSlide = (currentSlide.value + 1) % carouselItems.value.length; currentSlide.value = nextSlide; - }, 10000); // Ganti gambar setiap 10 detik + }, 10000); }; -// Fungsi untuk menghentikan carousel otomatis const stopCarousel = () => { if (carouselInterval.value) { clearInterval(carouselInterval.value); @@ -227,40 +221,33 @@ const stopCarousel = () => { } }; -// Fungsi untuk memutar video (menghentikan carousel) const playVideo = (index) => { currentSlide.value = index; - stopCarousel(); // Hentikan carousel saat video diputar + stopCarousel(); }; -// Tonton perubahan slide watch(currentSlide, (newSlide) => { const currentItem = carouselItems.value[newSlide]; if (currentItem && !currentItem.isImage) { - // Jika slide adalah video, hentikan carousel - console.log('Video detected, stopping carousel'); + console.log("Video detected, stopping carousel"); stopCarousel(); } else { - // Jika slide adalah gambar, mulai kembali carousel - console.log('Image detected, starting carousel'); + console.log("Image detected, starting carousel"); startCarousel(); } }); onMounted(() => { - // Mulai carousel saat komponen dimuat startCarousel(); }); onUnmounted(() => { - // Hentikan carousel saat komponen dihancurkan stopCarousel(); }); -// Fungsi untuk simulasi pembayaran debug const startDebugPayment = () => { console.log("Simulasi Pembayaran (Debug) dimulai."); - // Mengisi data dummy untuk simulasi + const dummyData = { posdevice: "GRANDPAV", invoice_number: "000000000000012000615", @@ -268,14 +255,15 @@ const startDebugPayment = () => { created_at: "2024-11-21T11:52:25.805965+07:00", display_name: "KASIH", id: "1", - status: "1", // Status awal untuk simulasi + status: "1", display_amount: "90", - qrvalue: "000201010212262710019ID.CO.BANKJATIM.WWW01189360011400001347728215ID02400134529083038ES1459015ID.OR.GPMQR.MM0215ID202431094996960309ES2049939530536054029605802D5923-RSUD SAIFUL ANWAR MLG-100000MALANG0556111622901250000000000000000000000000000012800061563040C9B", + qrvalue: + "000201010212262710019ID.CO.BANKJATIM.WWW01189360011400001347728215ID02400134529083038ES1459015ID.OR.GPMQR.MM0215ID202431094996960309ES2049939530536054029605802D5923-RSUD SAIFUL ANWAR MLG-100000MALANG0556111622901250000000000000000000000000000012800061563040C9B", ip: "10.10.150.106", display_nobill: "24072579/10000675", }; paymentStore.updatePayment({ data: [dummyData] }); - paymentStore.currentStep = 2; // Pindah ke QRISPayment + paymentStore.currentStep = 2; }; @@ -388,10 +376,13 @@ const startDebugPayment = () => { width: 100%; height: 100%; position: relative; - background: #000; + + background: white; display: flex; align-items: center; justify-content: center; + /* PASTIKAN INI ADA untuk membatasi iframe */ + overflow: hidden; } .youtube-iframe { @@ -399,8 +390,26 @@ const startDebugPayment = () => { height: 100%; border: none; border-radius: 15px; + + position: absolute; + top: 50%; + left: 50%; + + transform: translate(-50%, -50%); + + min-width: 100%; + min-height: 100%; + + aspect-ratio: 16 / 9; } +.thumbnail-img { + width: 100%; + height: 100%; + + object-fit: cover; + border-radius: 15px; +} .video-thumbnail { width: 100%; height: 100%; @@ -558,4 +567,4 @@ const startDebugPayment = () => { :deep(.v-carousel__controls--bottom) { bottom: 40px !important; } - \ No newline at end of file + diff --git a/components/PembayaranGagal.vue b/components/PembayaranGagal.vue index 9273fa7..3f01666 100644 --- a/components/PembayaranGagal.vue +++ b/components/PembayaranGagal.vue @@ -12,6 +12,19 @@

Terjadi kesalahan saat memproses
pembayaran Anda.

+
+ + mdi-home + Kembali ke Awal + +
- \ No newline at end of file + diff --git a/stores/payment.ts b/stores/payment.ts index 746ae20..642b359 100644 --- a/stores/payment.ts +++ b/stores/payment.ts @@ -1,21 +1,26 @@ // src/stores/payment.js import { defineStore } from 'pinia'; +// Variabel di luar store untuk menyimpan timer, agar persistensi di luar state Pinia +let autoResetTimer = null; + export const usePaymentStore = defineStore('payment', { state: () => ({ - currentStep: 1, + currentStep: 1, // 1: Menunggu Data, 2: Tampilkan QRIS, 3: Sukses, 4: Gagal patientInfo: { name: '', amount: '', - expiry: '', + expiry: '', // Dibiarkan kosong, waktu kedaluwarsa dihitung dari qrData.created_at }, qrData: { qrvalue: null, display_nobill: null, display_name: null, display_amount: null, - status: null, // Tambahkan status untuk tracking - ip: null, // Tambahkan IP untuk reference + status: null, // Status pembayaran: "1" (Pending), "2" (Sukses), "0" (Gagal/Expired) + ip: null, + created_at: null, // Tambahkan ini agar properti ada secara eksplisit + // ... properti lain dari API akan ditambahkan melalui spread operator }, }), @@ -23,12 +28,12 @@ export const usePaymentStore = defineStore('payment', { hasQrData: (state) => state.qrData && state.qrData.qrvalue, safeQrValue: (state) => state.qrData?.qrvalue || 'https://www.google.com', - // Getter untuk cek apakah data siap untuk polling status + // Getter untuk cek apakah data siap isReadyForStatusCheck: (state) => { return state.qrData.display_nobill && state.qrData.display_name; }, - // Getter untuk informasi debug + // Getter untuk debug debugInfo: (state) => ({ step: state.currentStep, hasIdentifiers: !!(state.qrData.display_nobill && state.qrData.display_name), @@ -46,12 +51,29 @@ export const usePaymentStore = defineStore('payment', { }, setStep(step) { - console.log(`Setting step from ${this.currentStep} to ${step}`); + console.log(`[STORE] Setting step from ${this.currentStep} to ${step}`); this.currentStep = step; }, + + /** + * @description Memulai timer untuk reset state kembali ke Step 1 (Home) setelah 20 detik + */ + startAutoReset() { + + if (autoResetTimer) { + clearTimeout(autoResetTimer); + } + console.log('🏠 [STORE] Starting auto return timer (20s) for reset.'); + + + autoResetTimer = setTimeout(() => { + console.log('🏠 [STORE] Auto return to home triggered'); + this.reset(); + }, 20000); + }, reset() { - console.log('Resetting payment store'); + console.log('--- [STORE] Resetting payment store ---'); this.currentStep = 1; this.patientInfo = { name: '', @@ -65,25 +87,26 @@ export const usePaymentStore = defineStore('payment', { display_amount: null, status: null, ip: null, + created_at: null, }; + if (autoResetTimer) { + clearTimeout(autoResetTimer); + autoResetTimer = null; + } }, updatePayment(apiResponse) { - console.log("=== UPDATE PAYMENT ==="); - console.log("API Response:", apiResponse); + console.log("=== [STORE] UPDATE PAYMENT ==="); // Validasi response if (!apiResponse?.data || !Array.isArray(apiResponse.data) || apiResponse.data.length === 0) { - console.error("Invalid API response structure"); + console.error("Invalid API response structure or empty data array"); return; } const apiData = apiResponse.data[0]; - console.log("API Data:", apiData); - - // Simpan data lama untuk comparison - const oldQrData = { ...this.qrData }; - + const oldStatus = this.qrData.status; // Simpan status lama + // Update qrData dengan semua properti dari API this.qrData = { qrvalue: apiData.qrvalue || apiData.qr_code || this.qrData.qrvalue, @@ -92,22 +115,43 @@ export const usePaymentStore = defineStore('payment', { display_amount: apiData.display_amount || apiData.nominal || this.qrData.display_amount, status: apiData.status || this.qrData.status, ip: apiData.ip || this.qrData.ip, - // Spread untuk properti lain yang mungkin ada + created_at: apiData.created_at || this.qrData.created_at, // Ambil 'created_at' + // Spread untuk properti lain yang mungkin ada (misal: transaction_id, reason) ...apiData }; // Update patientInfo this.patientInfo = { - name: apiData.display_name || this.patientInfo.name || 'Unknown', - amount: apiData.display_amount || apiData.nominal || 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, }; - // Log changes - if (oldQrData.status !== this.qrData.status) { - console.log(`Status changed: ${oldQrData.status} -> ${this.qrData.status}`); + // --- LOGIKA TRANSISI STATUS OTOMATIS (SUCCESS/FAIL) --- + const newStatus = this.qrData.status; + + // Log perubahan status (jika ada) + if (oldStatus !== newStatus) { + console.log(`[STORE] Status changed: ${oldStatus} -> ${newStatus}`); } + // Proses transisi hanya jika kita berada di Step 2 (Menunggu Pembayaran) + // DAN status yang diterima berbeda dari status sebelumnya + if (this.currentStep === 2 && oldStatus !== newStatus) { + if (newStatus === "2") { + // Status Sukses + console.log('🎉 [STORE] Status 2 (SUKSES) diterima. Pindah ke Step 3.'); + this.currentStep = 3; + this.startAutoReset(); + } else if (newStatus === "0") { + // Status Gagal + 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("===================");