This commit is contained in:
everythingonblack
2025-05-13 09:42:04 +07:00
parent 5ddf09e3d9
commit bf7ea19d80
10 changed files with 238 additions and 137 deletions

View File

@@ -27,6 +27,7 @@ import { getTableByCode } from "./helpers/tableHelper.js";
import { import {
getTransactionsFromCafe, getTransactionsFromCafe,
checkIsMyTransaction
} from "./helpers/transactionHelpers"; } from "./helpers/transactionHelpers";
import { import {
getConnectedGuestSides, getConnectedGuestSides,
@@ -82,6 +83,7 @@ function App() {
'transaction_failed', 'transaction_failed',
]; ];
const calculateTotalsFromLocalStorage = () => { const calculateTotalsFromLocalStorage = () => {
const { totalCount, totalPrice } = calculateTotals(shopId); const { totalCount, totalPrice } = calculateTotals(shopId);
setTotalItemsCount(totalCount); setTotalItemsCount(totalCount);
@@ -93,13 +95,17 @@ function App() {
console.log(lastTransaction); console.log(lastTransaction);
if (lastTransaction != null) { if (lastTransaction != null) {
console.log(lastTransaction)
setLastTransaction(lastTransaction); setLastTransaction(lastTransaction);
} }
}; };
useEffect(() => { useEffect(() => {
const init = async () => {
await checkLastTransaction();
};
calculateTotalsFromLocalStorage(); init(); // call the async function
const handleStorageChange = () => { const handleStorageChange = () => {
calculateTotalsFromLocalStorage(); calculateTotalsFromLocalStorage();
@@ -112,6 +118,33 @@ function App() {
}; };
}, [shopId]); }, [shopId]);
const checkLastTransaction = async () => {
const { totalCount, totalPrice } = calculateTotals(shopId);
setTotalItemsCount(totalCount);
setTotalPrice(totalPrice);
const lastTransactionStr = localStorage.getItem("lastTransaction");
if (!lastTransactionStr) return;
const lastTransaction = JSON.parse(lastTransactionStr);
console.log(lastTransaction);
if (!lastTransaction || !lastTransaction.transactionId) {
localStorage.removeItem("lastTransaction");
return;
}
const myLastTransaction = await checkIsMyTransaction(lastTransaction.transactionId);
console.log(myLastTransaction)
if (myLastTransaction.isMyTransaction) {
setLastTransaction(lastTransaction);
} else {
localStorage.removeItem("lastTransaction");
}
};
const handleSetParam = async ({ shopIdentifier, tableCode }) => { const handleSetParam = async ({ shopIdentifier, tableCode }) => {
setShopIdentifier(shopIdentifier); setShopIdentifier(shopIdentifier);
@@ -728,6 +761,7 @@ setDepth(depthh);
shopId={shopId} shopId={shopId}
sendParam={handleSetParam} sendParam={handleSetParam}
deviceType={deviceType} deviceType={deviceType}
paymentUrl={shop.qrPayment}
/> />
{/* <Footer {/* <Footer
shopId={shopIdentifier} shopId={shopIdentifier}

View File

@@ -3,6 +3,12 @@
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
border: none;
margin: 0 auto;
cursor: pointer;
display: block;
text-align: center;
} }
.button { .button {

View File

@@ -100,7 +100,7 @@ const Modal = ({ user, shop, isOpen, onClose, modalContent, deviceType, setModal
{modalContent === "transaction_pending" && <Transaction_pending deviceType={deviceType}/>} {modalContent === "transaction_pending" && <Transaction_pending deviceType={deviceType}/>}
{modalContent === "transaction_item" && <Transaction_item />} {modalContent === "transaction_item" && <Transaction_item />}
{modalContent === "transaction_confirmed" && ( {modalContent === "transaction_confirmed" && (
<Transaction_confirmed deviceType={deviceType} paymentUrl={shop.qrPayment} /> <Transaction_confirmed deviceType={deviceType} paymentUrl={shop.qrPayment} setModal={setModal}/>
)} )}
{modalContent === "payment_claimed" && ( {modalContent === "payment_claimed" && (
<Payment_claimed paymentUrl={shop.qrPayment} /> <Payment_claimed paymentUrl={shop.qrPayment} />

View File

@@ -151,7 +151,21 @@ export async function getTransaction(transactionId) {
console.error("Error:", error); console.error("Error:", error);
} }
} }
export async function checkIsMyTransaction(transactionId){
const token = getLocalStorage("auth");
const response = await fetch(
`${API_BASE_URL}/transaction/check-is-my-transaction/${transactionId}`,
{
method: "GET",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${token}`,
},
}
);
const res = await response.json();
return res;
}
export async function getMyTransactions() { export async function getMyTransactions() {
try { try {
const token = getLocalStorage("auth"); const token = getLocalStorage("auth");

View File

@@ -270,6 +270,7 @@ export default function Invoice({ shopId, setModal, table, sendParam, deviceType
textareaRef.current.value, textareaRef.current.value,
socketId socketId
); );
localStorage.removeItem('lastTransaction')
} }
else else
@@ -459,7 +460,7 @@ export default function Invoice({ shopId, setModal, table, sendParam, deviceType
{transactionData.payment_type != 'paylater' ? {transactionData.payment_type != 'paylater' ?
<> <>
<div onClick={() => setModal('transaction_item', { transactionId: transactionData.transactionId })} className={styles.AddedLastTransaction}> <div onClick={() => setModal('transaction_item', { transactionId: transactionData.transactionId })} className={styles.AddedLastTransaction}>
Pesanan akan ditambahkan ke transaksi sebelumnya Pembayaran akan ditambahkan ke transaksi sebelumnya
</div> </div>
<div className={styles.CancelAddedLastTransaction} onClick={() => { window.location.reload(); localStorage.removeItem('lastTransaction') }}> <div className={styles.CancelAddedLastTransaction} onClick={() => { window.location.reload(); localStorage.removeItem('lastTransaction') }}>
<svg <svg

View File

@@ -146,9 +146,8 @@
.RoundedRectangle { .RoundedRectangle {
border-radius: 20px; border-radius: 20px;
padding-top: 5px; padding-top: 5px;
margin: 26px; margin: 12px;
background-color: #f9f9f9; background-color: #f9f9f9;
margin-bottom: -20px;
} }
.EmailContainer { .EmailContainer {

View File

@@ -19,6 +19,7 @@ export default function Transactions({
sendParam, sendParam,
deviceType, deviceType,
paymentUrl, paymentUrl,
setModal
}) { }) {
const { shopId, tableId } = useParams(); const { shopId, tableId } = useParams();
if (sendParam) sendParam({ shopId, tableId }); if (sendParam) sendParam({ shopId, tableId });
@@ -165,7 +166,7 @@ export default function Transactions({
<ColorRing className={styles['receipt-logo']} /> <ColorRing className={styles['receipt-logo']} />
} }
<div className={styles['receipt-info']}> <div className={styles['receipt-info']}>
{transaction.payment_type == 'cashless' || transaction.payment_type == 'paylater/cashless' ? <h3>silahkan bayar dengan QRIS</h3> : transaction.payment_type == 'cash' || transaction.payment_type == 'paylater/cash' ? <h3>silahkan bayar ke kasir</h3> : transaction.DetailedTransactions.some(transaction => transaction.additionalNumber > 0) ? <h3>Item sukses ditambahkan</h3> : <h3>open bill disetujui</h3>} {transaction.payment_type == 'cashless' || transaction.payment_type == 'paylater/cashless' ? <h3>Silahkan bayar dengan QRIS</h3> : transaction.payment_type == 'cash' || transaction.payment_type == 'paylater/cash' ? <h3>silahkan bayar ke kasir</h3> : transaction.DetailedTransactions.some(transaction => transaction.additionalNumber > 0) ? <h3>Item sukses ditambahkan</h3> : <h3>open bill disetujui</h3>}
<p>Transaction ID: {transaction.transactionId}</p> <p>Transaction ID: {transaction.transactionId}</p>
<p>Payment Type: {transaction.payment_type}</p> <p>Payment Type: {transaction.payment_type}</p>
</div> </div>
@@ -195,7 +196,15 @@ export default function Transactions({
<div <div
onClick={() => { onClick={() => {
localStorage.setItem('lastTransaction', JSON.stringify(transaction)); localStorage.setItem('lastTransaction', JSON.stringify(transaction));
}} className={styles["addNewItem"]}>Tambah pesanan</div> setModal("message", { captMessage: 'Silahkan tambahkan pesanan', descMessage: 'Pembayaran akan ditambahkan ke transaksi sebelumnya.' }, null, null);
// Dispatch the custom event
window.dispatchEvent(new Event("localStorageUpdated"));
}}
className={styles["addNewItem"]}
>
Tambah pesanan
</div>
} }
<h2 className={styles["Transactions-detail"]}> <h2 className={styles["Transactions-detail"]}>

View File

@@ -135,7 +135,7 @@ export default function Transactions({ propsShopId, sendParam, deviceType, handl
<div className={styles['receipt-header']}> <div className={styles['receipt-header']}>
<ColorRing className={styles['receipt-logo']} /> <ColorRing className={styles['receipt-logo']} />
<div className={styles['receipt-info']}> <div className={styles['receipt-info']}>
<h3>memeriksa ketersediaan</h3> <h3>Memeriksa Ketersediaan</h3>
<p>ID Transaksi: {transaction.transactionId}</p> <p>ID Transaksi: {transaction.transactionId}</p>
<p>Pembayaran: {transaction.payment_type}</p> <p>Pembayaran: {transaction.payment_type}</p>
<p>{transaction.serving_type === "pickup" <p>{transaction.serving_type === "pickup"

View File

@@ -9,6 +9,7 @@ import {
getTransactionsFromCafe, getTransactionsFromCafe,
} from "../helpers/transactionHelpers"; } from "../helpers/transactionHelpers";
import { getTables } from "../helpers/tableHelper"; import { getTables } from "../helpers/tableHelper";
import ButtonWithReplica from "../components/ButtonWithReplica";
import TableCanvas from "../components/TableCanvas"; import TableCanvas from "../components/TableCanvas";
import dayjs from 'dayjs'; import dayjs from 'dayjs';
@@ -16,32 +17,33 @@ import utc from 'dayjs/plugin/utc';
import timezone from 'dayjs/plugin/timezone'; import timezone from 'dayjs/plugin/timezone';
export default function Transactions({ shop, shopId, propsShopId, sendParam, deviceType }) { export default function Transactions({ shop, shopId, propsShopId, sendParam, deviceType, paymentUrl }) {
const { shopIdentifier, tableId } = useParams(); const { shopIdentifier, tableId } = useParams();
if (sendParam) sendParam({ shopIdentifier, tableId }); if (sendParam) sendParam({ shopIdentifier, tableId });
dayjs.extend(utc); dayjs.extend(utc);
dayjs.extend(timezone); dayjs.extend(timezone);
const [tables, setTables] = useState([]);
const [selectedTable, setSelectedTable] = useState(null);
const [transactions, setTransactions] = useState([]); const [transactions, setTransactions] = useState([]);
const [myTransactions, setMyTransactions] = useState([]);
const [isPaymentLoading, setIsPaymentLoading] = useState(false); const [isPaymentLoading, setIsPaymentLoading] = useState(false);
const [isPaymentOpen, setIsPaymentOpen] = useState(false);
useEffect(() => { useEffect(() => {
const fetchTransactions = async () => { const fetchTransactions = async () => {
if (deviceType == 'clerk') {
try { try {
let response; let response;
response = await getTransactionsFromCafe(shopId || propsShopId, 5, false); response = await getTransactionsFromCafe(shopId || propsShopId, 5, false);
console.log(response) console.log(response)
if(response) { if (response) {
setTransactions(response); setTransactions(response);
return; return;
} }
} catch (error) { } catch (error) {
console.error("Error fetching transactions:", error); console.error("Error fetching transactions:", error);
} }
}
else {
try { try {
let response; let response;
response = await getMyTransactions(shopId || propsShopId, 5); response = await getMyTransactions(shopId || propsShopId, 5);
@@ -71,23 +73,11 @@ export default function Transactions({ shop, shopId, propsShopId, sendParam, dev
} catch (error) { } catch (error) {
console.error("Error fetching transactions:", error); console.error("Error fetching transactions:", error);
} }
};
fetchTransactions();
}, [shopId || propsShopId]);
useEffect(() => {
const fetchData = async () => {
try {
const fetchedTables = await getTables(shopId || propsShopId);
setTables(fetchedTables);
} catch (error) {
console.error("Error fetching tables:", error);
} }
}; };
fetchData(); fetchTransactions();
}, [shopId || propsShopId]); }, [deviceType]);
const calculateTotalPrice = (detailedTransactions) => { const calculateTotalPrice = (detailedTransactions) => {
return detailedTransactions.reduce((total, dt) => { return detailedTransactions.reduce((total, dt) => {
@@ -95,11 +85,11 @@ export default function Transactions({ shop, shopId, propsShopId, sendParam, dev
}, 0); }, 0);
}; };
const calculateAllTransactionsTotal = (transactions) => { const calculateAllTransactionsTotal = (transactions) => {
return transactions.reduce((grandTotal, transaction) => { return transactions.reduce((grandTotal, transaction) => {
return grandTotal + calculateTotalPrice(transaction.DetailedTransactions); return grandTotal + calculateTotalPrice(transaction.DetailedTransactions);
}, 0); }, 0);
}; };
const handleConfirm = async (transactionId) => { const handleConfirm = async (transactionId) => {
setIsPaymentLoading(true); setIsPaymentLoading(true);
@@ -156,9 +146,7 @@ const calculateAllTransactionsTotal = (transactions) => {
<div <div
key={transaction.transactionId} key={transaction.transactionId}
className={styles.RoundedRectangle} className={styles.RoundedRectangle}
onClick={() => style={{ overflow: 'hidden' }}
setSelectedTable(transaction.Table || { tableId: 0 })
}
> >
<div className={styles['receipt-header']}> <div className={styles['receipt-header']}>
@@ -192,19 +180,34 @@ const calculateAllTransactionsTotal = (transactions) => {
<div className={styles['receipt-info']}> <div className={styles['receipt-info']}>
{deviceType == 'clerk' ?
<h3>{transaction.confirmed === 1 ? ( <h3>{transaction.confirmed === 1 ? (
"Silahkan cek pembayaran" "Silahkan Cek Pembayaran"
) : transaction.confirmed === -1 ? ( ) : transaction.confirmed === -1 ? (
"Dibatalkan oleh kasir" "Dibatalkan Oleh Kasir"
) : transaction.confirmed === -2 ? ( ) : transaction.confirmed === -2 ? (
"Dibatalkan oleh pelanggan" "Dibatalkan Oleh Pelanggan"
) : transaction.confirmed === 2 ? (
"Sedang Diproses"
) : transaction.confirmed === 3 ? (
"Transaksi Sukses"
) : (
"Silahkan Cek Ketersediaan"
)}</h3>
:
<h3>{transaction.confirmed === 1 ? (
"Silahkan Bayar Dengan QRIS"
) : transaction.confirmed === -1 ? (
"Dibatalkan Oleh Kasir"
) : transaction.confirmed === -2 ? (
"Dibatalkan Oleh Pelanggan"
) : transaction.confirmed === 2 ? ( ) : transaction.confirmed === 2 ? (
"Sedang diproses" "Sedang diproses"
) : transaction.confirmed === 3 ? ( ) : transaction.confirmed === 3 ? (
"Transaction success" "Transaksi Sukses"
) : ( ) : (
"Silahkan cek ketersediaan" "Memeriksa Ketersediaan "
)}</h3> )}</h3>}
<p>Transaction ID: {transaction.transactionId}</p> <p>Transaction ID: {transaction.transactionId}</p>
<p>Payment Type: {transaction.payment_type}</p> <p>Payment Type: {transaction.payment_type}</p>
@@ -266,60 +269,95 @@ const calculateAllTransactionsTotal = (transactions) => {
</span> </span>
</div> </div>
<div className={styles.TotalContainer}> <div className={styles.TotalContainer}>
{(deviceType == 'clerk' && (transaction.confirmed == 0 || transaction.confirmed == 1 || transaction.confirmed == 2)) ||
(deviceType == 'guestDevice' && (transaction.confirmed == 0))&&
<button <button
className={styles.PayButton} className={styles.PayButton}
onClick={() => handleConfirm(transaction.transactionId)} onClick={() => handleConfirm(transaction.transactionId)}
disabled={ disabled={isPaymentLoading}
isPaymentLoading || // Disable if loading
(deviceType === "clerk" &&
transaction.confirmed !== 1 &&
transaction.confirmed !== 2 &&
transaction.confirmed !== 0) || // Disable for clerk when not Confirm has paid, Confirm item is ready, or Confirm availability
(deviceType !== "clerk" &&
transaction.confirmed !== 1 &&
transaction.paymentClaimed) || // Disable for buyer when not Claim has paid
transaction.confirmed === 3 || // Disable if Transaction success
transaction.confirmed === -1 || // Disable if Declined
transaction.confirmed === -2 || // Disable if Canceled
transaction.confirmed === 2 || // Disable if In process
(transaction.confirmed === 1 && transaction.paymentClaimed) // Disable if verifying payment
}
> >
{deviceType === "clerk" ? ( {deviceType === "clerk" ? (
isPaymentLoading ? ( isPaymentLoading ? (
<ColorRing height="50" width="50" color="white" /> <ColorRing height="50" width="50" color="white" />
) : transaction.confirmed === 1 ? ( ) : transaction.confirmed === 1 ? (
"Confirm has paid" "Konfirmasi Telah Bayar"
) : transaction.confirmed === -1 ? (
"Declined"
) : transaction.confirmed === -2 ? (
"Canceled"
) : transaction.confirmed === 2 ? ( ) : transaction.confirmed === 2 ? (
"Confirm item is ready" "Confirm item is ready"
) : transaction.confirmed === 3 ? (
"Transaction success"
) : ( ) : (
"Confirm availability" "Confirm availability"
) )
) : isPaymentLoading ? ( ) :
isPaymentLoading ? (
<ColorRing height="50" width="50" color="white" /> <ColorRing height="50" width="50" color="white" />
) : transaction.confirmed === 1 &&
!transaction.paymentClaimed ? (
"Claim has paid"
) : transaction.confirmed === 1 &&
transaction.paymentClaimed ? (
"Verifying your payment"
) : transaction.confirmed === -1 ? (
"Declined"
) : transaction.confirmed === -2 ? (
"Canceled"
) : transaction.confirmed === 2 ? (
"In process"
) : ( ) : (
"Transaction success" "Transaction success"
)} )}
</button> </button>
}
{transaction.payment_type != 'cash' && transaction.payment_type != 'paylater/cash' &&
<ButtonWithReplica
paymentUrl={paymentUrl}
price={
"Rp" + calculateTotalPrice(transaction.DetailedTransactions)
}
disabled={isPaymentLoading}
isPaymentLoading={isPaymentLoading}
handleClick={() => handleConfirm(transaction.transactionId)}
Open={() => setIsPaymentOpen(transaction.transactionId)}
isPaymentOpen={isPaymentOpen == transaction.transactionId}
>
{
isPaymentLoading ? null : isPaymentOpen == transaction.transactionId ? (
transaction.paymentClaimed ? (
<>
<div style={{ position: 'absolute', left: '15px', top: '9px' }}>
<ColorRing height="20" width="20" className={styles['receipt-logo']} />
</div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Menunggu konfirmasi
</>
) : 'Klaim telah bayar'
) : 'Tampilkan QR'
}
</ButtonWithReplica>
}
</div> </div>
{transaction.payment_type == 'cash' ?
<button
className={styles.PayButton}
onClick={() => handleDecline(transaction.transactionId)}
disabled={
transaction.confirmed === -1 ||
transaction.confirmed === 3 ||
isPaymentLoading
} // Disable button if confirmed (1) or declined (-1) or
>
{isPaymentLoading ? (
<ColorRing height="50" width="50" color="white" />
) : transaction.confirmed === -1 ? (
"Ditolak" // Display "Declined" if the transaction is declined (-1)
) : transaction.confirmed === -2 ? (
"Dibatalkan" // Display "Declined" if the transaction is declined (-1)
) : (
"Batalkan" // Display "Confirm availability" if the transaction is not confirmed (0)
)}
</button>
:
((transaction.payment_type != 'paylater/cash' && transaction.payment_type != 'paylater/cashless' || isPaymentOpen) &&
<h5
className={`${styles.DeclineButton}`}
onClick={() =>
isPaymentOpen
? setIsPaymentOpen(false)
: handleDecline(transaction.transactionId)
}
>
{isPaymentOpen ? "kembali" : "batalkan"}
</h5>
)
}
{transaction.confirmed == 0 && ( {transaction.confirmed == 0 && (
<h5 <h5
className={styles.DeclineButton} className={styles.DeclineButton}

View File

@@ -134,7 +134,7 @@
position: relative; position: relative;
border-radius: 20px; border-radius: 20px;
padding: 15px; /* Adjusted for better spacing */ padding: 15px; /* Adjusted for better spacing */
margin: 26px; margin: 12px;
background-color: #f9f9f9; background-color: #f9f9f9;
} }