diff --git a/backend/controllers/history.js b/backend/controllers/history.js
index 684bb35..1c85042 100644
--- a/backend/controllers/history.js
+++ b/backend/controllers/history.js
@@ -1,6 +1,5 @@
const db = require("../utils/database");
-// TODO: Get the recommondaed product given the userID
exports.HistoryByUserId = async (req, res) => {
const { id } = req.body;
try {
@@ -21,7 +20,7 @@ exports.HistoryByUserId = async (req, res) => {
JOIN User U ON P.UserID = U.UserID
JOIN Category C ON P.CategoryID = C.CategoryID
JOIN History H ON H.ProductID = P.ProductID
- WHERE U.UserID = ?
+ WHERE H.UserID = ?
)
SELECT
ProductID,
@@ -50,3 +49,42 @@ exports.HistoryByUserId = async (req, res) => {
});
}
};
+
+exports.AddHistory = async (req, res) => {
+ const { userID, productID } = req.body;
+ console.log(userID);
+ try {
+ // Use parameterized query to prevent SQL injection
+ const [result] = await db.execute(
+ `INSERT INTO History (UserID, ProductID) VALUES (?, ?)`,
+ [userID, productID],
+ );
+
+ res.json({
+ success: true,
+ message: "Product added to history successfully",
+ });
+ } catch (error) {
+ console.error("Error adding favorite product:", error);
+ return res.json({ error: "Could not add favorite product" });
+ }
+};
+
+exports.DelHistory = async (req, res) => {
+ const { userID, productID } = req.body;
+ console.log(userID);
+ try {
+ // Use parameterized query to prevent SQL injection
+ const [result] = await db.execute(`DELETE FROM History WHERE UserID=?`, [
+ userID,
+ ]);
+
+ res.json({
+ success: true,
+ message: "Product deleted from History successfully",
+ });
+ } catch (error) {
+ console.error("Error adding favorite product:", error);
+ return res.json({ error: "Could not add favorite product" });
+ }
+};
diff --git a/backend/controllers/product.js b/backend/controllers/product.js
index 357867a..c5a790c 100644
--- a/backend/controllers/product.js
+++ b/backend/controllers/product.js
@@ -20,6 +20,26 @@ exports.addFavorite = async (req, res) => {
}
};
+exports.removeFavorite = async (req, res) => {
+ const { userID, productID } = req.body;
+ console.log(userID);
+ try {
+ // Use parameterized query to prevent SQL injection
+ const [result] = await db.execute(
+ `DELETE FROM Favorites WHERE UserID = ? AND ProductID = ?`,
+ [userID, productID],
+ );
+
+ res.json({
+ success: true,
+ message: "Product removed from favorites successfully",
+ });
+ } catch (error) {
+ console.error("Error removing favorite product:", error);
+ return res.json({ error: "Could not remove favorite product" });
+ }
+};
+
exports.getFavorites = async (req, res) => {
const { userID } = req.body;
diff --git a/backend/routes/history.js b/backend/routes/history.js
index 50cd826..6713233 100644
--- a/backend/routes/history.js
+++ b/backend/routes/history.js
@@ -1,8 +1,14 @@
// routes/product.js
const express = require("express");
-const { HistoryByUserId } = require("../controllers/history");
+const {
+ HistoryByUserId,
+ DelHistory,
+ AddHistory,
+} = require("../controllers/history");
const router = express.Router();
router.post("/getHistory", HistoryByUserId);
+router.post("/delHistory", DelHistory);
+router.post("/addHistory", AddHistory);
module.exports = router;
diff --git a/backend/routes/product.js b/backend/routes/product.js
index 7158fbf..24c5705 100644
--- a/backend/routes/product.js
+++ b/backend/routes/product.js
@@ -3,6 +3,7 @@ const express = require("express");
const {
addFavorite,
getFavorites,
+ removeFavorite,
getAllProducts,
getProductById,
} = require("../controllers/product");
@@ -16,6 +17,7 @@ router.use((req, res, next) => {
router.post("/addFavorite", addFavorite);
router.post("/getFavorites", getFavorites);
+router.post("/delFavorite", removeFavorite);
router.get("/getProduct", getAllProducts);
router.get("/:id", getProductById); // Simplified route
diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx
index 6703948..4499afa 100644
--- a/frontend/src/App.jsx
+++ b/frontend/src/App.jsx
@@ -14,7 +14,6 @@ import Favorites from "./pages/Favorites";
import ProductDetail from "./pages/ProductDetail";
import ItemForm from "./pages/MyListings";
import SearchPage from "./pages/SearchPage"; // Make sure to import the SearchPage
-import axios from "axios";
function App() {
// Authentication state - initialize from localStorage if available
diff --git a/frontend/src/components/FloatingAlert.jsx b/frontend/src/components/FloatingAlert.jsx
new file mode 100644
index 0000000..6c6bf69
--- /dev/null
+++ b/frontend/src/components/FloatingAlert.jsx
@@ -0,0 +1,19 @@
+// components/FloatingAlert.jsx
+import { useEffect } from "react";
+
+const FloatingAlert = ({ message, onClose, duration = 3000 }) => {
+ useEffect(() => {
+ const timer = setTimeout(() => {
+ onClose();
+ }, duration);
+
+ return () => clearTimeout(timer);
+ }, [onClose, duration]);
+
+ return (
+
+ {message}
+
+ );
+};
+export default FloatingAlert;
diff --git a/frontend/src/pages/Favorites.jsx b/frontend/src/pages/Favorites.jsx
index a42486e..59219fb 100644
--- a/frontend/src/pages/Favorites.jsx
+++ b/frontend/src/pages/Favorites.jsx
@@ -7,6 +7,7 @@ const Favorites = () => {
const [showFilters, setShowFilters] = useState(false);
const [sortBy, setSortBy] = useState("dateAdded");
const [filterCategory, setFilterCategory] = useState("All");
+ const storedUser = JSON.parse(sessionStorage.getItem("user"));
const mapCategory = (id) => {
const categories = {
@@ -20,10 +21,41 @@ const Favorites = () => {
return categories[id] || "Other";
};
+ function reloadPage() {
+ var doctTimestamp = new Date(performance.timing.domLoading).getTime();
+ var now = Date.now();
+ if (now > doctTimestamp) {
+ location.reload();
+ }
+ }
+
+ const removeFromFavorites = async (itemID) => {
+ const response = await fetch(
+ "http://localhost:3030/api/product/delFavorite",
+ {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify({
+ userID: storedUser.ID,
+ productID: itemID,
+ }),
+ },
+ );
+ const data = await response.json();
+ if (data.success) {
+ reloadPage();
+ }
+
+ if (!response.ok) throw new Error("Failed to fetch products");
+ console.log(response);
+ console.log(`Add Product -> History: ${itemID}`);
+ };
+
useEffect(() => {
const fetchFavorites = async () => {
try {
- const user = JSON.parse(sessionStorage.getItem("user"));
const response = await fetch(
"http://localhost:3030/api/product/getFavorites",
{
@@ -31,13 +63,11 @@ const Favorites = () => {
headers: {
"Content-Type": "application/json",
},
- body: JSON.stringify({ userID: user.ID }),
+ body: JSON.stringify({ userID: storedUser.ID }),
},
);
const data = await response.json();
- console.log(user.ID);
- console.log(data);
const favoritesData = data.favorites;
@@ -75,11 +105,6 @@ const Favorites = () => {
return `${diffInDays}d ago`;
};
- const removeFromFavorites = (id) => {
- setFavorites(favorites.filter((item) => item.id !== id));
- // Optional: Send DELETE request to backend here
- };
-
const sortedFavorites = [...favorites].sort((a, b) => {
if (sortBy === "dateAdded")
return new Date(b.dateAdded) - new Date(a.dateAdded);
diff --git a/frontend/src/pages/Home.jsx b/frontend/src/pages/Home.jsx
index c07c032..315bf3b 100644
--- a/frontend/src/pages/Home.jsx
+++ b/frontend/src/pages/Home.jsx
@@ -1,6 +1,8 @@
import { useState, useEffect } from "react";
import { Link, useNavigate } from "react-router-dom";
-import { Tag, Heart } from "lucide-react";
+import { Tag } from "lucide-react";
+
+import FloatingAlert from "../components/FloatingAlert"; // adjust path if needed
const Home = () => {
const navigate = useNavigate();
@@ -9,10 +11,11 @@ const Home = () => {
const [history, sethistory] = useState([]);
const [error, setError] = useState(null);
const storedUser = JSON.parse(sessionStorage.getItem("user"));
+ const [showAlert, setShowAlert] = useState(false);
- const handleLinkClick = async (id) => {
+ const toggleFavorite = async (id) => {
const response = await fetch(
- "http://localhost:3030/api/product/addFavorites",
+ "http://localhost:3030/api/product/addFavorite",
{
method: "POST",
headers: {
@@ -20,17 +23,34 @@ const Home = () => {
},
body: JSON.stringify({
userID: storedUser.ID,
- productsID: id,
+ productID: id,
}),
},
);
-
- if (!response.ok) throw new Error("Failed to fetch products");
-
+ const data = await response.json();
+ if (data.success) {
+ setShowAlert(true);
+ }
console.log(response);
console.log(`Add Product -> History: ${id}`);
};
+ const addHistory = async (id) => {
+ const response = await fetch(
+ "http://localhost:3030/api/history/addHistory",
+ {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify({
+ userID: storedUser.ID,
+ productID: id,
+ }),
+ },
+ );
+ };
+
function reloadPage() {
var doctTimestamp = new Date(performance.timing.domLoading).getTime();
var now = Date.now();
@@ -44,7 +64,6 @@ const Home = () => {
useEffect(() => {
const fetchrecomProducts = async () => {
// Get the user's data from localStorage
- const storedUser = JSON.parse(sessionStorage.getItem("user"));
console.log(storedUser);
try {
const response = await fetch(
@@ -126,7 +145,6 @@ const Home = () => {
useEffect(() => {
const fetchrecomProducts = async () => {
// Get the user's data from localStorage
- const storedUser = JSON.parse(sessionStorage.getItem("user"));
console.log(storedUser);
try {
const response = await fetch(
@@ -155,7 +173,6 @@ const Home = () => {
image: product.ProductImage, // Use the alias for image URL
seller: product.SellerName, // Fetch seller name properly
datePosted: product.DateUploaded, // Use the actual date
- isFavorite: false, // Default state
})),
);
} else {
@@ -169,18 +186,6 @@ const Home = () => {
fetchrecomProducts();
}, []);
- // Toggle favorite status
- const toggleFavorite = (id, e) => {
- e.preventDefault(); // Prevent navigation when clicking the heart icon
- setListings((prevListings) =>
- prevListings.map((listing) =>
- listing.id === id
- ? { ...listing, isFavorite: !listing.isFavorite }
- : listing,
- ),
- );
- };
-
const handleSelling = () => {
navigate("/selling");
};
@@ -218,6 +223,12 @@ const Home = () => {
{/* Recent Listings */}
+ {showAlert && (
+ setShowAlert(false)}
+ />
+ )}
Recommendation
@@ -245,6 +256,7 @@ const Home = () => {
addHistory(recommended.id)}
className="bg-white border border-gray-200 hover:shadow-md transition-shadow w-70 flex-shrink-0 relative"
>
@@ -254,16 +266,14 @@ const Home = () => {
className="w-full h-48 object-cover"
/>
@@ -308,6 +318,12 @@ const Home = () => {
{/* Recent Listings */}
+ {showAlert && (
+ setShowAlert(false)}
+ />
+ )}
Recent Listings
@@ -335,26 +351,24 @@ const Home = () => {
handleLinkClick(listing.id)}
className="bg-white border border-gray-200 hover:shadow-md transition-shadow w-70 flex-shrink-0 relative"
>

addHistory(listing.id)}
className="w-full h-48 object-cover"
/>
@@ -399,6 +413,12 @@ const Home = () => {
{/* Recent Listings */}
+ {showAlert && (
+ setShowAlert(false)}
+ />
+ )}
History
@@ -433,16 +453,14 @@ const Home = () => {
className="w-full h-48 object-cover"
/>
diff --git a/frontend/src/pages/Settings.jsx b/frontend/src/pages/Settings.jsx
index dfc967e..4f758e6 100644
--- a/frontend/src/pages/Settings.jsx
+++ b/frontend/src/pages/Settings.jsx
@@ -1,5 +1,6 @@
import { useState, useEffect } from "react";
import { User, Lock, Trash2, History, Search, Shield } from "lucide-react";
+import FloatingAlert from "../components/FloatingAlert"; // adjust path if needed
const Settings = () => {
const [userData, setUserData] = useState({
@@ -16,6 +17,8 @@ const Settings = () => {
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState(null);
+ const [showAlert, setShowAlert] = useState(false);
+ const storedUser = JSON.parse(sessionStorage.getItem("user"));
// Fetch user data when component mounts
useEffect(() => {
@@ -88,6 +91,25 @@ const Settings = () => {
}));
};
+ const removeHistory = async () => {
+ const response = await fetch(
+ "http://localhost:3030/api/history/delHistory",
+ {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify({
+ userID: storedUser.ID,
+ }),
+ },
+ );
+
+ if (response.ok) {
+ setShowAlert(true);
+ }
+ };
+
const handleUpdateProfile = async () => {
try {
// Ensure userId is present
@@ -159,12 +181,6 @@ const Settings = () => {
}
};
- const handleDeleteHistory = (type) => {
- // TODO: Delete the specified history
- console.log(`Deleting ${type} history`);
- alert(`${type} history deleted successfully!`);
- };
-
const handleDeleteAccount = async () => {
if (
window.confirm(
@@ -416,6 +432,12 @@ const Settings = () => {
{/* Privacy Section */}
+ {showAlert && (
+ setShowAlert(false)}
+ />
+ )}
@@ -432,33 +454,12 @@ const Settings = () => {
Search History
- Delete all your search history on StudentMarket
+ Delete all your history on Market
-
-
-
-
-
-
-
- Browsing History
-
-
- Delete all your browsing history on StudentMarket
-
-
-
-