add review and read review now done

This commit is contained in:
Mann Patel
2025-04-12 13:10:17 -06:00
parent 0e32389482
commit 0f8bb622a4
16 changed files with 408 additions and 196 deletions

View File

@@ -37,7 +37,6 @@ exports.HistoryByUserId = async (req, res) => {
[id], [id],
); );
console.log(data);
res.json({ res.json({
success: true, success: true,
message: "Products fetched successfully", message: "Products fetched successfully",

View File

@@ -1,12 +1,12 @@
const db = require("../utils/database"); const db = require("../utils/database");
exports.addToFavorite = async (req, res) => { exports.addFavorite = async (req, res) => {
const { userID, productsID } = req.body; const { userID, productsID } = req.body;
try { try {
// Use parameterized query to prevent SQL injection // Use parameterized query to prevent SQL injection
const [result] = await db.execute( const [result] = await db.execute(
"INSERT INTO Favorites (UserID, ProductID) VALUES unique(?, ?)", "INSERT INTO Favorites (UserID, ProductID) VALUES (?, ?)",
[userID, productsID], [userID, productsID],
); );
@@ -14,13 +14,41 @@ exports.addToFavorite = async (req, res) => {
success: true, success: true,
message: "Product added to favorites successfully", message: "Product added to favorites successfully",
}); });
console.log(result);
} catch (error) { } catch (error) {
console.error("Error adding favorite product:", error); console.error("Error adding favorite product:", error);
return res.json({ error: "Could not add favorite product" }); return res.json({ error: "Could not add favorite product" });
} }
}; };
exports.getFavorites = async (req, res) => {
const { userID } = req.body;
try {
const [favorites] = await db.execute(
`
SELECT
p.*,
u.Name AS SellerName,
i.URL AS image_url
FROM Favorites f
JOIN Product p ON f.ProductID = p.ProductID
JOIN User u ON p.UserID = u.UserID
LEFT JOIN Image_URL i ON p.ProductID = i.ProductID
WHERE f.UserID = ?
`,
[userID],
);
res.json({
success: true,
favorites: favorites,
});
} catch (error) {
console.error("Error retrieving favorites:", error);
res.status(500).json({ error: "Could not retrieve favorite products" });
}
};
// Get all products along with their image URLs // Get all products along with their image URLs
exports.getAllProducts = async (req, res) => { exports.getAllProducts = async (req, res) => {
try { try {
@@ -52,7 +80,6 @@ exports.getAllProducts = async (req, res) => {
WHERE RowNum = 1; WHERE RowNum = 1;
`); `);
console.log(data);
res.json({ res.json({
success: true, success: true,
message: "Products fetched successfully", message: "Products fetched successfully",
@@ -74,7 +101,7 @@ exports.getProductById = async (req, res) => {
try { try {
const [data] = await db.execute( const [data] = await db.execute(
` `
SELECT p.*,U.Name AS SellerName, i.URL AS image_url SELECT p.*,U.Name AS SellerName,U.Email as SellerEmail,U.Phone as SellerPhone, i.URL AS image_url
FROM Product p FROM Product p
LEFT JOIN Image_URL i ON p.ProductID = i.ProductID LEFT JOIN Image_URL i ON p.ProductID = i.ProductID
JOIN User U ON p.UserID = U.UserID JOIN User U ON p.UserID = U.UserID

View File

@@ -1,13 +1,17 @@
const db = require("../utils/database"); const db = require("../utils/database");
exports.getreview = async (req, res) => { /**
* Get reviews for a specific product
* Returns both reviews for the product and reviews by the product owner for other products
*/
exports.getReviews = async (req, res) => {
const { id } = req.params; const { id } = req.params;
console.log("Received Product ID:", id); console.log("Received Product ID:", id);
try { try {
const [data] = await db.execute( // First query: Get reviews for this specific product
` const [productReviews] = await db.execute(
SELECT `SELECT
R.ReviewID, R.ReviewID,
R.UserID, R.UserID,
R.ProductID, R.ProductID,
@@ -15,44 +19,49 @@ exports.getreview = async (req, res) => {
R.Rating, R.Rating,
R.Date AS ReviewDate, R.Date AS ReviewDate,
U.Name AS ReviewerName, U.Name AS ReviewerName,
P.Name AS ProductName P.Name AS ProductName,
'product' AS ReviewType
FROM Review R FROM Review R
JOIN User U ON R.UserID = U.UserID JOIN User U ON R.UserID = U.UserID
JOIN Product P ON R.ProductID = P.ProductID JOIN Product P ON R.ProductID = P.ProductID
WHERE R.ProductID = ? WHERE R.ProductID = ?`,
[id],
UNION
SELECT
R.ReviewID,
R.UserID,
R.ProductID,
R.Comment,
R.Rating,
R.Date AS ReviewDate,
U.Name AS ReviewerName,
P.Name AS ProductName
FROM Review R
JOIN User U ON R.UserID = U.UserID
JOIN Product P ON R.ProductID = P.ProductID
WHERE P.UserID = (
SELECT UserID
FROM Product
WHERE ProductID = ?
)
AND R.UserID != P.UserID;
`,
[id, id],
); );
// Log raw data for debugging // // Second query: Get reviews written by the product owner for other products
console.log("Raw Database Result:", data); // const [sellerReviews] = await db.execute(
// `SELECT
// R.ReviewID,
// R.UserID,
// R.ProductID,
// R.Comment,
// R.Rating,
// R.Date AS ReviewDate,
// U.Name AS ReviewerName,
// P.Name AS ProductName,
// 'seller' AS ReviewType
// FROM Review R
// JOIN User U ON R.UserID = U.UserID
// JOIN Product P ON R.ProductID = P.ProductID
// WHERE R.UserID = (
// SELECT UserID
// FROM Product
// WHERE ProductID = ?
// )
// AND R.ProductID != ?`,
// [id, id],
// );
// Combine the results
const combinedReviews = [...productReviews];
// Log data for debugging
console.log("Combined Reviews:", combinedReviews);
console.log(data);
res.json({ res.json({
success: true, success: true,
message: "Products fetched successfully", message: "Reviews fetched successfully",
data, data: combinedReviews,
}); });
} catch (error) { } catch (error) {
console.error("Full Error Details:", error); console.error("Full Error Details:", error);
@@ -64,7 +73,9 @@ exports.getreview = async (req, res) => {
} }
}; };
// Add this to your existing controller file /**
* Submit a new review for a product
*/
exports.submitReview = async (req, res) => { exports.submitReview = async (req, res) => {
const { productId, userId, rating, comment } = req.body; const { productId, userId, rating, comment } = req.body;
@@ -85,16 +96,41 @@ exports.submitReview = async (req, res) => {
} }
try { try {
// Check if user has already reviewed this product
const [existingReview] = await db.execute(
`SELECT ReviewID FROM Review WHERE ProductID = ? AND UserID = ?`,
[productId, userId],
);
if (existingReview.length > 0) {
return res.status(400).json({
success: false,
message: "You have already reviewed this product",
});
}
// Check if user is trying to review their own product
const [productOwner] = await db.execute(
`SELECT UserID FROM Product WHERE ProductID = ?`,
[productId],
);
if (productOwner.length > 0 && productOwner[0].UserID === userId) {
return res.status(400).json({
success: false,
message: "You cannot review your own product",
});
}
// Insert the review into the database // Insert the review into the database
const [result] = await db.execute( const [result] = await db.execute(
` `INSERT INTO Review (
INSERT INTO Review (
ProductID, ProductID,
UserID, UserID,
Rating, Rating,
Comment Comment,
) VALUES (?, ?, ?, ?) Date
`, ) VALUES (?, ?, ?, ?, NOW())`,
[productId, userId, rating, comment], [productId, userId, rating, comment],
); );
@@ -103,22 +139,24 @@ exports.submitReview = async (req, res) => {
// Fetch the newly created review to return to client // Fetch the newly created review to return to client
const [newReview] = await db.execute( const [newReview] = await db.execute(
` `SELECT
SELECT R.ReviewID,
ReviewID as id, R.ProductID,
ProductID, R.UserID,
UserID, R.Rating,
Rating, R.Comment,
Comment, R.Date AS ReviewDate,
Date as ReviewDate U.Name AS ReviewerName,
FROM Review P.Name AS ProductName
WHERE ReviewID = ? FROM Review R
`, JOIN User U ON R.UserID = U.UserID
JOIN Product P ON R.ProductID = P.ProductID
WHERE R.ReviewID = ?`,
[reviewId], [reviewId],
); );
res.status(201).json({ res.status(201).json({
success: false, success: true, // Fixed from false to true
message: "Review submitted successfully", message: "Review submitted successfully",
data: newReview[0], data: newReview[0],
}); });
@@ -131,3 +169,134 @@ exports.submitReview = async (req, res) => {
}); });
} }
}; };
// /**
// * Update an existing review
// */
// exports.updateReview = async (req, res) => {
// const { reviewId } = req.params;
// const { rating, comment } = req.body;
// const userId = req.body.userId; // Assuming you have middleware that validates the user
// // Validate required fields
// if (!reviewId || !rating || !comment) {
// return res.status(400).json({
// success: false,
// message: "Missing required fields",
// });
// }
// // Validate rating is between 1 and 5
// if (rating < 1 || rating > 5) {
// return res.status(400).json({
// success: false,
// message: "Rating must be between 1 and 5",
// });
// }
// try {
// // Check if review exists and belongs to the user
// const [existingReview] = await db.execute(
// `SELECT ReviewID, UserID FROM Review WHERE ReviewID = ?`,
// [reviewId],
// );
// if (existingReview.length === 0) {
// return res.status(404).json({
// success: false,
// message: "Review not found",
// });
// }
// if (existingReview[0].UserID !== userId) {
// return res.status(403).json({
// success: false,
// message: "You can only update your own reviews",
// });
// }
// // Update the review
// await db.execute(
// `UPDATE Review
// SET Rating = ?, Comment = ?, Date = NOW()
// WHERE ReviewID = ?`,
// [rating, comment, reviewId],
// );
// // Fetch the updated review
// const [updatedReview] = await db.execute(
// `SELECT
// R.ReviewID,
// R.ProductID,
// R.UserID,
// R.Rating,
// R.Comment,
// R.Date AS ReviewDate,
// U.Name AS ReviewerName,
// P.Name AS ProductName
// FROM Review R
// JOIN User U ON R.UserID = U.UserID
// JOIN Product P ON R.ProductID = P.ProductID
// WHERE R.ReviewID = ?`,
// [reviewId],
// );
// res.json({
// success: true,
// message: "Review updated successfully",
// data: updatedReview[0],
// });
// } catch (error) {
// console.error("Error updating review:", error);
// return res.status(500).json({
// success: false,
// message: "Database error occurred",
// error: error.message,
// });
// }
// };
// /**
// * Delete a review
// */
// exports.deleteReview = async (req, res) => {
// const { reviewId } = req.params;
// const userId = req.body.userId; // Assuming you have middleware that validates the user
// try {
// // Check if review exists and belongs to the user
// const [existingReview] = await db.execute(
// `SELECT ReviewID, UserID FROM Review WHERE ReviewID = ?`,
// [reviewId],
// );
// if (existingReview.length === 0) {
// return res.status(404).json({
// success: false,
// message: "Review not found",
// });
// }
// if (existingReview[0].UserID !== userId) {
// return res.status(403).json({
// success: false,
// message: "You can only delete your own reviews",
// });
// }
// // Delete the review
// await db.execute(`DELETE FROM Review WHERE ReviewID = ?`, [reviewId]);
// res.json({
// success: true,
// message: "Review deleted successfully",
// });
// } catch (error) {
// console.error("Error deleting review:", error);
// return res.status(500).json({
// success: false,
// message: "Database error occurred",
// error: error.message,
// });
// }
// };

View File

@@ -39,9 +39,9 @@ checkDatabaseConnection(db);
//Routes //Routes
app.use("/api/user", userRouter); //prefix with /api/user app.use("/api/user", userRouter); //prefix with /api/user
app.use("/api/product", productRouter); //prefix with /api/product app.use("/api/product", productRouter); //prefix with /api/product
app.use("/api/search_products", searchRouter); //prefix with /api/product app.use("/api/search", searchRouter); //prefix with /api/product
app.use("/api/Engine", recommendedRouter); //prefix with /api/ app.use("/api/engine", recommendedRouter); //prefix with /api/
app.use("/api/get", history); //prefix with /api/ app.use("/api/history", history); //prefix with /api/
app.use("/api/review", review); //prefix with /api/ app.use("/api/review", review); //prefix with /api/
// Set up a scheduler to run cleanup every hour // Set up a scheduler to run cleanup every hour

View File

@@ -3,6 +3,6 @@ const express = require("express");
const { HistoryByUserId } = require("../controllers/history"); const { HistoryByUserId } = require("../controllers/history");
const router = express.Router(); const router = express.Router();
router.post("/history", HistoryByUserId); router.post("/getHistory", HistoryByUserId);
module.exports = router; module.exports = router;

View File

@@ -1,7 +1,8 @@
// routes/product.js // routes/product.js
const express = require("express"); const express = require("express");
const { const {
addToFavorite, addFavorite,
getFavorites,
getAllProducts, getAllProducts,
getProductById, getProductById,
} = require("../controllers/product"); } = require("../controllers/product");
@@ -13,8 +14,10 @@ router.use((req, res, next) => {
next(); next();
}); });
router.post("/add_fav_product", addToFavorite); router.post("/addFavorite", addFavorite);
router.get("/get_product", getAllProducts); router.post("/getFavorites", getFavorites);
router.get("/getProduct", getAllProducts);
router.get("/:id", getProductById); // Simplified route router.get("/:id", getProductById); // Simplified route
module.exports = router; module.exports = router;

View File

@@ -1,9 +1,9 @@
// routes/product.js // routes/product.js
const express = require("express"); const express = require("express");
const { getreview, submitReview } = require("../controllers/review"); const { getReviews, submitReview } = require("../controllers/review");
const router = express.Router(); const router = express.Router();
router.get("/:id", getreview); router.get("/:id", getReviews);
router.post("/add", submitReview); router.post("/add", submitReview);
module.exports = router; module.exports = router;

View File

@@ -9,6 +9,6 @@ router.use((req, res, next) => {
next(); next();
}); });
router.get("/search", searchProductsByName); router.get("/getProduct", searchProductsByName);
module.exports = router; module.exports = router;

View File

@@ -11,9 +11,8 @@ const Home = () => {
const storedUser = JSON.parse(sessionStorage.getItem("user")); const storedUser = JSON.parse(sessionStorage.getItem("user"));
const handleLinkClick = async (id) => { const handleLinkClick = async (id) => {
// Example: append to localStorage or call analytics
const response = await fetch( const response = await fetch(
"http://localhost:3030/api/product/add_fav_product", "http://localhost:3030/api/product/addFavorites",
{ {
method: "POST", method: "POST",
headers: { headers: {
@@ -32,6 +31,16 @@ const Home = () => {
console.log(`Add Product -> History: ${id}`); console.log(`Add Product -> History: ${id}`);
}; };
function reloadPage() {
var doctTimestamp = new Date(performance.timing.domLoading).getTime();
var now = Date.now();
var tenSec = 10 * 1000;
if (now > doctTimestamp + tenSec) {
location.reload();
}
}
reloadPage();
useEffect(() => { useEffect(() => {
const fetchrecomProducts = async () => { const fetchrecomProducts = async () => {
// Get the user's data from localStorage // Get the user's data from localStorage
@@ -76,13 +85,15 @@ const Home = () => {
} }
}; };
fetchrecomProducts(); fetchrecomProducts();
//reloadPage();
}, []); }, []);
reloadPage();
useEffect(() => { useEffect(() => {
const fetchProducts = async () => { const fetchProducts = async () => {
try { try {
const response = await fetch( const response = await fetch(
"http://localhost:3030/api/product/get_product", "http://localhost:3030/api/product/getProduct",
); );
if (!response.ok) throw new Error("Failed to fetch products"); if (!response.ok) throw new Error("Failed to fetch products");
@@ -118,15 +129,18 @@ const Home = () => {
const storedUser = JSON.parse(sessionStorage.getItem("user")); const storedUser = JSON.parse(sessionStorage.getItem("user"));
console.log(storedUser); console.log(storedUser);
try { try {
const response = await fetch("http://localhost:3030/api/get/history", { const response = await fetch(
method: "POST", "http://localhost:3030/api/history/getHistory",
headers: { {
"Content-Type": "application/json", method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
id: storedUser.ID,
}),
}, },
body: JSON.stringify({ );
id: storedUser.ID,
}),
});
if (!response.ok) throw new Error("Failed to fetch products"); if (!response.ok) throw new Error("Failed to fetch products");
const data = await response.json(); const data = await response.json();

View File

@@ -1,6 +1,15 @@
import { useState, useEffect, setErrors } from "react"; import { useState, useEffect } from "react";
import { useParams, Link, isSession } from "react-router-dom"; import { useParams, Link } from "react-router-dom";
import { Heart, ArrowLeft, Tag, User, Calendar, Star } from "lucide-react"; import {
Heart,
ArrowLeft,
Tag,
User,
Calendar,
Star,
Phone,
Mail,
} from "lucide-react";
const ProductDetail = () => { const ProductDetail = () => {
const { id } = useParams(); const { id } = useParams();
@@ -8,16 +17,19 @@ const ProductDetail = () => {
const [loading, setLoading] = useState({ const [loading, setLoading] = useState({
product: true, product: true,
reviews: true, reviews: true,
submitting: false,
}); });
const [error, setError] = useState({ const [error, setError] = useState({
product: null, product: null,
reviews: null, reviews: null,
submit: null,
}); });
const [isFavorite, setIsFavorite] = useState(false); const [isFavorite, setIsFavorite] = useState(false);
const [contactForm, showContactForm, setShowContactForm] = useState(false); const [showContactOptions, setShowContactOptions] = useState(false);
const [currentImage, setCurrentImage] = useState(0); const [currentImage, setCurrentImage] = useState(0);
const [reviews, setReviews] = useState([]); const [reviews, setReviews] = useState([]);
const [showReviewForm, setShowReviewForm] = useState(false); const [showReviewForm, setShowReviewForm] = useState(false);
const storedUser = JSON.parse(sessionStorage.getItem("user"));
const [reviewForm, setReviewForm] = useState({ const [reviewForm, setReviewForm] = useState({
rating: 3, rating: 3,
@@ -42,39 +54,70 @@ const ProductDetail = () => {
})); }));
}; };
const handleSubmitReview = async () => { const handleSubmitReview = async (e) => {
try { e.preventDefault(); // Prevent form default behavior
// Ensure userId is present
if (!userData.userId) {
throw new Error("User ID is missing. Unable to update profile.");
}
setIsLoading(true); try {
setError(null); setLoading((prev) => ({ ...prev, submitting: true }));
setError((prev) => ({ ...prev, submit: null }));
const reviewData = {
productId: id,
rating: reviewForm.rating,
comment: reviewForm.comment,
userId: storedUser.ID,
};
const response = await fetch(`http://localhost:3030/api/review/add`, { const response = await fetch(`http://localhost:3030/api/review/add`, {
method: "POST", // or "PUT" if your backend supports it method: "POST",
headers: { headers: { "Content-Type": "application/json" },
"Content-Type": "application/json", body: JSON.stringify(reviewData),
},
body: JSON.stringify(userData),
}); });
const result = await response.json(); const result = await response.json();
if (!response.ok) { // Check if API returned an error message even with 200 status
throw new Error(result.error || "Failed to update profile"); if (!result.success) {
throw new Error(result.message || "Failed to submit review");
} }
console.log("Profile updated successfully:", result); alert("Review submitted successfully!");
alert("Profile updated successfully!");
setReviewForm({
rating: 3,
comment: "",
name: "",
});
setShowReviewForm(false);
try {
setLoading((prev) => ({ ...prev, reviews: true }));
const reviewsResponse = await fetch(
`http://localhost:3030/api/review/${id}`,
);
const reviewsResult = await reviewsResponse.json();
if (reviewsResult.success) {
setReviews(reviewsResult.data || []);
setError((prev) => ({ ...prev, reviews: null }));
} else {
throw new Error(reviewsResult.message || "Error fetching reviews");
}
} catch (reviewsError) {
console.error("Error fetching reviews:", reviewsError);
setError((prev) => ({ ...prev, reviews: reviewsError.message }));
} finally {
setLoading((prev) => ({ ...prev, reviews: false }));
}
} catch (error) { } catch (error) {
console.error("Error updating profile:", error); console.error("Error submitting review:", error);
setError( alert(`Error: ${error.message}`);
error.message || "An error occurred while updating your profile.", setError((prev) => ({
); ...prev,
submit: error.message,
}));
} finally { } finally {
setIsLoading(false); setLoading((prev) => ({ ...prev, submitting: false }));
} }
}; };
@@ -172,48 +215,6 @@ const ProductDetail = () => {
} }
}; };
// Handle form input changes
const handleContactInputChange = (e) => {
const { id, value } = e.target;
setContactForm((prev) => ({
...prev,
[id]: value,
}));
};
// Handle message submission with improved validation
const handleSendMessage = (e) => {
e.preventDefault();
// Basic validation
if (!contactForm.email || !contactForm.phone) {
alert("Please fill in all required fields");
return;
}
// Email validation
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(contactForm.email)) {
alert("Please enter a valid email address");
return;
}
// TODO: Implement actual message sending logic
try {
// Mock API call
console.log("Message sent:", contactForm);
setContactForm({
email: "",
phone: "",
message: "Hi, is this item still available?",
});
setShowContactForm(false);
alert("Message sent to seller!");
} catch (error) {
alert(`Failed to send message: ${error.message}`);
}
};
// Image navigation // Image navigation
const nextImage = () => { const nextImage = () => {
if (product?.images?.length > 0) { if (product?.images?.length > 0) {
@@ -417,12 +418,38 @@ const ProductDetail = () => {
</p> </p>
</div> </div>
{/* <button <div className="relative">
onClick={() => setShowContactForm(!showContactForm)} <button
className="w-full bg-green-500 hover:bg-green-600 text-white font-medium py-3 px-4 mb-3" onClick={() => setShowContactOptions(!showContactOptions)}
> className="w-full bg-green-500 hover:bg-green-600 text-white font-medium py-3 px-4 mb-3"
Contact Seller >
</button> */} Contact Seller
</button>
{showContactOptions && (
<div className="absolute z-10 w-full bg-white border border-gray-200 shadow-md">
{product.SellerPhone && (
<a
href={`tel:${product.SellerPhone}`}
className="flex items-center gap-2 p-3 hover:bg-gray-50 border-b border-gray-100"
>
<Phone className="h-5 w-5 text-green-500" />
<span>Call Seller</span>
</a>
)}
{product.SellerEmail && (
<a
href={`mailto:${product.SellerEmail}`}
className="flex items-center gap-2 p-3 hover:bg-gray-50"
>
<Mail className="h-5 w-5 text-green-500" />
<span>Email Seller</span>
</a>
)}
</div>
)}
</div>
<div className="pt-4 border-t border-gray-200"> <div className="pt-4 border-t border-gray-200">
{/* Seller Info */} {/* Seller Info */}
@@ -441,29 +468,6 @@ const ProductDetail = () => {
</p> </p>
</div> </div>
</div> </div>
{/* Contact Options */}
{showContactForm && (
<div className="mt-4 border border-gray-200 p-4">
<h3 className="font-medium text-gray-800 mb-2">
Contact Seller
</h3>
<div className="flex flex-col sm:flex-row gap-3">
<a
href={`tel:${contactForm.phone}`}
className="bg-green-500 hover:bg-green-600 text-white font-medium py-2 px-4 text-center "
>
Call Seller
</a>
<a
href={`mailto:${contactForm.email}`}
className="bg-green-500 hover:bg-green-600 text-white font-medium py-2 px-4 text-center "
>
Email Seller
</a>
</div>
</div>
)}
</div> </div>
</div> </div>
</div> </div>
@@ -495,7 +499,7 @@ const ProductDetail = () => {
> >
<div className="flex justify-between mb-2"> <div className="flex justify-between mb-2">
<div className="font-medium text-gray-800"> <div className="font-medium text-gray-800">
{review.ReviewerName || "Anonymous"} {review.ReviewerName}
</div> </div>
<div className="text-sm text-gray-500"> <div className="text-sm text-gray-500">
{review.ReviewDate {review.ReviewDate
@@ -546,20 +550,6 @@ const ProductDetail = () => {
</div> </div>
<form onSubmit={handleSubmitReview}> <form onSubmit={handleSubmitReview}>
<div className="mb-4">
<label htmlFor="name" className="block text-gray-700 mb-1">
Your Name <span className="text-red-500">*</span>
</label>
<input
type="text"
id="name"
value={reviewForm.name}
onChange={handleReviewInputChange}
className="w-full p-3 border border-gray-300 rounded focus:outline-none focus:border-green-500"
required
/>
</div>
<div className="mb-4"> <div className="mb-4">
<label className="block text-gray-700 mb-1"> <label className="block text-gray-700 mb-1">
Rating <span className="text-red-500">*</span> Rating <span className="text-red-500">*</span>
@@ -612,8 +602,9 @@ const ProductDetail = () => {
<button <button
type="submit" type="submit"
className="px-4 py-2 bg-green-500 text-white rounded hover:bg-green-600" className="px-4 py-2 bg-green-500 text-white rounded hover:bg-green-600"
disabled={loading.submitting}
> >
Submit Review {loading.submitting ? "Submitting..." : "Submit Review"}
</button> </button>
</div> </div>
</form> </form>

View File

@@ -27,7 +27,7 @@ const SearchPage = () => {
try { try {
const response = await axios.get( const response = await axios.get(
`http://localhost:3030/api/search_products/search`, `http://localhost:3030/api/search/getProduct`,
{ {
params: { name: query }, params: { name: query },
}, },

View File

@@ -101,7 +101,8 @@ CREATE TABLE Favorites (
UserID INT, UserID INT,
ProductID INT, ProductID INT,
FOREIGN KEY (UserID) REFERENCES User (UserID), FOREIGN KEY (UserID) REFERENCES User (UserID),
FOREIGN KEY (ProductID) REFERENCES Product (ProductID) FOREIGN KEY (ProductID) REFERENCES Product (ProductID),
UNIQUE (UserID, ProductID) -- Prevents duplicate favorites
); );
-- Product-Category Junction Table (Many-to-Many) -- Product-Category Junction Table (Many-to-Many)

6
package-lock.json generated Normal file
View File

@@ -0,0 +1,6 @@
{
"name": "Campus-Plug",
"lockfileVersion": 3,
"requires": true,
"packages": {}
}

View File

@@ -108,6 +108,10 @@ def get_user_history(user_id):
return final return final
def delete_user_recommendations(userId):
pass
def get_recommendations(user_id, top_n=10): def get_recommendations(user_id, top_n=10):
try: try:
# Get all products and user history with their category vectors # Get all products and user history with their category vectors

View File

@@ -6,8 +6,6 @@ from flask import Flask, request, jsonify
from flask_cors import CORS from flask_cors import CORS
from app import get_recommendations from app import get_recommendations
#import time
app = Flask(__name__) app = Flask(__name__)
CORS(app) # Enable CORS for all routes CORS(app) # Enable CORS for all routes