History (add/ remove) favorites add remove done
This commit is contained in:
@@ -1,6 +1,5 @@
|
|||||||
const db = require("../utils/database");
|
const db = require("../utils/database");
|
||||||
|
|
||||||
// TODO: Get the recommondaed product given the userID
|
|
||||||
exports.HistoryByUserId = async (req, res) => {
|
exports.HistoryByUserId = async (req, res) => {
|
||||||
const { id } = req.body;
|
const { id } = req.body;
|
||||||
try {
|
try {
|
||||||
@@ -21,7 +20,7 @@ exports.HistoryByUserId = async (req, res) => {
|
|||||||
JOIN User U ON P.UserID = U.UserID
|
JOIN User U ON P.UserID = U.UserID
|
||||||
JOIN Category C ON P.CategoryID = C.CategoryID
|
JOIN Category C ON P.CategoryID = C.CategoryID
|
||||||
JOIN History H ON H.ProductID = P.ProductID
|
JOIN History H ON H.ProductID = P.ProductID
|
||||||
WHERE U.UserID = ?
|
WHERE H.UserID = ?
|
||||||
)
|
)
|
||||||
SELECT
|
SELECT
|
||||||
ProductID,
|
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" });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|||||||
@@ -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) => {
|
exports.getFavorites = async (req, res) => {
|
||||||
const { userID } = req.body;
|
const { userID } = req.body;
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,14 @@
|
|||||||
// routes/product.js
|
// routes/product.js
|
||||||
const express = require("express");
|
const express = require("express");
|
||||||
const { HistoryByUserId } = require("../controllers/history");
|
const {
|
||||||
|
HistoryByUserId,
|
||||||
|
DelHistory,
|
||||||
|
AddHistory,
|
||||||
|
} = require("../controllers/history");
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
router.post("/getHistory", HistoryByUserId);
|
router.post("/getHistory", HistoryByUserId);
|
||||||
|
router.post("/delHistory", DelHistory);
|
||||||
|
router.post("/addHistory", AddHistory);
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ const express = require("express");
|
|||||||
const {
|
const {
|
||||||
addFavorite,
|
addFavorite,
|
||||||
getFavorites,
|
getFavorites,
|
||||||
|
removeFavorite,
|
||||||
getAllProducts,
|
getAllProducts,
|
||||||
getProductById,
|
getProductById,
|
||||||
} = require("../controllers/product");
|
} = require("../controllers/product");
|
||||||
@@ -16,6 +17,7 @@ router.use((req, res, next) => {
|
|||||||
|
|
||||||
router.post("/addFavorite", addFavorite);
|
router.post("/addFavorite", addFavorite);
|
||||||
router.post("/getFavorites", getFavorites);
|
router.post("/getFavorites", getFavorites);
|
||||||
|
router.post("/delFavorite", removeFavorite);
|
||||||
|
|
||||||
router.get("/getProduct", getAllProducts);
|
router.get("/getProduct", getAllProducts);
|
||||||
router.get("/:id", getProductById); // Simplified route
|
router.get("/:id", getProductById); // Simplified route
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ import Favorites from "./pages/Favorites";
|
|||||||
import ProductDetail from "./pages/ProductDetail";
|
import ProductDetail from "./pages/ProductDetail";
|
||||||
import ItemForm from "./pages/MyListings";
|
import ItemForm from "./pages/MyListings";
|
||||||
import SearchPage from "./pages/SearchPage"; // Make sure to import the SearchPage
|
import SearchPage from "./pages/SearchPage"; // Make sure to import the SearchPage
|
||||||
import axios from "axios";
|
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
// Authentication state - initialize from localStorage if available
|
// Authentication state - initialize from localStorage if available
|
||||||
|
|||||||
19
frontend/src/components/FloatingAlert.jsx
Normal file
19
frontend/src/components/FloatingAlert.jsx
Normal file
@@ -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 (
|
||||||
|
<div className="fixed top-4 left-1/2 transform -translate-x-1/2 bg-green-500 text-white px-4 py-2 rounded-xl shadow-lg z-50 text-center">
|
||||||
|
{message}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
export default FloatingAlert;
|
||||||
@@ -7,6 +7,7 @@ const Favorites = () => {
|
|||||||
const [showFilters, setShowFilters] = useState(false);
|
const [showFilters, setShowFilters] = useState(false);
|
||||||
const [sortBy, setSortBy] = useState("dateAdded");
|
const [sortBy, setSortBy] = useState("dateAdded");
|
||||||
const [filterCategory, setFilterCategory] = useState("All");
|
const [filterCategory, setFilterCategory] = useState("All");
|
||||||
|
const storedUser = JSON.parse(sessionStorage.getItem("user"));
|
||||||
|
|
||||||
const mapCategory = (id) => {
|
const mapCategory = (id) => {
|
||||||
const categories = {
|
const categories = {
|
||||||
@@ -20,10 +21,41 @@ const Favorites = () => {
|
|||||||
return categories[id] || "Other";
|
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(() => {
|
useEffect(() => {
|
||||||
const fetchFavorites = async () => {
|
const fetchFavorites = async () => {
|
||||||
try {
|
try {
|
||||||
const user = JSON.parse(sessionStorage.getItem("user"));
|
|
||||||
const response = await fetch(
|
const response = await fetch(
|
||||||
"http://localhost:3030/api/product/getFavorites",
|
"http://localhost:3030/api/product/getFavorites",
|
||||||
{
|
{
|
||||||
@@ -31,13 +63,11 @@ const Favorites = () => {
|
|||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
body: JSON.stringify({ userID: user.ID }),
|
body: JSON.stringify({ userID: storedUser.ID }),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
console.log(user.ID);
|
|
||||||
console.log(data);
|
|
||||||
|
|
||||||
const favoritesData = data.favorites;
|
const favoritesData = data.favorites;
|
||||||
|
|
||||||
@@ -75,11 +105,6 @@ const Favorites = () => {
|
|||||||
return `${diffInDays}d ago`;
|
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) => {
|
const sortedFavorites = [...favorites].sort((a, b) => {
|
||||||
if (sortBy === "dateAdded")
|
if (sortBy === "dateAdded")
|
||||||
return new Date(b.dateAdded) - new Date(a.dateAdded);
|
return new Date(b.dateAdded) - new Date(a.dateAdded);
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect } from "react";
|
||||||
import { Link, useNavigate } from "react-router-dom";
|
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 Home = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
@@ -9,10 +11,11 @@ const Home = () => {
|
|||||||
const [history, sethistory] = useState([]);
|
const [history, sethistory] = useState([]);
|
||||||
const [error, setError] = useState(null);
|
const [error, setError] = useState(null);
|
||||||
const storedUser = JSON.parse(sessionStorage.getItem("user"));
|
const storedUser = JSON.parse(sessionStorage.getItem("user"));
|
||||||
|
const [showAlert, setShowAlert] = useState(false);
|
||||||
|
|
||||||
const handleLinkClick = async (id) => {
|
const toggleFavorite = async (id) => {
|
||||||
const response = await fetch(
|
const response = await fetch(
|
||||||
"http://localhost:3030/api/product/addFavorites",
|
"http://localhost:3030/api/product/addFavorite",
|
||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
@@ -20,17 +23,34 @@ const Home = () => {
|
|||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
userID: storedUser.ID,
|
userID: storedUser.ID,
|
||||||
productsID: id,
|
productID: id,
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
const data = await response.json();
|
||||||
if (!response.ok) throw new Error("Failed to fetch products");
|
if (data.success) {
|
||||||
|
setShowAlert(true);
|
||||||
|
}
|
||||||
console.log(response);
|
console.log(response);
|
||||||
console.log(`Add Product -> History: ${id}`);
|
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() {
|
function reloadPage() {
|
||||||
var doctTimestamp = new Date(performance.timing.domLoading).getTime();
|
var doctTimestamp = new Date(performance.timing.domLoading).getTime();
|
||||||
var now = Date.now();
|
var now = Date.now();
|
||||||
@@ -44,7 +64,6 @@ const Home = () => {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchrecomProducts = async () => {
|
const fetchrecomProducts = async () => {
|
||||||
// Get the user's data from localStorage
|
// Get the user's data from localStorage
|
||||||
const storedUser = JSON.parse(sessionStorage.getItem("user"));
|
|
||||||
console.log(storedUser);
|
console.log(storedUser);
|
||||||
try {
|
try {
|
||||||
const response = await fetch(
|
const response = await fetch(
|
||||||
@@ -126,7 +145,6 @@ const Home = () => {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchrecomProducts = async () => {
|
const fetchrecomProducts = async () => {
|
||||||
// Get the user's data from localStorage
|
// Get the user's data from localStorage
|
||||||
const storedUser = JSON.parse(sessionStorage.getItem("user"));
|
|
||||||
console.log(storedUser);
|
console.log(storedUser);
|
||||||
try {
|
try {
|
||||||
const response = await fetch(
|
const response = await fetch(
|
||||||
@@ -155,7 +173,6 @@ const Home = () => {
|
|||||||
image: product.ProductImage, // Use the alias for image URL
|
image: product.ProductImage, // Use the alias for image URL
|
||||||
seller: product.SellerName, // Fetch seller name properly
|
seller: product.SellerName, // Fetch seller name properly
|
||||||
datePosted: product.DateUploaded, // Use the actual date
|
datePosted: product.DateUploaded, // Use the actual date
|
||||||
isFavorite: false, // Default state
|
|
||||||
})),
|
})),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
@@ -169,18 +186,6 @@ const Home = () => {
|
|||||||
fetchrecomProducts();
|
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 = () => {
|
const handleSelling = () => {
|
||||||
navigate("/selling");
|
navigate("/selling");
|
||||||
};
|
};
|
||||||
@@ -218,6 +223,12 @@ const Home = () => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Recent Listings */}
|
{/* Recent Listings */}
|
||||||
|
{showAlert && (
|
||||||
|
<FloatingAlert
|
||||||
|
message="Product added to favorites!"
|
||||||
|
onClose={() => setShowAlert(false)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<div className="relative py-4">
|
<div className="relative py-4">
|
||||||
<h2 className="text-xl font-semibold text-gray-800 mb-4">
|
<h2 className="text-xl font-semibold text-gray-800 mb-4">
|
||||||
Recommendation
|
Recommendation
|
||||||
@@ -245,6 +256,7 @@ const Home = () => {
|
|||||||
<Link
|
<Link
|
||||||
key={recommended.id}
|
key={recommended.id}
|
||||||
to={`/product/${recommended.id}`}
|
to={`/product/${recommended.id}`}
|
||||||
|
onClick={() => addHistory(recommended.id)}
|
||||||
className="bg-white border border-gray-200 hover:shadow-md transition-shadow w-70 flex-shrink-0 relative"
|
className="bg-white border border-gray-200 hover:shadow-md transition-shadow w-70 flex-shrink-0 relative"
|
||||||
>
|
>
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
@@ -254,16 +266,14 @@ const Home = () => {
|
|||||||
className="w-full h-48 object-cover"
|
className="w-full h-48 object-cover"
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
onClick={(e) => toggleFavorite(recommended.id, e)}
|
onClick={(e) => {
|
||||||
className="absolute top-2 right-2 p-2 bg-white rounded-full shadow-sm"
|
e.stopPropagation();
|
||||||
|
e.preventDefault();
|
||||||
|
toggleFavorite(recommended.id);
|
||||||
|
}}
|
||||||
|
className="absolute top-2 right-2 p-2 bg-white rounded-full shadow-sm hover:bg-gray-100 transition"
|
||||||
>
|
>
|
||||||
<Heart
|
<span className="text-xl font-bold text-gray-600">+</span>
|
||||||
className={`h-6 w-6 ${
|
|
||||||
recommended.isFavorite
|
|
||||||
? "text-red-500 fill-red-500"
|
|
||||||
: "text-gray-400"
|
|
||||||
}`}
|
|
||||||
/>
|
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -308,6 +318,12 @@ const Home = () => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Recent Listings */}
|
{/* Recent Listings */}
|
||||||
|
{showAlert && (
|
||||||
|
<FloatingAlert
|
||||||
|
message="Product added to favorites!"
|
||||||
|
onClose={() => setShowAlert(false)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<div className="relative py-4">
|
<div className="relative py-4">
|
||||||
<h2 className="text-xl font-semibold text-gray-800 mb-4">
|
<h2 className="text-xl font-semibold text-gray-800 mb-4">
|
||||||
Recent Listings
|
Recent Listings
|
||||||
@@ -335,26 +351,24 @@ const Home = () => {
|
|||||||
<Link
|
<Link
|
||||||
key={listing.id}
|
key={listing.id}
|
||||||
to={`/product/${listing.id}`}
|
to={`/product/${listing.id}`}
|
||||||
onClick={() => handleLinkClick(listing.id)}
|
|
||||||
className="bg-white border border-gray-200 hover:shadow-md transition-shadow w-70 flex-shrink-0 relative"
|
className="bg-white border border-gray-200 hover:shadow-md transition-shadow w-70 flex-shrink-0 relative"
|
||||||
>
|
>
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<img
|
<img
|
||||||
src={listing.image}
|
src={listing.image}
|
||||||
alt={listing.title}
|
alt={listing.title}
|
||||||
|
onClick={() => addHistory(listing.id)}
|
||||||
className="w-full h-48 object-cover"
|
className="w-full h-48 object-cover"
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
onClick={(e) => toggleFavorite(listing.id, e)}
|
onClick={(e) => {
|
||||||
className="absolute top-2 right-2 p-2 bg-white rounded-full shadow-sm"
|
e.stopPropagation();
|
||||||
|
e.preventDefault();
|
||||||
|
toggleFavorite(listing.id);
|
||||||
|
}}
|
||||||
|
className="absolute top-2 right-2 p-2 bg-white rounded-full shadow-sm hover:bg-gray-100 transition"
|
||||||
>
|
>
|
||||||
<Heart
|
<span className="text-xl font-bold text-gray-600">+</span>
|
||||||
className={`h-6 w-6 ${
|
|
||||||
listing.isFavorite
|
|
||||||
? "text-red-500 fill-red-500"
|
|
||||||
: "text-gray-400"
|
|
||||||
}`}
|
|
||||||
/>
|
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -399,6 +413,12 @@ const Home = () => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Recent Listings */}
|
{/* Recent Listings */}
|
||||||
|
{showAlert && (
|
||||||
|
<FloatingAlert
|
||||||
|
message="Product added to favorites!"
|
||||||
|
onClose={() => setShowAlert(false)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<div className="relative py-4">
|
<div className="relative py-4">
|
||||||
<h2 className="text-xl font-semibold text-gray-800 mb-4">History</h2>
|
<h2 className="text-xl font-semibold text-gray-800 mb-4">History</h2>
|
||||||
|
|
||||||
@@ -433,16 +453,14 @@ const Home = () => {
|
|||||||
className="w-full h-48 object-cover"
|
className="w-full h-48 object-cover"
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
onClick={(e) => toggleFavorite(history.id, e)}
|
onClick={(e) => {
|
||||||
className="absolute top-2 right-2 p-2 bg-white rounded-full shadow-sm"
|
e.stopPropagation();
|
||||||
|
e.preventDefault();
|
||||||
|
toggleFavorite(history.id);
|
||||||
|
}}
|
||||||
|
className="absolute top-2 right-2 p-2 bg-white rounded-full shadow-sm hover:bg-gray-100 transition"
|
||||||
>
|
>
|
||||||
<Heart
|
<span className="text-xl font-bold text-gray-600">+</span>
|
||||||
className={`h-6 w-6 ${
|
|
||||||
history.isFavorite
|
|
||||||
? "text-red-500 fill-red-500"
|
|
||||||
: "text-gray-400"
|
|
||||||
}`}
|
|
||||||
/>
|
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect } from "react";
|
||||||
import { User, Lock, Trash2, History, Search, Shield } from "lucide-react";
|
import { User, Lock, Trash2, History, Search, Shield } from "lucide-react";
|
||||||
|
import FloatingAlert from "../components/FloatingAlert"; // adjust path if needed
|
||||||
|
|
||||||
const Settings = () => {
|
const Settings = () => {
|
||||||
const [userData, setUserData] = useState({
|
const [userData, setUserData] = useState({
|
||||||
@@ -16,6 +17,8 @@ const Settings = () => {
|
|||||||
|
|
||||||
const [isLoading, setIsLoading] = useState(true);
|
const [isLoading, setIsLoading] = useState(true);
|
||||||
const [error, setError] = useState(null);
|
const [error, setError] = useState(null);
|
||||||
|
const [showAlert, setShowAlert] = useState(false);
|
||||||
|
const storedUser = JSON.parse(sessionStorage.getItem("user"));
|
||||||
|
|
||||||
// Fetch user data when component mounts
|
// Fetch user data when component mounts
|
||||||
useEffect(() => {
|
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 () => {
|
const handleUpdateProfile = async () => {
|
||||||
try {
|
try {
|
||||||
// Ensure userId is present
|
// 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 () => {
|
const handleDeleteAccount = async () => {
|
||||||
if (
|
if (
|
||||||
window.confirm(
|
window.confirm(
|
||||||
@@ -416,6 +432,12 @@ const Settings = () => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Privacy Section */}
|
{/* Privacy Section */}
|
||||||
|
{showAlert && (
|
||||||
|
<FloatingAlert
|
||||||
|
message="Product removed from History!"
|
||||||
|
onClose={() => setShowAlert(false)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<div className="bg-white border border-gray-200 mb-6">
|
<div className="bg-white border border-gray-200 mb-6">
|
||||||
<div className="border-b border-gray-200 p-4">
|
<div className="border-b border-gray-200 p-4">
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
@@ -432,33 +454,12 @@ const Settings = () => {
|
|||||||
<div>
|
<div>
|
||||||
<h3 className="font-medium text-gray-800">Search History</h3>
|
<h3 className="font-medium text-gray-800">Search History</h3>
|
||||||
<p className="text-sm text-gray-500">
|
<p className="text-sm text-gray-500">
|
||||||
Delete all your search history on StudentMarket
|
Delete all your history on Market
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
onClick={() => handleDeleteHistory("search")}
|
onClick={() => removeHistory()}
|
||||||
className="bg-gray-100 hover:bg-gray-200 text-gray-700 font-medium py-2 px-4 flex items-center"
|
|
||||||
>
|
|
||||||
<Trash2 className="h-4 w-4 mr-1" />
|
|
||||||
Delete
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex justify-between items-center">
|
|
||||||
<div className="flex items-start">
|
|
||||||
<History className="h-5 w-5 text-gray-500 mr-2 mt-0.5" />
|
|
||||||
<div>
|
|
||||||
<h3 className="font-medium text-gray-800">
|
|
||||||
Browsing History
|
|
||||||
</h3>
|
|
||||||
<p className="text-sm text-gray-500">
|
|
||||||
Delete all your browsing history on StudentMarket
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<button
|
|
||||||
onClick={() => handleDeleteHistory("browsing")}
|
|
||||||
className="bg-gray-100 hover:bg-gray-200 text-gray-700 font-medium py-2 px-4 flex items-center"
|
className="bg-gray-100 hover:bg-gray-200 text-gray-700 font-medium py-2 px-4 flex items-center"
|
||||||
>
|
>
|
||||||
<Trash2 className="h-4 w-4 mr-1" />
|
<Trash2 className="h-4 w-4 mr-1" />
|
||||||
|
|||||||
Reference in New Issue
Block a user