diff --git a/src/components/DocumentViewer.jsx b/src/components/DocumentViewer.jsx
index 930d9b2..0857f3d 100644
--- a/src/components/DocumentViewer.jsx
+++ b/src/components/DocumentViewer.jsx
@@ -1,6 +1,38 @@
-import React from 'react';
+import React, { useState } from 'react';
+import StatusBadge from './StatusBadge';
+import { API_BASE_URL } from '../config';
+import { useAuth } from '../context/AuthContext';
+
+const DocumentViewer = ({ documents, sellerId, refreshDocs }) => {
+ const { token } = useAuth();
+ const [previewDoc, setPreviewDoc] = useState(null);
+
+ const handleApprove = async (docId) => {
+ try {
+ const res = await fetch(`${API_BASE_URL}/sellers/${sellerId}/documents/${docId}/approve/`, {
+ method: 'POST',
+ headers: {
+ 'Authorization': `Bearer ${token}`,
+ 'Content-Type': 'application/json'
+ }
+ });
+ if (!res.ok) throw new Error('Failed to approve document');
+ alert('Document approved successfully');
+ if (refreshDocs) refreshDocs();
+ } catch (err) {
+ alert(err.message);
+ }
+ };
+
+ const handleDownload = (doc) => {
+ const link = document.createElement('a');
+ link.href = doc.url;
+ link.download = doc.filename;
+ document.body.appendChild(link);
+ link.click();
+ document.body.removeChild(link);
+ };
-const DocumentViewer = ({ documents, sellerId }) => {
return (
KYC Document Verification
@@ -11,29 +43,60 @@ const DocumentViewer = ({ documents, sellerId }) => {
background: 'rgba(255, 255, 255, 0.02)',
border: '1px solid var(--glass-border)',
borderRadius: 'var(--border-radius)',
- padding: '16px'
+ padding: '16px',
+ display: 'flex',
+ flexDirection: 'column',
+ justifyContent: 'space-between'
}}>
-
-
{doc.type}
-
Status: Verified
+
+
+ {doc.type}
+
+
+
+ {doc.filename.match(/\.(jpg|jpeg|png)$/i) ? (
+

+ ) : (
+
[Document Preview: {doc.filename}]
+ )}
+
-
- [Presigned Document Preview: {doc.filename}]
-
-
-
- Open Original
-
+
+
+
+
))}
@@ -41,6 +104,41 @@ const DocumentViewer = ({ documents, sellerId }) => {
) : (
No KYC documents submitted yet.
)}
+
+ {/* Lightbox / Preview Modal Overlay */}
+ {previewDoc && (
+
setPreviewDoc(null)}>
+
e.stopPropagation()}>
+
+
Document Preview: {previewDoc.type}
+
+
+
+ {previewDoc.filename.match(/\.(jpg|jpeg|png)$/i) ? (
+

+ ) : previewDoc.filename.match(/\.pdf$/i) ? (
+
+ ) : (
+
+
Preview is not supported directly for this file type ({previewDoc.filename}).
+
+
+ )}
+
+
+
+
+
+
+ )}
);
};
diff --git a/src/index.css b/src/index.css
index 6c8aa72..fd8fc76 100644
--- a/src/index.css
+++ b/src/index.css
@@ -323,3 +323,100 @@ a:hover {
color: var(--text-secondary);
font-size: 14px;
}
+
+/* Modal Popup Styling */
+.modal-overlay {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100vw;
+ height: 100vh;
+ background: rgba(0, 0, 0, 0.7);
+ backdrop-filter: blur(8px);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ z-index: 1000;
+ animation: fadeIn 0.2s ease-out;
+}
+
+.modal-content {
+ background: var(--bg-secondary);
+ border: 1px solid var(--glass-border);
+ border-radius: var(--border-radius);
+ box-shadow: var(--glass-shadow);
+ width: 90%;
+ max-width: 600px;
+ max-height: 85vh;
+ overflow-y: auto;
+ padding: 24px;
+ animation: slideUp 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+}
+
+.modal-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ border-bottom: 1px solid var(--glass-border);
+ padding-bottom: 16px;
+ margin-bottom: 16px;
+}
+
+.modal-close {
+ background: transparent;
+ border: none;
+ color: var(--text-secondary);
+ font-size: 24px;
+ cursor: pointer;
+ transition: var(--transition);
+}
+
+.modal-close:hover {
+ color: #fff;
+}
+
+.modal-section {
+ margin-bottom: 20px;
+}
+
+.modal-section-title {
+ font-size: 16px;
+ font-weight: 600;
+ color: var(--accent-hover);
+ margin-bottom: 12px;
+ text-transform: uppercase;
+ letter-spacing: 0.5px;
+}
+
+.details-grid {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 12px;
+}
+
+.details-item {
+ display: flex;
+ flex-direction: column;
+}
+
+.details-label {
+ font-size: 11px;
+ color: var(--text-muted);
+ text-transform: uppercase;
+}
+
+.details-value {
+ font-size: 14px;
+ color: var(--text-primary);
+ font-weight: 500;
+}
+
+@keyframes fadeIn {
+ from { opacity: 0; }
+ to { opacity: 1; }
+}
+
+@keyframes slideUp {
+ from { transform: translateY(20px); opacity: 0; }
+ to { transform: translateY(0); opacity: 1; }
+}
diff --git a/src/pages/products/ProductList.jsx b/src/pages/products/ProductList.jsx
index 10cc6be..b633d6b 100644
--- a/src/pages/products/ProductList.jsx
+++ b/src/pages/products/ProductList.jsx
@@ -9,6 +9,7 @@ const ProductList = () => {
const [products, setProducts] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
+ const [selectedProduct, setSelectedProduct] = useState(null);
const fetchProducts = async () => {
try {
@@ -109,29 +110,42 @@ const ProductList = () => {
{filteredProducts.map(prod => (
| #{prod.id} |
- {prod.name} |
+ setSelectedProduct(prod)}
+ >
+ {prod.name}
+ |
{prod.supplier_name || 'N/A'} |
₹{parseFloat(prod.price).toLocaleString('en-IN')} |
{prod.stock} items |
|
- {prod.status === 'pending_approval' && (
+ {(prod.status === 'pending' || prod.status === 'pending_approval') && (
<>
-
)}
+
+ {selectedProduct && (
+ setSelectedProduct(null)}>
+ e.stopPropagation()}>
+
+ Product & Seller Details
+ setSelectedProduct(null)}>×
+
+
+
+
+ Product Information
+
+
+ ID
+ #{selectedProduct.id}
+
+
+ Title
+ {selectedProduct.name}
+
+
+ Category
+ {selectedProduct.category || 'N/A'}
+
+
+ SKU
+ {selectedProduct.sku || 'N/A'}
+
+
+ Price
+ ₹{parseFloat(selectedProduct.price).toLocaleString('en-IN')}
+
+
+ Stock
+ {selectedProduct.stock} items
+
+
+ Status
+
+
+
+ Active Listing
+ {selectedProduct.is_active ? 'Yes' : 'No'}
+
+
+ {selectedProduct.image && (
+
+ Product Image
+ {selectedProduct.image.startsWith('data:image') || selectedProduct.image.startsWith('http') ? (
+ 
+ ) : (
+ {selectedProduct.image}
+ )}
+
+ )}
+
+
+
+ Seller / Supplier Information
+
+
+ Store Name
+ {selectedProduct.supplier_name || 'N/A'}
+
+
+ Account Status
+
+
+
+ Email
+ {selectedProduct.supplier_email || 'N/A'}
+
+
+ Phone
+ {selectedProduct.supplier_phone || 'N/A'}
+
+
+ GSTIN
+ {selectedProduct.supplier_gstin || 'N/A'}
+
+
+
+
+
+
+ {
+ await handleStatusChange(selectedProduct.id, 'approve');
+ setSelectedProduct(null);
+ }}
+ >
+ Approve
+
+ {
+ await handleStatusChange(selectedProduct.id, 'hold');
+ setSelectedProduct(null);
+ }}
+ >
+ Hold
+
+ {
+ await handleStatusChange(selectedProduct.id, 'reject');
+ setSelectedProduct(null);
+ }}
+ >
+ Reject
+
+ {
+ await handleRemove(selectedProduct.id);
+ setSelectedProduct(null);
+ }}
+ >
+ Remove Product
+
+
+
+
+ )}
);
};
diff --git a/src/pages/sellers/SellerDetail.jsx b/src/pages/sellers/SellerDetail.jsx
index 7025a6f..a78aaf8 100644
--- a/src/pages/sellers/SellerDetail.jsx
+++ b/src/pages/sellers/SellerDetail.jsx
@@ -189,7 +189,7 @@ const SellerDetail = () => {
)}
{activeTab === 'documents' && (
-
+
)}
);
|