diff --git a/BACKEND/controllers/savedForLater.controller.js b/BACKEND/controllers/savedForLater.controller.js
index aafa165..182360b 100644
--- a/BACKEND/controllers/savedForLater.controller.js
+++ b/BACKEND/controllers/savedForLater.controller.js
@@ -61,7 +61,6 @@ export const removeFromSavedForLater = async (req, res, next) => {
if (!productId) {
return next(new AppError("Product ID is required", 400));
}
-
let savedList = await SavedForLater.findOne({ user: req.user._id });
if (!savedList) {
diff --git a/BACKEND/models/order.model.js b/BACKEND/models/order.model.js
index 753e00e..7d6145f 100644
--- a/BACKEND/models/order.model.js
+++ b/BACKEND/models/order.model.js
@@ -62,6 +62,15 @@ const orderSchema = new mongoose.Schema({
type: Date,
default: null,
},
+ deliveryStatus: {
+ type: String,
+ enum: ["pending", "shipped", "delivered"],
+ default: "pending",
+ },
+ deliveryDate: {
+ type: Date,
+ default: null,
+ },
}, { timestamps: true });
// Indexes for faster lookups
diff --git a/BACKEND/models/user.model.js b/BACKEND/models/user.model.js
index fd1479a..be7fba6 100644
--- a/BACKEND/models/user.model.js
+++ b/BACKEND/models/user.model.js
@@ -81,19 +81,22 @@ const userSchema = new mongoose.Schema(
default: null,
},
+ role: {
+ type: String,
+ enum: ['user', 'admin'],
+ default: 'user',
+ },
referralCode: {
type: String,
unique: true,
sparse: true,
trim: true,
},
-
referredBy: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User',
default: null,
},
-
walletBalance: {
type: Number,
default: 0,
diff --git a/FRONTEND/applyDemo.cjs b/FRONTEND/applyDemo.cjs
new file mode 100644
index 0000000..07e068d
--- /dev/null
+++ b/FRONTEND/applyDemo.cjs
@@ -0,0 +1,48 @@
+const fs = require('fs');
+
+// App.jsx
+let appPath = 'src/App.jsx';
+let appContent = fs.readFileSync(appPath, 'utf8');
+appContent = appContent.replace('import { useKeyboardShortcuts } from "./hooks/useKeyboardShortcuts";', 'import { useKeyboardShortcuts } from "./hooks/useKeyboardShortcuts";\nimport { ToastContainer } from "./utils/toastService";');
+appContent = appContent.replace('', '\n ');
+fs.writeFileSync(appPath, appContent);
+
+// ErrorBoundary.jsx
+let ebPath = 'src/components/ui/ErrorBoundary.jsx';
+let ebContent = fs.readFileSync(ebPath, 'utf8');
+ebContent = ebContent.replace('console.error("ErrorBoundary caught:", error, info.componentStack);', 'console.error("ErrorBoundary caught:", error, info.componentStack);\n // Sentry.captureException(error, { extra: info });\n // LogRocket.captureException(error, { extra: info });');
+fs.writeFileSync(ebPath, ebContent);
+
+// HomePage.jsx
+let hpPath = 'src/pages/HomePage.jsx';
+let hpContent = fs.readFileSync(hpPath, 'utf8');
+hpContent = hpContent.replace('import FilterPanel from "../components/ui/FilterPanel";', 'import FilterPanel from "../components/ui/FilterPanel";\nimport { notify } from "../utils/toastService";\n\nconst CrashTest = ({ shouldCrash }) => {\n if (shouldCrash) {\n throw new Error("Simulated Frontend Crash for Demo!");\n }\n return null;\n};\n');
+hpContent = hpContent.replace('const [totalProducts, setTotalProducts] = useState(0);', 'const [totalProducts, setTotalProducts] = useState(0);\n const [shouldCrash, setShouldCrash] = useState(false);');
+
+let buttonsStr = `
+
+ Current Products🚀
+
+
+
+
+
+
+ `;
+
+hpContent = hpContent.replace(' \n \n Current Products🚀\n ', buttonsStr);
+fs.writeFileSync(hpPath, hpContent);
+
+console.log("Applied demo changes");
diff --git a/FRONTEND/cleanup.cjs b/FRONTEND/cleanup.cjs
new file mode 100644
index 0000000..3309797
--- /dev/null
+++ b/FRONTEND/cleanup.cjs
@@ -0,0 +1,24 @@
+const fs = require('fs');
+
+let hpPath = 'src/pages/HomePage.jsx';
+let c = fs.readFileSync(hpPath, 'utf8');
+
+const importRegex = /import \{ notify \} from "\.\.\/utils\/toastService";\r?\n\r?\nconst CrashTest = \(\{ shouldCrash \}\) => \{[\s\S]*?if \(shouldCrash\) \{[\s\S]*?throw new Error\("Simulated Frontend Crash for Demo!"\);[\s\S]*?\}[\s\S]*?return null;[\s\S]*?\};\r?\n/;
+c = c.replace(importRegex, '');
+
+const stateRegex = /const \[shouldCrash, setShouldCrash\] = useState\(false\);\r?\n\s*/;
+c = c.replace(stateRegex, '');
+
+const buttonsRegex = /[\s\S]*?
);
})}
)}
+ {savedItems && savedItems.length > 0 && (
+
+
+ {t("cart.savedForLater") || "Saved for Later"} ({savedItems.length})
+
+ {savedItems.map((item) => (
+
+
+ {item.name}
+
+ {formatPrice(item.price, currency, rates)}
+
+
+
+ handleMoveToCart(item)} width="100%">
+ Move to Cart
+
+ removeFromSaved(item._id)} width="100%">
+ Remove
+
+
+
+ ))}
+
+
+ )}
diff --git a/FRONTEND/src/pages/HomePage.jsx b/FRONTEND/src/pages/HomePage.jsx
index 2d4b448..2e987db 100644
--- a/FRONTEND/src/pages/HomePage.jsx
+++ b/FRONTEND/src/pages/HomePage.jsx
@@ -17,6 +17,8 @@ import { formatPrice } from '../utils/currency';
import RecentlyViewedCarousel from "../components/ui/RecentlyViewedCarousel";
import FilterPanel from "../components/ui/FilterPanel";
+
+
const ProductCardSkeleton = () => {
const bg = useColorModeValue("white", "gray.800");
const borderColor = useColorModeValue("gray.200", "gray.700");
@@ -52,6 +54,7 @@ const HomePage = () => {
const [page, setPage] = useState(1);
const [totalPages, setTotalPages] = useState(1);
const [totalProducts, setTotalProducts] = useState(0);
+
const limit = 10;
const [filters, setFilters] = useState({
diff --git a/FRONTEND/src/pages/Login.jsx b/FRONTEND/src/pages/Login.jsx
index de2d846..dd616c3 100644
--- a/FRONTEND/src/pages/Login.jsx
+++ b/FRONTEND/src/pages/Login.jsx
@@ -23,8 +23,8 @@ import {
showErrorToast,
showWarningToast,
} from "../utils/toastHelpers";
+import { useSavedForLaterStore } from "../store/savedForLater";
import { useAuth } from '../context/AuthContext';
-
function Login() {
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
@@ -61,6 +61,9 @@ function Login() {
login(data.token, data.user)
+ // Sync local saved items with the backend profile
+ await useSavedForLaterStore.getState().syncWithBackend();
+
showSuccessToast(
toast,
'Login successful!',
diff --git a/FRONTEND/updateNavbar.cjs b/FRONTEND/updateNavbar.cjs
new file mode 100644
index 0000000..0f8b8be
--- /dev/null
+++ b/FRONTEND/updateNavbar.cjs
@@ -0,0 +1,105 @@
+const fs = require('fs');
+const path = 'src/components/ui/Navbar.jsx';
+let lines = fs.readFileSync(path, 'utf8').split(/\r?\n/);
+
+// We will find lines to replace and insert.
+
+// 1. Add `useSavedForLater` import.
+let importIdx = lines.findIndex(l => l.includes('import { useCart }'));
+if (importIdx !== -1 && !lines.find(l => l.includes('useSavedForLater'))) {
+ lines.splice(importIdx + 1, 0, 'import { useSavedForLater } from "../../store/savedForLater";');
+ lines.splice(importIdx + 2, 0, 'import { Divider } from "@chakra-ui/react";');
+}
+
+// 2. Add `useSavedForLater` hook inside Navbar.
+let cartHookIdx = lines.findIndex(l => l.includes('const { cartItems, removeFromCart, totalPrice, emptyCart } = useCart();'));
+if (cartHookIdx !== -1) {
+ lines[cartHookIdx] = ' const { cartItems, removeFromCart, totalPrice, emptyCart, addToCart } = useCart();';
+ lines.splice(cartHookIdx + 1, 0, ' const { savedItems, saveForLater, removeFromSaved } = useSavedForLater();');
+}
+
+// 3. Add orchestration methods before totalItemsCount
+let totalItemsIdx = lines.findIndex(l => l.includes('const totalItemsCount = cartItems.reduce'));
+if (totalItemsIdx !== -1 && !lines.find(l => l.includes('handleSaveForLater'))) {
+ const orchestrator = [
+ ' const handleSaveForLater = async (item) => {',
+ ' await saveForLater(item);',
+ ' removeFromCart(item._id);',
+ ' };',
+ '',
+ ' const handleMoveToCart = async (item) => {',
+ ' const res = addToCart(item, item.quantity || 1);',
+ ' if (res.status === "added") {',
+ ' await removeFromSaved(item._id);',
+ ' } else if (res.status === "capped") {',
+ ' toast({ title: "Stock Limit", description: "You can\'t add more of this item.", status: "warning", duration: 3000 });',
+ ' } else if (res.status === "out_of_stock") {',
+ ' toast({ title: "Out of Stock", description: "This item is currently out of stock.", status: "error", duration: 3000 });',
+ ' }',
+ ' };',
+ ''
+ ];
+ lines.splice(totalItemsIdx, 0, ...orchestrator);
+}
+
+// 4. Update the Remove button exactly
+let currentPriceIdx = lines.findIndex(l => l.includes('currentPrice, currency, rates'));
+if (currentPriceIdx !== -1) {
+ let btnStart = currentPriceIdx + 3;
+ if (lines[btnStart].includes('',
+ ' handleSaveForLater(item)} width="100%">',
+ ' Save for Later',
+ ' ',
+ ' removeFromCart(item._id)} width="100%">',
+ ' Remove',
+ ' ',
+ ' '
+ );
+ }
+}
+
+// 5. Add Saved Items section before
+let drawerBodyEndIdx = lines.lastIndexOf(' ');
+if (drawerBodyEndIdx !== -1 && !lines.find(l => l.includes('savedItems.length > 0'))) {
+ const savedItemsBlock = [
+ ' {savedItems && savedItems.length > 0 && (',
+ ' ',
+ ' ',
+ ' {t("cart.savedForLater") || "Saved for Later"} ({savedItems.length})',
+ ' ',
+ ' {savedItems.map((item) => (',
+ ' ',
+ ' ',
+ ' {item.name}',
+ ' ',
+ ' {formatPrice(item.price, currency, rates)}',
+ ' ',
+ ' ',
+ ' ',
+ ' handleMoveToCart(item)} width="100%">',
+ ' Move to Cart',
+ ' ',
+ ' removeFromSaved(item._id)} width="100%">',
+ ' Remove',
+ ' ',
+ ' ',
+ ' ',
+ ' ))}',
+ ' ',
+ ' ',
+ ' )}'
+ ];
+ lines.splice(drawerBodyEndIdx, 0, ...savedItemsBlock);
+}
+
+fs.writeFileSync(path, lines.join('\n'));
+console.log('Navbar updated completely via arrays.');