This commit is contained in:
karyamanswasta
2025-08-27 05:54:02 +07:00
parent f58b40c70d
commit df203447a9
20 changed files with 2344 additions and 1701 deletions

View File

@@ -1,18 +1,13 @@
import React, { useState, useRef, useEffect } from "react";
import QrScanner from "qr-scanner"; // Import qr-scanner
import { getImageUrl } from "../helpers/itemHelper";
import {
getCafe,
saveCafeDetails,
setConfirmationStatus,
setOpenBillAvailability
} from "../helpers/cafeHelpers";
import { getCafe, saveCafeDetails } from "../helpers/cafeHelpers";
import Switch from "react-switch"; // Import the Switch component
import styles from "./PaymentOptions.module.css";
const SetPaymentQr = ({ shopId,
qrCodeUrl }) => {
const [qrPosition, setQrPosition] = useState([50, 50]);
const [qrSize, setQrSize] = useState(50);
const SetPaymentQr = ({ shopId, qrCodeUrl }) => {
const [qrPosition, setQrPosition] = useState([50, 50]); // legacy kept for API compatibility
const [qrSize, setQrSize] = useState(50); // legacy kept for API compatibility
const [qrPayment, setQrPayment] = useState();
const [qrPaymentFile, setQrPaymentFile] = useState();
const [qrCodeDetected, setQrCodeDetected] = useState(false);
@@ -26,6 +21,9 @@ const SetPaymentQr = ({ shopId,
const [isConfigQRIS, setIsConfigQRIS] = useState(false);
const [isOpenBillAvailable, setIsOpenBillAvailable] = useState(false);
const [saving, setSaving] = useState(false);
const [saveStatus, setSaveStatus] = useState(null); // 'success' | 'error'
const [copied, setCopied] = useState(false);
useEffect(() => {
const fetchCafe = async () => {
@@ -104,6 +102,8 @@ const SetPaymentQr = ({ shopId,
// Save cafe details
const handleSave = async () => {
setSaving(true);
setSaveStatus(null);
let qrPaymentFileCache;
console.log(qrPaymentFile)
if(qrPaymentFile != null)
@@ -120,240 +120,141 @@ const SetPaymentQr = ({ shopId,
try {
const response = await saveCafeDetails(cafe.cafeId, details);
setIsNeedConfirmationState(response.needsConfirmation ? 1 : 0); // Update state after saving
setIsQRISavailable(response.isQRISavailable ? 1 : 0); // Update state after saving
setIsOpenBillAvailable(response.isOpenBillAvailable ? 1 : 0); // Update state after saving
setIsNeedConfirmationState(response.needsConfirmation ? 1 : 0);
setIsQRISavailable(response.isQRISavailable ? 1 : 0);
setIsOpenBillAvailable(response.isOpenBillAvailable ? 1 : 0);
setSaveStatus('success');
console.log("Cafe details saved:", response);
} catch (error) {
console.error("Error saving cafe details:", error);
setSaveStatus('error');
} finally {
setSaving(false);
}
};
const copyQrData = async () => {
if (!qrCodeData) return;
try {
await navigator.clipboard.writeText(qrCodeData);
setCopied(true);
setTimeout(()=>setCopied(false), 1200);
} catch {}
};
return (
<div style={styles.container}>
<h3 style={styles.title}>Konfigurasi pembayaran</h3>
<div className={styles.container}>
<h3 className={styles.title}>Konfigurasi pembayaran</h3>
<div style={styles.switchContainer}>
<p style={styles.uploadMessage}>
Pembayaran QRIS.
</p>
<div className={styles.section}>
<div className={styles.sectionHeader}>
<div>
<div className={styles.sectionTitle}>Pembayaran QRIS</div>
<div className={styles.sectionDesc}>Aktifkan agar pelanggan dapat membayar via QRIS. Kasir tetap perlu verifikasi rekening.</div>
</div>
<Switch
onChange={(checked) => setIsQRISavailable(checked ? 1 : 0)}
checked={isQRISavailable === 1}
offColor="#888"
onColor="#4CAF50"
uncheckedIcon={false}
checkedIcon={false}
height={25}
width={50}
/>
</div>
{isConfigQRIS ?
<div className={styles.row}>
<button
type="button"
className={`${styles.button} ${styles.configButton}`}
onClick={() => isQRISavailable === 1 && setIsConfigQRIS(true)}
disabled={isQRISavailable !== 1}
>
Konfigurasi QRIS
</button>
</div>
{isConfigQRIS && (
<>
<div
id="qr-code-container"
ref={qrCodeContainerRef}
className={styles.imageBox}
onClick={() => qrPaymentInputRef.current.click()}
style={{
...styles.qrCodeContainer,
backgroundImage: `url(${qrPayment})`,
backgroundPosition: "center",
backgroundRepeat: "no-repeat",
backgroundSize: "contain",
}}
style={{ backgroundImage: `url(${qrPayment})` }}
>
<input
type="file"
accept="image/*"
ref={qrPaymentInputRef}
style={{ display: "none" }}
onChange={handleFileChange}
/>
<input type="file" accept="image/*" ref={qrPaymentInputRef} style={{ display: 'none' }} onChange={handleFileChange} />
</div>
<div style={styles.uploadMessage}>
<p>Klik untuk ganti background</p>
</div>
<div style={styles.resultMessage}>
{qrCodeDetected && qrPayment !== 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSPsNr0TPq8dHT3nBwDQ6OHQQTrqzVFoeBOmuWfgyErrLbJi6f6CnnYhpNHEvkJ_2X-kyI&usqp=CAU' ? <p>QR terdeteksi</p> : <p>Tidak ada qr terdeteksi</p>}
{qrCodeDetected && qrPayment !== 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSPsNr0TPq8dHT3nBwDQ6OHQQTrqzVFoeBOmuWfgyErrLbJi6f6CnnYhpNHEvkJ_2X-kyI&usqp=CAU' ? <div
onClick={() => qrPaymentInputRef.current.click()} style={styles.uploadButton}>Ganti</div> : <div
onClick={() => qrPaymentInputRef.current.click()} style={styles.uploadButton}>Unggah</div>}
</div>
<div onClick={() => setIsConfigQRIS(false)}
style={{
...styles.qrisConfigButton,
width: '100%',
marginLeft: "0",
}}
>Terapkan</div>
</>
:
<>
<p style={styles.description}>
Aktifkan fitur agar pelanggan dapat menggunakan opsi pembayaran QRIS, namun kasir anda perlu memeriksa rekening untuk memastikan pembayaran.
</p>
<div style={{ display: 'flex' }}>
<Switch
onChange={(checked) => setIsQRISavailable(checked ? 1 : 0)}
checked={isQRISavailable === 1} // Convert to boolean
offColor="#888"
onColor="#4CAF50"
uncheckedIcon={false}
checkedIcon={false}
height={25}
width={50}
/>
<div
onClick={() => setIsConfigQRIS(true)}
style={{
...styles.qrisConfigButton,
backgroundColor: isQRISavailable == 1 ? styles.qrisConfigButton.backgroundColor : 'gray',
}}
>
Konfigurasi QRIS
<div className={styles.smallNote}>Klik area untuk unggah/ganti gambar QR</div>
<div className={styles.detectRow}>
<div className={`${styles.tag} ${qrCodeDetected ? styles.tagOk : styles.tagBad}`}>
{qrCodeDetected && qrPayment !== 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSPsNr0TPq8dHT3nBwDQ6OHQQTrqzVFoeBOmuWfgyErrLbJi6f6CnnYhpNHEvkJ_2X-kyI&usqp=CAU' ? 'QR terdeteksi' : 'Tidak ada QR terdeteksi'}
</div>
<button className={styles.button} onClick={() => qrPaymentInputRef.current.click()}>{qrPayment ? 'Ganti' : 'Unggah'}</button>
</div>
{qrCodeDetected && (
<div className={styles.copyRow}>
<input className={styles.linkField} readOnly value={qrCodeData || ''} />
<button className={styles.button} onClick={copyQrData}>{copied ? 'Disalin' : 'Salin'}</button>
</div>
)}
<div className={styles.actionsRight}>
<button className={`${styles.button} ${styles.primary}`} onClick={() => setIsConfigQRIS(false)}>Terapkan</button>
</div>
</>
}
</div>
<div style={styles.switchContainer}>
<p style={styles.uploadMessage}>
Open bill
</p>
<p style={styles.description}>
Aktifkan fitur agar pelanggan dapat menambahkan pesanan selama sesi berlangsung tanpa perlu melakukan transaksi baru dan hanya membayar di akhir.
</p>
<Switch
onChange={(checked) => setIsOpenBillAvailable(checked ? 1 : 0)}
checked={isOpenBillAvailable === 1} // Convert to boolean
offColor="#888"
onColor="#4CAF50"
uncheckedIcon={false}
checkedIcon={false}
height={25}
width={50}
/>
)}
</div>
<div style={styles.switchContainer}>
<p style={styles.uploadMessage}>
Pengecekan ganda
</p>
<p style={styles.description}>
Nyalakan agar kasir memeriksa kembali ketersediaan produk sebelum pelanggan membayar.
</p>
<Switch
onChange={(checked) => setIsNeedConfirmationState(checked ? 1 : 0)}
checked={isNeedConfirmationState === 1} // Convert to boolean
offColor="#888"
onColor="#4CAF50"
uncheckedIcon={false}
checkedIcon={false}
height={25}
width={50}
/>
<div className={styles.section}>
<div className={styles.sectionHeader}>
<div>
<div className={styles.sectionTitle}>Open bill</div>
<div className={styles.sectionDesc}>Izinkan pelanggan menambah pesanan dalam satu sesi dan bayar di akhir.</div>
</div>
<Switch
onChange={(checked) => setIsOpenBillAvailable(checked ? 1 : 0)}
checked={isOpenBillAvailable === 1}
offColor="#888"
onColor="#4CAF50"
uncheckedIcon={false}
checkedIcon={false}
height={25}
width={50}
/>
</div>
</div>
<div style={styles.buttonContainer}>
<button onClick={handleSave} style={styles.saveButton}>
Simpan
<div className={styles.section}>
<div className={styles.sectionHeader}>
<div>
<div className={styles.sectionTitle}>Pengecekan ganda</div>
<div className={styles.sectionDesc}>Kasir memeriksa kembali ketersediaan item sebelum pembayaran.</div>
</div>
<Switch
onChange={(checked) => setIsNeedConfirmationState(checked ? 1 : 0)}
checked={isNeedConfirmationState === 1}
offColor="#888"
onColor="#4CAF50"
uncheckedIcon={false}
checkedIcon={false}
height={25}
width={50}
/>
</div>
</div>
<div className={styles.footer}>
<div>
{saveStatus === 'success' && <span className={`${styles.banner} ${styles.bannerSuccess}`}>Simpan berhasil</span>}
{saveStatus === 'error' && <span className={`${styles.banner} ${styles.bannerError}`}>Gagal menyimpan</span>}
</div>
<button className={`${styles.button} ${styles.primary}`} onClick={handleSave} disabled={saving}>
{saving ? 'Menyimpan…' : 'Simpan'}
</button>
</div>
</div>
);
};
// Styles
const styles = {
container: {
position: 'relative',
overflowY: 'auto',
overflowX: 'hidden',
maxHeight: '80vh',
width: '100%',
backgroundColor: "white",
padding: "20px",
borderRadius: "8px",
boxShadow: "0 2px 10px rgba(0, 0, 0, 0.1)",
textAlign: "center", // Center text and children
},
title: {
marginBottom: "20px",
fontWeight: "bold",
},
qrCodeContainer: {
backgroundColor: '#999999',
borderRadius: '20px',
position: "relative",
width: "100%",
height: "200px",
backgroundSize: "contain",
overflow: "hidden",
margin: "0 auto", // Center the QR code container
marginTop: '10px'
},
uploadMessage: {
fontWeight: 600,
textAlign: "left",
},
qrisConfigButton: {
borderRadius: '15px',
backgroundColor: '#28a745',
width: '144px',
textAlign: 'center',
color: 'white',
lineHeight: '24px',
marginLeft: '14px',
},
uploadButton: {
paddingRight: '10px',
backgroundColor: '#28a745',
borderRadius: '30px',
color: 'white',
fontWeight: 700,
height: '36px',
lineHeight: '36px',
paddingLeft: '10px',
paddingHeight: '10px',
},
resultMessage: {
marginTop: "-24px",
textAlign: "left",
display: 'flex',
justifyContent: 'space-between'
},
buttonContainer: {
marginTop: "20px",
textAlign: "left",
},
saveButton: {
padding: "10px 20px",
fontSize: "16px",
backgroundColor: "#28a745",
color: "#fff",
border: "none",
borderRadius: "30px",
cursor: "pointer",
transition: "background-color 0.3s",
},
switchContainer: {
textAlign: "left",
},
description: {
margin: "10px 0",
fontSize: "14px",
color: "#666",
},
sliderContainer: {
marginBottom: "20px",
},
label: {
display: "block",
marginBottom: "10px",
},
sliderWrapper: {
display: "flex",
alignItems: "center",
},
input: {
flex: "1",
margin: "0 10px",
},
};
export default SetPaymentQr;