Remove mock data from Orders and Payments tabs; wire real API data
All checks were successful
Beta CI/CD Pipeline / build-and-test (push) Successful in 55s
Beta CI/CD Pipeline / deploy-beta (push) Successful in 9s

This commit is contained in:
vickytechkey 2026-08-21 12:06:56 +05:30
parent b61b4bca23
commit 84f07711c3
3 changed files with 243 additions and 66 deletions

View file

@ -148,6 +148,6 @@ describe('Supplier Portal Onboarding & Active Dashboard Tests', () => {
fireEvent.click(walletTabBtn)
expect(screen.getByText(/Available for Payout/i)).toBeInTheDocument()
expect(screen.getByText(/Recent Transactions/i)).toBeInTheDocument()
expect(screen.getByText(/Transaction History/i)).toBeInTheDocument()
})
})

View file

@ -1,11 +1,58 @@
import React from 'react';
import React, { useState } from 'react';
import { useSeller } from '../../../context/SellerContext';
type TabFilter = 'All Orders' | 'Pending' | 'Shipped' | 'Completed';
const TAB_STATUSES: Record<TabFilter, string[]> = {
'All Orders': [],
'Pending': ['Pending Acceptance'],
'Shipped': ['Ready to Ship', 'Shipped'],
'Completed': ['Delivered', 'Cancelled', 'Rejected'],
};
const STATUS_TAG: Record<string, string> = {
'Pending Acceptance': 'is-warning is-light',
'Ready to Ship': 'is-primary is-light',
'Shipped': 'is-info is-light',
'Delivered': 'is-success is-light',
'Cancelled': 'is-danger is-light',
'Rejected': 'is-danger is-light',
};
export default function OrdersTab() {
const { orders, handleAcceptOrder, handleRejectOrder, setSelectedOrderDetail } = useSeller();
const [activeTab, setActiveTab] = useState<TabFilter>('All Orders');
const filteredOrders = TAB_STATUSES[activeTab].length === 0
? orders
: orders.filter((o: any) => TAB_STATUSES[activeTab].includes(o.status));
const formatDate = (dateStr: string) => {
const d = new Date(dateStr);
if (isNaN(d.getTime())) return dateStr;
return d.toLocaleDateString('en-IN', { day: '2-digit', month: 'short', year: 'numeric' });
};
const handleExportCsv = () => {
const header = 'Order ID,Date,Customer,Item,Qty,Status,Total\n';
const rows = orders.map((o: any) =>
`${o.id},${o.date},${o.customer},${o.item},${o.quantity},${o.status},${o.total}`
).join('\n');
const blob = new Blob([header + rows], { type: 'text/csv;charset=utf-8;' });
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.setAttribute('href', url);
link.setAttribute('download', 'orders_export.csv');
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
};
return (
<div>
<div className="is-flex is-justify-content-space-between is-align-items-center mb-5">
<h1 className="title is-3 has-text-dark mb-0" style={{ fontFamily: 'Libre Caslon Text, serif' }}>Orders</h1>
<button className="button is-primary is-outlined">
<button className="button is-primary is-outlined" onClick={handleExportCsv}>
<span className="icon"><span className="material-symbols-outlined">download</span></span>
<span>Export</span>
</button>
@ -14,42 +61,76 @@ export default function OrdersTab() {
<div className="box">
<div className="tabs">
<ul>
<li className="is-active"><a>All Orders</a></li>
<li><a>Pending</a></li>
<li><a>Shipped</a></li>
<li><a>Completed</a></li>
{(Object.keys(TAB_STATUSES) as TabFilter[]).map(tab => (
<li key={tab} className={activeTab === tab ? 'is-active' : ''}>
<a onClick={() => setActiveTab(tab)}>{tab}</a>
</li>
))}
</ul>
</div>
<table className="table is-fullwidth is-hoverable is-striped">
<thead>
<tr>
<th>Order ID</th>
<th>Date</th>
<th>Customer</th>
<th>Status</th>
<th>Total</th>
<th>Action</th>
</tr>
</thead>
<tbody>
{[
{ id: '#1045', date: 'Oct 24, 2023', customer: 'Jane Doe', status: 'Processing', type: 'info', total: '$120.00' },
{ id: '#1044', date: 'Oct 22, 2023', customer: 'Alex Johnson', status: 'Shipped', type: 'warning', total: '$45.50' },
{ id: '#1043', date: 'Oct 20, 2023', customer: 'Sarah Williams', status: 'Completed', type: 'success', total: '$210.00' }
].map(order => (
<tr key={order.id}>
<td><strong>{order.id}</strong></td>
<td>{order.date}</td>
<td>{order.customer}</td>
<td><span className={`tag is-${order.type} is-light`}>{order.status}</span></td>
<td>{order.total}</td>
<td>
<button className="button is-small is-light">View</button>
</td>
{filteredOrders.length === 0 ? (
<div className="has-text-centered py-6 has-text-grey">
<span className="material-symbols-outlined" style={{ fontSize: '3rem' }}>inventory_2</span>
<p className="mt-2">No orders found in this category.</p>
</div>
) : (
<table className="table is-fullwidth is-hoverable is-striped">
<thead>
<tr>
<th>Order ID</th>
<th>Date</th>
<th>Customer</th>
<th>Item</th>
<th>Status</th>
<th>Total</th>
<th>Action</th>
</tr>
))}
</tbody>
</table>
</thead>
<tbody>
{filteredOrders.map((order: any) => (
<tr key={order.id}>
<td><strong>#{order.id}</strong></td>
<td>{formatDate(order.date)}</td>
<td>{order.customer || '—'}</td>
<td>{order.item || '—'}</td>
<td>
<span className={`tag ${STATUS_TAG[order.status] || 'is-light'}`}>
{order.status}
</span>
</td>
<td>{Number(order.total).toFixed(2)}</td>
<td>
<div className="buttons are-small">
<button
className="button is-light"
onClick={() => setSelectedOrderDetail(order)}
>
View
</button>
{order.status === 'Pending Acceptance' && (
<>
<button
className="button is-success is-light"
onClick={() => handleAcceptOrder(order.id)}
>
Accept
</button>
<button
className="button is-danger is-light"
onClick={() => handleRejectOrder(order.id)}
>
Reject
</button>
</>
)}
</div>
</td>
</tr>
))}
</tbody>
</table>
)}
</div>
</div>
);

View file

@ -1,50 +1,146 @@
import React from 'react';
import React, { useState } from 'react';
import { useSeller } from '../../../context/SellerContext';
export default function PaymentsTab() {
const { wallet, withdrawAmount, setWithdrawAmount, handleWithdrawRequest } = useSeller();
const outstanding = Number(wallet.outstanding || 0);
const withdrawn = Number(wallet.withdrawn || 0);
const transactions = wallet.transactions || wallet.history || [];
// Pending = orders delivered but not yet in wallet (approximated as 0 unless backend provides it)
const pendingClearance = Number(wallet.pending_clearance || 0);
const [showWithdrawModal, setShowWithdrawModal] = useState(false);
const formatDate = (dateStr: string) => {
const d = new Date(dateStr);
if (isNaN(d.getTime())) return dateStr;
return d.toLocaleDateString('en-IN', { day: '2-digit', month: 'short', year: 'numeric' });
};
const handleWithdraw = async () => {
await handleWithdrawRequest();
setShowWithdrawModal(false);
setWithdrawAmount('');
};
return (
<div>
<h1 className="title is-3 has-text-dark mb-5" style={{ fontFamily: 'Libre Caslon Text, serif' }}>Payments & Earnings</h1>
<h1 className="title is-3 has-text-dark mb-5" style={{ fontFamily: 'Libre Caslon Text, serif' }}>
Payments &amp; Earnings
</h1>
<div className="columns is-multiline mb-5">
<div className="column is-6">
<div className="box has-background-primary has-text-white">
<p className="heading has-text-white-ter mb-1">Available for Payout</p>
<p className="title is-1 has-text-white mb-4">$1,240.00</p>
<button className="button is-white is-outlined is-fullwidth">Withdraw Funds</button>
<p className="title is-1 has-text-white mb-4">
{outstanding.toLocaleString('en-IN', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
</p>
<button
className="button is-white is-outlined is-fullwidth"
onClick={() => setShowWithdrawModal(true)}
disabled={outstanding <= 0}
>
Withdraw Funds
</button>
</div>
</div>
<div className="column is-6">
<div className="box" style={{ height: '100%' }}>
<p className="heading has-text-grey-dark mb-1">Pending Clearance</p>
<p className="title is-3 has-text-dark mb-4">$320.00</p>
<p className="heading has-text-grey-dark mb-1">Total Withdrawn</p>
<p className="title is-3 has-text-dark mb-3">
{withdrawn.toLocaleString('en-IN', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
</p>
{pendingClearance > 0 && (
<>
<p className="heading has-text-grey-dark mb-1 mt-3">Pending Clearance</p>
<p className="title is-5 has-text-dark mb-2">
{pendingClearance.toLocaleString('en-IN', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
</p>
</>
)}
<p className="is-size-7 has-text-grey">Funds will be available in 3-5 business days after order delivery.</p>
</div>
</div>
</div>
{/* Withdraw Modal */}
{showWithdrawModal && (
<div className="modal is-active">
<div className="modal-background" onClick={() => setShowWithdrawModal(false)} />
<div className="modal-card">
<header className="modal-card-head">
<p className="modal-card-title">Withdraw Funds</p>
<button className="delete" onClick={() => setShowWithdrawModal(false)} />
</header>
<section className="modal-card-body">
<p className="mb-3 has-text-grey">
Available: {outstanding.toLocaleString('en-IN', { minimumFractionDigits: 2 })}
</p>
<div className="field">
<label className="label">Amount ()</label>
<div className="control">
<input
className="input"
type="number"
min="1"
max={outstanding}
placeholder="Enter amount"
value={withdrawAmount}
onChange={e => setWithdrawAmount(e.target.value)}
/>
</div>
</div>
</section>
<footer className="modal-card-foot">
<button className="button is-primary" onClick={handleWithdraw}>Confirm Withdrawal</button>
<button className="button" onClick={() => setShowWithdrawModal(false)}>Cancel</button>
</footer>
</div>
</div>
)}
<div className="box">
<h2 className="title is-5 has-text-dark">Recent Transactions</h2>
<table className="table is-fullwidth">
<thead>
<tr>
<th>Date</th>
<th>Description</th>
<th>Amount</th>
</tr>
</thead>
<tbody>
<tr>
<td>Oct 20, 2023</td>
<td>Payout to Bank Account (...1234)</td>
<td className="has-text-danger">-$500.00</td>
</tr>
<tr>
<td>Oct 19, 2023</td>
<td>Order #1042 Revenue</td>
<td className="has-text-success">+$85.00</td>
</tr>
</tbody>
</table>
<h2 className="title is-5 has-text-dark">Transaction History</h2>
{transactions.length === 0 ? (
<div className="has-text-centered py-5 has-text-grey">
<span className="material-symbols-outlined" style={{ fontSize: '3rem' }}>receipt_long</span>
<p className="mt-2">No transactions yet.</p>
</div>
) : (
<table className="table is-fullwidth is-hoverable">
<thead>
<tr>
<th>Date</th>
<th>Description</th>
<th>Amount</th>
<th>Status</th>
</tr>
</thead>
<tbody>
{transactions.map((tx: any) => {
const amount = Number(tx.amount || 0);
const isDebit = tx.type === 'withdrawal' || amount < 0;
return (
<tr key={tx.id}>
<td>{formatDate(tx.date)}</td>
<td>{tx.description || (isDebit ? 'Payout Withdrawal' : 'Order Revenue')}</td>
<td className={isDebit ? 'has-text-danger' : 'has-text-success'}>
{isDebit ? '-' : '+'}{Math.abs(amount).toFixed(2)}
</td>
<td>
<span className={`tag ${tx.status === 'Transferred' ? 'is-success is-light' : 'is-warning is-light'}`}>
{tx.status || 'Pending'}
</span>
</td>
</tr>
);
})}
</tbody>
</table>
)}
</div>
</div>
);