From 8bb53d19dd965734a739439a7e46ebd0580b671e Mon Sep 17 00:00:00 2001 From: sriram Date: Tue, 18 Aug 2026 18:39:20 +0530 Subject: [PATCH] frontend changes with drop elements --- src/App.jsx | 20 +- src/components/NavigationHeader.jsx | 14 +- src/pages/LoginPage.jsx | 7 +- src/pages/UserPage.jsx | 605 ---------------------------- 4 files changed, 10 insertions(+), 636 deletions(-) delete mode 100644 src/pages/UserPage.jsx diff --git a/src/App.jsx b/src/App.jsx index 2b8ae00..07d3a37 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -18,7 +18,6 @@ import { LoginPage } from './pages/LoginPage'; * sees, so deferring it would only add a round trip before the form appears. */ const HomePage = lazy(() => import('./pages/HomePage').then((m) => ({ default: m.HomePage }))); -const UserPage = lazy(() => import('./pages/UserPage').then((m) => ({ default: m.UserPage }))); const AdminPage = lazy(() => import('./pages/AdminPage').then((m) => ({ default: m.AdminPage }))); const McpPage = lazy(() => import('./pages/McpPage').then((m) => ({ default: m.McpPage }))); @@ -48,10 +47,11 @@ function ProtectedRoute({ children, allowedRoles }) { const effectiveRole = role || (user.role === 'store' ? 'user' : user.role); if (allowedRoles && !allowedRoles.includes(effectiveRole)) { - if (window.location.pathname === '/user') { - return children; - } - return ; + // Every remaining route is admin-only, so there is nowhere else in the app + // to send a non-admin. This can still be reached by a token minted before + // the `user` account was disabled - those stay valid for their 12h TTL - + // so it has to terminate somewhere public rather than redirect in a loop. + return ; } return children; @@ -78,16 +78,6 @@ export default function App() { } /> - {/* User Workspace Route */} - - - - } - /> - {/* Admin Panel Route - RESTRICTED TO ADMIN ONLY */} { if (onResetHome) onResetHome(); }} - title={role === 'admin' ? 'Navigate to Catalog' : 'Navigate to User Workspace'} + title="Navigate to Catalog" className="group flex items-center gap-2 rounded-full bg-gradient-to-r from-amber-500 to-amber-600 hover:from-amber-600 hover:to-amber-700 text-white px-4 py-2 text-xs font-semibold shadow-sm transition-all duration-200 active:scale-95 hover:shadow-md" > @@ -107,16 +107,6 @@ export function NavigationHeader({ )} - {/* User Upload tab */} - - User Upload - - {/* MCP tab ONLY visible to Admin role */} {role === 'admin' && ( { - if (!bName) return; - setLoadingBrand(true); - try { - const data = await api.getBrandProducts(bName, { limit: 50 }); - const itemsList = Array.isArray(data) - ? data - : Array.isArray(data?.products) - ? data.products - : []; - setBrandProducts(itemsList); - } catch (e) { - console.warn('Failed to fetch brand products', e); - setBrandProducts([]); - } finally { - setLoadingBrand(false); - } - }; - - useEffect(() => { - fetchBrandCatalog(brandSearch); - }, [brandSearch]); - - const handlePresetLionDates = () => { - setEntryMode('single'); - setBrand('Lion Dates'); - setProductName('Lion Dates 450g'); - setCategory('Health Foods'); - setPriceRange('₹160-220'); - setFinalPrice('185.00'); - setBarcode('20086040'); - setHsnCode('2008'); - setDescription('Premium quality Lion Dates 450g pack enriched with natural nutrients and vitamins.'); - setImageUrl('https://liondates.com/cdn/shop/files/4.datespowder_lifestyle.png?v=1773397173&width=1445'); - }; - - const handleSingleSubmit = async (e) => { - e.preventDefault(); - setSingleError(''); - setSingleResult(null); - setSubmittingSingle(true); - - try { - const payload = { - brand, - product_name: productName, - category, - price_range: priceRange, - final_selling_price: finalPrice ? parseFloat(finalPrice) : null, - barcode: barcode || null, - hsn_code: hsnCode || null, - description: description || undefined, - image_url: imageUrl || undefined, - }; - - const data = await api.addUserProduct(payload); - setSingleResult(data); - setSubmittingSingle(false); - - // Refresh catalog list for current brand - setBrandSearch(brand); - fetchBrandCatalog(brand); - } catch (err) { - setSubmittingSingle(false); - setSingleError(err.message || 'An error occurred while adding the product.'); - } - }; - - const handleBatchSubmit = async (e) => { - e.preventDefault(); - if (!batchFile) return; - setBatchError(''); - setBatchResult(null); - setUploadingBatch(true); - - try { - const data = await api.uploadUserProductsFile(batchFile); - setBatchResult(data); - setUploadingBatch(false); - - if (data.added_products && Array.isArray(data.added_products)) { - // Re-read the brand from the API rather than trusting the response, so - // the panel below is showing what the database actually holds. A card - // built purely from the upload response is what made a failed import - // look successful. - const firstBrand = data.added_products[0]?.brand; - if (firstBrand) { - setBrandSearch(firstBrand); - fetchBrandCatalog(firstBrand); - } - - } - } catch (err) { - setUploadingBatch(false); - setBatchError(err.message || 'Error uploading file.'); - } - }; - - const downloadSampleCSV = () => { - const csvContent = - 'Brand Name,Product Name / Variant,Category,Price Range,Final Price (₹),Barcode (GTIN/EAN),HSN Code,Custom Image URL,Description\n' + - 'Lion Dates,Lion Dates 450g,Health Foods,₹160-220,185.00,20086040,2008,https://liondates.com/cdn/shop/files/4.datespowder_lifestyle.png?v=1773397173&width=1445,Premium Quality Lion Dates 450g\n' + - 'Naga,Naga Maida 2kg,Flour & Grains,₹90-110,98.00,8906012345001,1101,,High grade refined wheat flour maida\n'; - - const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' }); - const url = URL.createObjectURL(blob); - const link = document.createElement('a'); - link.href = url; - link.setAttribute('download', 'sample_product_batch_template.csv'); - document.body.appendChild(link); - link.click(); - document.body.removeChild(link); - URL.revokeObjectURL(url); - }; - - // A spreadsheet import can genuinely half-succeed, and that must not be - // painted the same green as a clean one - the whole complaint was a success - // panel over rows that never landed. - const batchHadErrors = Boolean( - batchResult && ((batchResult.error_count ?? 0) > 0 || batchResult.status === 'partial') - ); - - return ( - -
- - -
- {/* Workspace banner */} -
-
-
- -
-
-

User Product Management

-

- Single/Batch Product Uploads with Dual Persistence -

-
-
- -
- - {/* ========================================================================= */} - {/* VIEW 1: PRODUCT ENTRY & BATCH UPLOAD */} - {/* ========================================================================= */} -
-
-
- - Database & Seed JSON Auto-Sync - -

Upload & Add New Product Records

-

- Add new product variants (e.g. "Lion Dates 450g") via single form or batch CSV/Excel upload. Product details & images sync directly into PostgreSQL database tables and JSON seed catalog files. -

-
- -
- - - -
-
- -
- {/* Left Form: Single vs Batch Upload Tabs */} -
-
-
- - - -
- - - Auto-Enrich & Dual Persistence - -
- - {/* SINGLE PRODUCT FORM */} - {entryMode === 'single' && ( -
- {singleError && ( -
- {singleError} -
- )} - -
-
-
- - setBrand(e.target.value)} - placeholder="e.g. Lion Dates" - className="w-full rounded-xl border border-ink-900/15 bg-white p-2.5 text-xs font-medium text-ink-950 focus:border-blue-500 focus:outline-none" - /> -
- -
- - setProductName(e.target.value)} - placeholder="e.g. Lion Dates 450g" - className="w-full rounded-xl border border-ink-900/15 bg-white p-2.5 text-xs font-medium text-ink-950 focus:border-blue-500 focus:outline-none" - /> -
-
- -
-
- - setCategory(e.target.value)} - placeholder="e.g. Health Foods" - className="w-full rounded-xl border border-ink-900/15 bg-white p-2.5 text-xs font-medium text-ink-950 focus:border-blue-500 focus:outline-none" - /> -
- -
- - setPriceRange(e.target.value)} - placeholder="e.g. ₹160-220" - className="w-full rounded-xl border border-ink-900/15 bg-white p-2.5 text-xs font-medium text-ink-950 focus:border-blue-500 focus:outline-none" - /> -
- -
- - setFinalPrice(e.target.value)} - placeholder="e.g. 185.00" - className="w-full rounded-xl border border-ink-900/15 bg-white p-2.5 text-xs font-medium text-ink-950 focus:border-blue-500 focus:outline-none" - /> -
-
- -
-
- - setBarcode(e.target.value)} - placeholder="e.g. 20086040" - className="w-full rounded-xl border border-ink-900/15 bg-white p-2.5 text-xs font-medium text-ink-950 focus:border-blue-500 focus:outline-none" - /> -
- -
- - setHsnCode(e.target.value)} - placeholder="e.g. 2008" - className="w-full rounded-xl border border-ink-900/15 bg-white p-2.5 text-xs font-medium text-ink-950 focus:border-blue-500 focus:outline-none" - /> -
-
- -
- - setImageUrl(e.target.value)} - placeholder="https://..." - className="w-full rounded-xl border border-ink-900/15 bg-white p-2.5 text-xs font-medium text-ink-950 focus:border-blue-500 focus:outline-none" - /> -
- -
- -