added review functionality

This commit is contained in:
Mann Patel
2025-04-12 11:27:27 -06:00
parent d8ed58f572
commit 10f0469b56
6 changed files with 139 additions and 89 deletions

View File

@@ -14,6 +14,7 @@ exports.addToFavorite = async (req, res) => {
success: true,
message: "Product added to favorites successfully",
});
console.log(result);
} catch (error) {
console.error("Error adding favorite product:", error);
return res.json({ error: "Could not add favorite product" });

View File

@@ -8,6 +8,29 @@ const Home = () => {
const [recommended, setRecommended] = useState([]);
const [history, sethistory] = useState([]);
const [error, setError] = useState(null);
const storedUser = JSON.parse(sessionStorage.getItem("user"));
const handleLinkClick = async (id) => {
// Example: append to localStorage or call analytics
const response = await fetch(
"http://localhost:3030/api/product/add_fav_product",
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
userID: storedUser.ID,
productsID: id,
}),
},
);
if (!response.ok) throw new Error("Failed to fetch products");
console.log(response);
console.log(`Add Product -> History: ${id}`);
};
useEffect(() => {
const fetchrecomProducts = async () => {
@@ -298,6 +321,7 @@ const Home = () => {
<Link
key={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"
>
<div className="relative">

View File

@@ -14,7 +14,7 @@ const ProductDetail = () => {
reviews: null,
});
const [isFavorite, setIsFavorite] = useState(false);
const [showContactForm, setShowContactForm] = useState(false);
const [contactForm, showContactForm, setShowContactForm] = useState(false);
const [currentImage, setCurrentImage] = useState(0);
const [reviews, setReviews] = useState([]);
const [showReviewForm, setShowReviewForm] = useState(false);
@@ -417,81 +417,15 @@ const ProductDetail = () => {
</p>
</div>
<button
{/* <button
onClick={() => setShowContactForm(!showContactForm)}
className="w-full bg-green-500 hover:bg-green-600 text-white font-medium py-3 px-4 mb-3"
>
Contact Seller
</button>
{showContactForm && (
<div className="border border-gray-200 p-4 mb-4">
<h3 className="font-medium text-gray-800 mb-2">
Contact Seller
</h3>
<form onSubmit={handleSendMessage}>
<div className="mb-3">
<label htmlFor="email" className="block text-gray-700 mb-1">
Email <span className="text-red-500">*</span>
</label>
<input
type="email"
id="email"
value={contactForm.email}
onChange={handleContactInputChange}
className="w-full p-3 border border-gray-300 focus:outline-none focus:border-green-500"
required
/>
</div>
<div className="mb-3">
<label htmlFor="phone" className="block text-gray-700 mb-1">
Phone Number <span className="text-red-500">*</span>
</label>
<input
type="tel"
id="phone"
value={contactForm.phone}
onChange={handleContactInputChange}
className="w-full p-3 border border-gray-300 focus:outline-none focus:border-green-500"
required
/>
</div>
<div className="mb-3">
<label
htmlFor="message"
className="block text-gray-700 mb-1"
>
Message
</label>
<textarea
id="message"
value={contactForm.message}
onChange={handleContactInputChange}
placeholder="Hi, is this item still available?"
className="w-full p-3 border border-gray-300 focus:outline-none focus:border-green-500"
rows="3"
/>
</div>
<div className="flex justify-between">
<button
type="submit"
className="bg-green-500 hover:bg-green-600 text-white font-medium py-2 px-4"
>
Send Contact Info
</button>
<button
type="button"
onClick={() => setShowContactForm(false)}
className="bg-gray-200 hover:bg-gray-300 text-gray-800 font-medium py-2 px-4"
>
Cancel
</button>
</div>
</form>
</div>
)}
</button> */}
<div className="pt-4 border-t border-gray-200">
{/* Seller Info */}
<div className="flex items-center mb-3">
<div className="mr-3">
<div className="h-12 w-12 rounded-full bg-gray-200 flex items-center justify-center">
@@ -507,23 +441,33 @@ const ProductDetail = () => {
</p>
</div>
</div>
<div className="text-sm text-gray-600">
<div>
<span className="font-medium">Rating:</span>{" "}
{product.seller?.rating ? (
<div className="flex items-center">
{renderStars(product.seller.rating)}
<span className="ml-1">{product.seller.rating}/5</span>
{/* 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>
) : (
"N/A"
)}
</div>
</div>
</div>
</div>
</div>
</div>
{/* Reviews Section */}
<div className="mt-8">

View File

@@ -415,6 +415,60 @@ const Settings = () => {
</div>
</div>
{/* Privacy Section */}
<div className="bg-white border border-gray-200 mb-6">
<div className="border-b border-gray-200 p-4">
<div className="flex items-center">
<Shield className="h-5 w-5 text-gray-500 mr-2" />
<h2 className="text-lg font-medium text-gray-800">Privacy</h2>
</div>
</div>
<div className="p-4">
<div className="space-y-4">
<div className="flex justify-between items-center pb-4 border-b border-gray-100">
<div className="flex items-start">
<Search className="h-5 w-5 text-gray-500 mr-2 mt-0.5" />
<div>
<h3 className="font-medium text-gray-800">Search History</h3>
<p className="text-sm text-gray-500">
Delete all your search history on StudentMarket
</p>
</div>
</div>
<button
onClick={() => handleDeleteHistory("search")}
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"
>
<Trash2 className="h-4 w-4 mr-1" />
Delete
</button>
</div>
</div>
</div>
</div>
{/* Delete Account (Danger Zone) */}
<div className="bg-white border border-red-200 mb-6">
<div className="border-b border-red-200 p-4 bg-red-50">

View File

@@ -1,4 +1,6 @@
# pip install mysql.connector
#
import mysql.connector
from sklearn.metrics.pairwise import cosine_similarity
@@ -15,6 +17,28 @@ def database():
)
return db_connection
def get_popular_products():
pass
def delete_user_recommendation(userID, Array):
db_con = database()
cursor = db_con.cursor()
try:
for item in Array:
#Product ID starts form index 1
item_value = item + 1
print(item_value)
# Use parameterized queries to prevent SQL injection
cursor.execute(f"INTO Recommendation (UserID, RecommendedProductID) VALUES ({userID}, {item_value});")
db_con.commit()
#results = cursor.fetchall()
#print(results)
except:
pass
def get_all_products():
@@ -89,9 +113,9 @@ def get_recommendations(user_id, top_n=10):
# Get all products and user history with their category vectors
all_products = get_all_products()
user_history = get_user_history(user_id)
# if not user_history:
# # Cold start: return popular products
# return get_popular_products(top_n)
if not user_history:
#Cold start: return popular products
return get_popular_products(top_n)
# Calculate similarity between all products and user history
user_profile = np.mean(user_history, axis=0) # Average user preferences
similarities = cosine_similarity([user_profile], all_products)

View File

@@ -1,9 +1,12 @@
from flask import Flask, request, jsonify
from flask_cors import CORS
from app import get_recommendations
from app import history_upload
import time
#import time
app = Flask(__name__)