add order history to profile
This commit is contained in:
@@ -2075,6 +2075,68 @@ body {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.profile-orders-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.profile-order-card {
|
||||
border: 1px solid #f0f0f0;
|
||||
border-radius: 10px;
|
||||
padding: 0.85rem 1rem;
|
||||
background: #fafafa;
|
||||
}
|
||||
|
||||
.profile-order-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.profile-order-date {
|
||||
font-size: 0.85rem;
|
||||
color: #555;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.profile-order-total {
|
||||
font-size: 0.95rem;
|
||||
font-weight: 700;
|
||||
color: #222;
|
||||
}
|
||||
|
||||
.profile-order-meta {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
font-size: 0.78rem;
|
||||
color: #999;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.profile-order-items {
|
||||
margin: 0.25rem 0 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.2rem;
|
||||
border-top: 1px solid #ececec;
|
||||
padding-top: 0.5rem;
|
||||
}
|
||||
|
||||
.profile-order-items li {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
font-size: 0.82rem;
|
||||
color: #444;
|
||||
}
|
||||
|
||||
.profile-order-item-price {
|
||||
color: #888;
|
||||
}
|
||||
|
||||
/* Store Selector */
|
||||
|
||||
.nav-store-select {
|
||||
|
||||
@@ -25,6 +25,8 @@ export default function ProfilePage() {
|
||||
|
||||
const [pets, setPets] = useState([]);
|
||||
const [loadingPets, setLoadingPets] = useState(false);
|
||||
const [orders, setOrders] = useState([]);
|
||||
const [loadingOrders, setLoadingOrders] = useState(false);
|
||||
const [showForm, setShowForm] = useState(false);
|
||||
const [editingPet, setEditingPet] = useState(null);
|
||||
const [petName, setPetName] = useState("");
|
||||
@@ -120,11 +122,27 @@ export default function ProfilePage() {
|
||||
};
|
||||
}, [clearPetImageObjectUrls]);
|
||||
|
||||
const loadOrders = useCallback(async () => {
|
||||
if (!token) return;
|
||||
setLoadingOrders(true);
|
||||
try {
|
||||
const res = await fetch(`${API_BASE}/api/v1/sales/my?size=20&sort=saleDate,desc`, {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
});
|
||||
if (!res.ok) return;
|
||||
const data = await res.json();
|
||||
setOrders(data.content ?? []);
|
||||
} catch { } finally {
|
||||
setLoadingOrders(false);
|
||||
}
|
||||
}, [token]);
|
||||
|
||||
useEffect(() => {
|
||||
if (user?.role === "CUSTOMER" || user?.role === "ADMIN") {
|
||||
loadPets();
|
||||
loadOrders();
|
||||
}
|
||||
}, [user, loadPets]);
|
||||
}, [user, loadPets, loadOrders]);
|
||||
|
||||
useEffect(() => {
|
||||
let objectUrl = null;
|
||||
@@ -642,6 +660,46 @@ export default function ProfilePage() {
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{(user.role === "CUSTOMER" || user.role === "ADMIN") && (
|
||||
<div className="profile-pets-section">
|
||||
<div className="profile-pets-header">
|
||||
<h2 className="profile-pets-title">Order History</h2>
|
||||
</div>
|
||||
{loadingOrders ? (
|
||||
<p className="appt-loading">Loading orders...</p>
|
||||
) : orders.length === 0 ? (
|
||||
<p className="profile-pets-empty">No orders yet.</p>
|
||||
) : (
|
||||
<div className="profile-orders-list">
|
||||
{orders.map((order) => (
|
||||
<div key={order.saleId} className="profile-order-card">
|
||||
<div className="profile-order-header">
|
||||
<span className="profile-order-date">
|
||||
{new Date(order.saleDate).toLocaleDateString([], { year: "numeric", month: "short", day: "numeric" })}
|
||||
</span>
|
||||
<span className="profile-order-total">${Number(order.totalAmount).toFixed(2)}</span>
|
||||
</div>
|
||||
<div className="profile-order-meta">
|
||||
<span>{order.storeName}</span>
|
||||
{order.paymentMethod && <span>{order.paymentMethod}</span>}
|
||||
</div>
|
||||
{order.items?.length > 0 && (
|
||||
<ul className="profile-order-items">
|
||||
{order.items.map((item) => (
|
||||
<li key={item.saleItemId}>
|
||||
<span>{item.productName} × {item.quantity}</span>
|
||||
<span className="profile-order-item-price">${(Number(item.unitPrice) * item.quantity).toFixed(2)}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user