From edec5bb339ce99994abafe039ddd24e85ea08d13 Mon Sep 17 00:00:00 2001 From: bagus-arie05 Date: Fri, 12 Sep 2025 09:54:00 +0700 Subject: [PATCH] update async dan interface --- components/Home.vue | 555 ++++++++++++++++++++++++++ components/QRISPayment.vue | 119 ++++++ components/Success.vue | 38 ++ composables/useWebSocket.ts | 43 ++ nuxt.config.ts | 1 + package-lock.json | 165 +++++++- package.json | 1 + pages/Home.vue | 775 ------------------------------------ pages/figma.vue | 541 ------------------------- pages/index.vue | 112 ++++++ stores/payment.ts | 53 ++- stores/payment1.ts | 37 ++ 12 files changed, 1086 insertions(+), 1354 deletions(-) create mode 100644 components/Home.vue create mode 100644 components/QRISPayment.vue create mode 100644 components/Success.vue create mode 100644 composables/useWebSocket.ts delete mode 100644 pages/Home.vue delete mode 100644 pages/figma.vue create mode 100644 pages/index.vue create mode 100644 stores/payment1.ts diff --git a/components/Home.vue b/components/Home.vue new file mode 100644 index 0000000..e4079d6 --- /dev/null +++ b/components/Home.vue @@ -0,0 +1,555 @@ + + + + + + \ No newline at end of file diff --git a/components/QRISPayment.vue b/components/QRISPayment.vue new file mode 100644 index 0000000..6e9087f --- /dev/null +++ b/components/QRISPayment.vue @@ -0,0 +1,119 @@ + + + + + \ No newline at end of file diff --git a/components/Success.vue b/components/Success.vue new file mode 100644 index 0000000..3e9f255 --- /dev/null +++ b/components/Success.vue @@ -0,0 +1,38 @@ + + + + + + \ No newline at end of file diff --git a/composables/useWebSocket.ts b/composables/useWebSocket.ts new file mode 100644 index 0000000..d18430e --- /dev/null +++ b/composables/useWebSocket.ts @@ -0,0 +1,43 @@ +import { io } from 'socket.io-client'; +import { usePaymentStore } from '~/stores/payment1'; + +// Fungsi untuk mendapatkan IP Address lokal (ini butuh bantuan backend/API eksternal) +async function getLocalIpAddress() { + // Anda bisa menggunakan API eksternal atau endpoint di backend Anda sendiri. + // Contoh menggunakan API eksternal: + // const response = await fetch('https://api.ipify.org?format=json'); + // const data = await response.json(); + // return data.ip; + + // ATAU, jika IP address diatur secara statis pada tablet: + return '192.168.1.101'; // Ganti dengan IP Address loket yang sesungguhnya +} + +export async function setupSocket() { + const paymentStore = usePaymentStore(); + const socket = io('https://your-backend-api.com'); // Ganti dengan URL backend Anda + + const localIp = await getLocalIpAddress(); + + socket.on('connect', () => { + console.log('Connected to backend WebSocket'); + + // Mengirim IP Address tablet ke backend untuk identifikasi loket. + socket.emit('register-kiosk', { ipAddress: localIp }); + }); + + socket.on('payment-data-ready', (data) => { + console.log('Payment data received:', data); + // Panggil action Pinia untuk memperbarui state dan pindah step + paymentStore.updatePayment(data); + }); + + socket.on('disconnect', () => { + console.log('Disconnected from backend'); + }); + + // Tambahkan error handling + socket.on('error', (error) => { + console.error('Socket error:', error); + }); +} \ No newline at end of file diff --git a/nuxt.config.ts b/nuxt.config.ts index a57d680..742577f 100644 --- a/nuxt.config.ts +++ b/nuxt.config.ts @@ -11,6 +11,7 @@ export default defineNuxtConfig({ '@nuxt/scripts', '@nuxt/test-utils', '@nuxt/ui', + 'nuxt-qrcode', '@pinia/nuxt', (_options, nuxt) => { nuxt.hooks.hook('vite:extendConfig', (config) => { diff --git a/package-lock.json b/package-lock.json index 1b577d6..92be866 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,9 +21,11 @@ "pinia": "^3.0.3", "typescript": "^5.9.2", "vue": "^3.5.20", - "vue-router": "^4.5.1" + "vue-router": "^4.5.1", + "vuetify": "^3.4.0" }, "devDependencies": { + "nuxt-qrcode": "^0.4.8", "sass-embedded": "^1.92.1", "vite-plugin-vuetify": "^2.1.2", "vuetify": "^3.9.7" @@ -4808,6 +4810,20 @@ "@types/ms": "*" } }, + "node_modules/@types/dom-webcodecs": { + "version": "0.1.16", + "resolved": "https://registry.npmjs.org/@types/dom-webcodecs/-/dom-webcodecs-0.1.16.tgz", + "integrity": "sha512-gRNWaC3YW5EzhPRjVYy7BnxCbtLGqsgu+uTkmV/IxOF1bllFD+FAJ1KBdsDFsuJB+F+CE+nWmMlWt8vaZ3yYXA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/emscripten": { + "version": "1.41.1", + "resolved": "https://registry.npmjs.org/@types/emscripten/-/emscripten-1.41.1.tgz", + "integrity": "sha512-vW2aEgBUU1c2CB+qVMislA98amRVPszdALjqNCuUIJaEFZsNaFaM4g5IMXIs+6oHbmmb7q6zeXYubhtObJ9ZLg==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/estree": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", @@ -6188,6 +6204,16 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "license": "MIT" }, + "node_modules/barcode-detector": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/barcode-detector/-/barcode-detector-3.0.5.tgz", + "integrity": "sha512-SWeGhJ8SEW0T3Anbr2wEugUXW2bSCld3PauZh+LjTgN1lSInnIrI+RnG53NkzS4pl3cfPCl1AZ10Rq+hSkXBSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "zxing-wasm": "2.2.0" + } + }, "node_modules/bare-events": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.6.1.tgz", @@ -12455,6 +12481,55 @@ "node": ">=18.12.0" } }, + "node_modules/nuxt-qrcode": { + "version": "0.4.8", + "resolved": "https://registry.npmjs.org/nuxt-qrcode/-/nuxt-qrcode-0.4.8.tgz", + "integrity": "sha512-m489cF5NtXbZ2P3s2euuKEQ2iClmNwFtXQU8B9H5RqdSpMrM+MRci9eHp+OE8IlTCXQBb4TEUZXApzz8xk91Tw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nuxt/kit": "^4.1.1", + "@vueuse/core": "^13.9.0", + "barcode-detector": "^3.0.5", + "defu": "^6.1.4", + "uqr": "^0.1.2", + "vue-qrcode-reader": "^5.7.3" + } + }, + "node_modules/nuxt-qrcode/node_modules/@nuxt/kit": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@nuxt/kit/-/kit-4.1.1.tgz", + "integrity": "sha512-2MGfOXtbcxdkbUNZDjyEv4xmokicZhTrQBMrmNJQztrePfpKOVBe8AiGf/BfbHelXMKio5PgktiRoiEIyIsX4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "c12": "^3.2.0", + "consola": "^3.4.2", + "defu": "^6.1.4", + "destr": "^2.0.5", + "errx": "^0.1.0", + "exsolve": "^1.0.7", + "ignore": "^7.0.5", + "jiti": "^2.5.1", + "klona": "^2.0.6", + "mlly": "^1.8.0", + "ohash": "^2.0.11", + "pathe": "^2.0.3", + "pkg-types": "^2.3.0", + "rc9": "^2.1.2", + "scule": "^1.3.0", + "semver": "^7.7.2", + "std-env": "^3.9.0", + "tinyglobby": "^0.2.14", + "ufo": "^1.6.1", + "unctx": "^2.4.1", + "unimport": "^5.2.0", + "untyped": "^2.0.0" + }, + "engines": { + "node": ">=18.12.0" + } + }, "node_modules/nypm": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/nypm/-/nypm-0.6.1.tgz", @@ -14494,7 +14569,6 @@ "!riscv64", "!x64" ], - "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -14508,7 +14582,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -14525,7 +14598,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -14542,7 +14614,6 @@ "cpu": [ "riscv64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -14559,7 +14630,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -14576,7 +14646,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -14593,7 +14662,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -14610,7 +14678,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -14627,7 +14694,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -14644,7 +14710,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -14661,7 +14726,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -14678,7 +14742,6 @@ "cpu": [ "riscv64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -14695,7 +14758,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -14712,7 +14774,6 @@ "cpu": [ "riscv64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -14729,7 +14790,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -14743,7 +14803,6 @@ "version": "1.92.1", "resolved": "https://registry.npmjs.org/sass-embedded-unknown-all/-/sass-embedded-unknown-all-1.92.1.tgz", "integrity": "sha512-AT9oXvtNY4N+Nd0wvoWqq9A5HjdH/X3aUH4boQUtXyaJ/9DUwnQmBpP5Gtn028ZS8exOGBdobmmWAuigv0k/OA==", - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -14763,7 +14822,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -14780,7 +14838,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -14832,6 +14889,13 @@ "integrity": "sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==", "license": "MIT" }, + "node_modules/sdp": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/sdp/-/sdp-3.2.1.tgz", + "integrity": "sha512-lwsAIzOPlH8/7IIjjz3K0zYBk7aBVVcvjMwt3M4fLxpjMYyy7i3I97SLHebgn4YBjirkzfp3RvRDWSKsh/+WFw==", + "dev": true, + "license": "MIT" + }, "node_modules/semver": { "version": "7.7.2", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", @@ -17215,6 +17279,41 @@ "eslint": "^8.57.0 || ^9.0.0" } }, + "node_modules/vue-qrcode-reader": { + "version": "5.7.3", + "resolved": "https://registry.npmjs.org/vue-qrcode-reader/-/vue-qrcode-reader-5.7.3.tgz", + "integrity": "sha512-iSGko42FsEvdHyizBMBs/X+HMO9Z5ONDxjW+mQdoraOR5emRNedmjC5SEJdYzGz8ZP5ME3lwB4iHy3S7MOt5Qw==", + "dev": true, + "license": "MIT", + "dependencies": { + "barcode-detector": "2.2.2", + "webrtc-adapter": "8.2.3" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/vue-qrcode-reader/node_modules/barcode-detector": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/barcode-detector/-/barcode-detector-2.2.2.tgz", + "integrity": "sha512-JcSekql+EV93evfzF9zBr+Y6aRfkR+QFvgyzbwQ0dbymZXoAI9+WgT7H1E429f+3RKNncHz2CW98VQtaaKpmfQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/dom-webcodecs": "^0.1.11", + "zxing-wasm": "1.1.3" + } + }, + "node_modules/vue-qrcode-reader/node_modules/zxing-wasm": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/zxing-wasm/-/zxing-wasm-1.1.3.tgz", + "integrity": "sha512-MYm9k/5YVs4ZOTIFwlRjfFKD0crhefgbnt1+6TEpmKUDFp3E2uwqGSKwQOd2hOIsta/7Usq4hnpNRYTLoljnfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/emscripten": "^1.39.10" + } + }, "node_modules/vue-router": { "version": "4.5.1", "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.5.1.tgz", @@ -17283,6 +17382,20 @@ "integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==", "license": "MIT" }, + "node_modules/webrtc-adapter": { + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/webrtc-adapter/-/webrtc-adapter-8.2.3.tgz", + "integrity": "sha512-gnmRz++suzmvxtp3ehQts6s2JtAGPuDPjA1F3a9ckNpG1kYdYuHWYpazoAnL9FS5/B21tKlhkorbdCXat0+4xQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "sdp": "^3.2.0" + }, + "engines": { + "node": ">=6.0.0", + "npm": ">=3.10.0" + } + }, "node_modules/whatwg-url": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", @@ -17672,6 +17785,20 @@ "type": "github", "url": "https://github.com/sponsors/wooorm" } + }, + "node_modules/zxing-wasm": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/zxing-wasm/-/zxing-wasm-2.2.0.tgz", + "integrity": "sha512-RyHxVaAHsLSDzmwcAG05IF8sVOE5Ta2JT1dRDh0mzVZOIiDXZstsjkqvKHasN1n4lvFSbX7ngkHDufnt/XI07Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/emscripten": "^1.40.1", + "type-fest": "^4.41.0" + }, + "peerDependencies": { + "@types/emscripten": ">=1.39.6" + } } } } diff --git a/package.json b/package.json index c7d9d0e..89b50b1 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "vuetify": "^3.4.0" }, "devDependencies": { + "nuxt-qrcode": "^0.4.8", "sass-embedded": "^1.92.1", "vite-plugin-vuetify": "^2.1.2", "vuetify": "^3.9.7" diff --git a/pages/Home.vue b/pages/Home.vue deleted file mode 100644 index 6f95b86..0000000 --- a/pages/Home.vue +++ /dev/null @@ -1,775 +0,0 @@ - - - - - diff --git a/pages/figma.vue b/pages/figma.vue deleted file mode 100644 index 136daeb..0000000 --- a/pages/figma.vue +++ /dev/null @@ -1,541 +0,0 @@ - - - - - \ No newline at end of file diff --git a/pages/index.vue b/pages/index.vue new file mode 100644 index 0000000..9c4f335 --- /dev/null +++ b/pages/index.vue @@ -0,0 +1,112 @@ + + + + + \ No newline at end of file diff --git a/stores/payment.ts b/stores/payment.ts index f12c6ab..dc01e47 100644 --- a/stores/payment.ts +++ b/stores/payment.ts @@ -1,31 +1,46 @@ -import { defineStore } from 'pinia' +// src/stores/payment.js +import { defineStore } from 'pinia'; export const usePaymentStore = defineStore('payment', { state: () => ({ - currentStep: 1, // 1: info, 2: qr, 3: success + currentStep: 1, patientInfo: { - name: 'ALDY GUSTINARA', - amount: 'Rp 1.520.000', - expiry: '2025-08-24 12:30:00' + name: '', + amount: '', + expiry: '', // Tidak ada di API, bisa dihapus atau diisi null }, - qrCode: 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAwIiBoZWlnaHQ9IjIwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cmVjdCB3aWR0aD0iMjAwIiBoZWlnaHQ9IjIwMCIgZmlsbD0iIzAwMCIvPjxyZWN0IHg9IjEwIiB5PSIxMCIgd2lkdGg9IjE4MCIgaGVpZ2h0PSIxODAiIGZpbGw9IiNmZmYiLz48L3N2Zz4=' + qrData: null, // Properti baru untuk menyimpan data QRIS dari API }), - actions: { nextStep() { - if (this.currentStep < 3) { - this.currentStep++ - } + this.currentStep++; }, - prevStep() { - if (this.currentStep > 1) { - this.currentStep-- - } + this.currentStep--; }, - reset() { - this.currentStep = 1 - } - } -}) \ No newline at end of file + this.currentStep = 1; + this.patientInfo = { + name: '', + amount: '', + expiry: '', + }; + this.qrData = null; // Reset data QR + }, + // Action baru untuk menerima dan memproses data dari backend + updatePayment(apiResponse) { + // Ambil objek data pertama dari array 'data' + const apiData = apiResponse.data[0]; + + // Perbarui state dengan data yang sesuai + this.qrData = apiData; + this.patientInfo = { + name: apiData.display_name, + amount: apiData.display_amount, + }; + + // Ganti step secara otomatis + this.currentStep = 2; + }, + }, +}); \ No newline at end of file diff --git a/stores/payment1.ts b/stores/payment1.ts new file mode 100644 index 0000000..d1fc2b1 --- /dev/null +++ b/stores/payment1.ts @@ -0,0 +1,37 @@ +// src/stores/payment.js +import { defineStore } from 'pinia'; + +export const usePaymentStore = defineStore('payment', { + state: () => ({ + currentStep: 1, + patientInfo: { + name: '', + amount: '', + expiry: '', + }, + paymentData: null, // Tambahkan state ini untuk menyimpan data dari backend + }), + actions: { + nextStep() { + this.currentStep++; + }, + prevStep() { + this.currentStep--; + }, + reset() { + this.currentStep = 1; + this.patientInfo = {}; + this.paymentData = null; // Reset data pembayaran + }, + // Tambahkan action baru untuk menerima data dari WebSocket + updatePayment(data: { patientName: any; amount: any; expiryDate: any; } | null) { + this.paymentData = data; + this.patientInfo = { + name: data.patientName, + amount: data.amount, + expiry: data.expiryDate, + }; + this.currentStep = 2; // Pindah ke step 2 secara otomatis + }, + }, +}); \ No newline at end of file