Skip to content
Snippets Groups Projects
Commit 0fcad898 authored by Huang, Ench (UG - Comp Sci & Elec Eng)'s avatar Huang, Ench (UG - Comp Sci & Elec Eng)
Browse files

Cleaned up code and connected main api point to frontend

cleaned up suggestions.js file, currently using dummy data in response, the userId in request query is also hardcoded, need to be addressed later on
parent fa4b7fb0
No related branches found
No related tags found
No related merge requests found
...@@ -5,4 +5,5 @@ microservice-users/__pycache__/main.cpython-311.pyc ...@@ -5,4 +5,5 @@ microservice-users/__pycache__/main.cpython-311.pyc
api-gateway/__pycache__/main.cpython-313.pyc api-gateway/__pycache__/main.cpython-313.pyc
microservice-products/__pycache__/main.cpython-313.pyc microservice-products/__pycache__/main.cpython-313.pyc
frontend/node_modules frontend/node_modules
frontend/.vite frontend/.vite
\ No newline at end of file node_modules
\ No newline at end of file
// apiService.js
export const handleRecommendedEvents = async (userId: any) => {
try {
const res = await fetch(`http://localhost:8005/suggestions?userId=${userId}`);
const data = await res.json(); // or res.json() if it's JSON
return data;
} catch (err:any) {
return `Error: ${err.message}`;
}
};
\ No newline at end of file
import { useState, useEffect } from 'react' import { useState, useEffect } from 'react'
import { handleRecommendedEvents } from './RecommendationService'
import './Recommendations.css' import './Recommendations.css'
function RecommendationList(){ function RecommendationList(){
...@@ -16,18 +17,20 @@ function RecommendationList(){ ...@@ -16,18 +17,20 @@ function RecommendationList(){
const [error, setError] = useState(null); const [error, setError] = useState(null);
useEffect(() => { useEffect(() => {
const fetchEvents = async () => { const fetchEvents = async () => {
try { try {
setRecommendation(fakeEvents) const userId = '55555'
const data = await handleRecommendedEvents(userId);
setRecommendation(data);
} catch (err) { } catch (err) {
setError(err.message); // Catch errors and set error state setError(err.message);
} finally { } finally {
setLoading(false); // Stop loading setLoading(false);
} }
}; };
fetchEvents(); fetchEvents();
}, []); }, []);
if (loading) return <div>Loading...</div>; if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error}</div>; if (error) return <div>Error: {error}</div>;
...@@ -36,13 +39,12 @@ function RecommendationList(){ ...@@ -36,13 +39,12 @@ function RecommendationList(){
<> <>
<h1>Recommendations</h1> <h1>Recommendations</h1>
<ul className='rcmd-list'> <ul className='rcmd-list'>
{recommendations.map((recommendation)=>( {recommendations.map((recommendation, index) => (
<li key={recommendation.id} className='rcmd-event'> <li key={index} className='rcmd-event'>
<h3>{recommendation.name}</h3> <h3>{recommendation.name}</h3>
<p>P{recommendation.date}</p> {recommendation.score && <p>Score: {recommendation.score}</p>}
<p>{recommendation.location}</p> </li>
</li> ))}
))}
</ul> </ul>
</> </>
) )
......
...@@ -13,53 +13,62 @@ const User = require('../models/users'); ...@@ -13,53 +13,62 @@ const User = require('../models/users');
router.get('/', async (req, res)=>{ router.get('/', async (req, res)=>{
try { try {
const {userId} = req.query // Extract userId from query
if(!userId) return res.status(400).json({message:'Missing user ID'}) const { userId } = req.query;
const user = await User.findOne({userId}) console.log('Hardcoded userId from frontend:', userId);
if(!user) return res.status(400).json({message: 'User not found!'})
// === PLACEHOLDER: Validate userId and find user ===
//find events that have matching tags to the users liked tags // if (!userId) return res.status(400).json({ message: 'Missing user ID' });
const likedTags = user.likedTags;
// $in is a mongoDB operator that matches values in an array field // const user = await User.findOne({ userId });
// tags is the name of the field to query, likedTags are what we are interested in // if (!user) return res.status(400).json({ message: 'User not found!' });
// this will return any event that has at least one match with the users liked tags
let events = await Event.find({tags: {$in:likedTags}}) // === DUMMY: Simulated liked tags for the user ===
const likedTags = ['tech', 'music', 'outdoors'];
// assess how close an events tag match users liked tags
// assess the events average rating // === PLACEHOLDER: Get all events with at least one matching tag ===
// Event score = (tag match* weight) + (average rating*weight) // let events = await Event.find({ tags: { $in: likedTags } });
// === DUMMY: Simulated event data ===
const events = [
{ id: 1, name: 'basketball', tags: ['tech', 'innovation'] },
{ id: 2, name: 'michael jackson', tags: ['outdoors', 'music'] },
{ id: 3, name: 'pdd', tags: ['literature'] },
{ id: 4, name: 'Fake event!!!!!!', tags: ['business', 'tech'] },
];
const tagMatchWeight = 0.7; const tagMatchWeight = 0.7;
const reviewScoreWeight = 0.3; const reviewScoreWeight = 0.3;
//wait for all events to finish before moving on // Score each event
// for every event in events(all events with liked tags): const eventScores = await Promise.all(events.map(async (event) => {
// find how similar users liked tags is to the events tags const matchingTags = event.tags.filter(tag => likedTags.includes(tag));
const eventScores = await Promise.all(events.map(async(event)=>{ const tagMatchScore = matchingTags.length / event.tags.length;
const matchingTags = event.tags.filter(value=>likedTags.includes(value)) //.filter returns what match condition inside param // TODO: Replace with actual rating from review microservice
const tagMatchScore = matchingTags.length / event.tags.length; // Percentage of tags that match const eventRating = 4; // hardcoded out of 5
const reviewScore = eventRating / 5;
//TODO: NEED TO SEE HOW THIS COMES OUT FROM REVIEW MICROSERVICE
// THIS IS WITH ASSUMPTION THAT EVENT OVERALL RATING IS ALREADY CALCULATED const finalScore = (tagMatchScore * tagMatchWeight) + (reviewScore * reviewScoreWeight);
const eventRating = 0
const reviewScore = eventRating / 5; return { event, finalScore };
}));
const finalScore = (tagMatchScore * tagMatchWeight) + (reviewScore * reviewScoreWeight)
// Sort events by score (highest to lowest)
return {event, finalScore} // end up with array of {event: {name, tags[]}, fianlsore: } const eventOrdered = eventScores.sort((a, b) => b.finalScore - a.finalScore);
}))
// TODO: Customize response shape later
//sort them by finalScore, .sort((a,b)) take two elements and compare them, const response = eventOrdered.map(({ event, finalScore }) => ({
eventOrdered = eventScores.sort((a,b)=> b.finalScore - a.finalScore) name: event.name,
score: finalScore.toFixed(2),
//TODO: }));
// HOW SHOULD I RESPOND THIS? NAME SHOULD PROABBLY BE ENOUGH, BUT SHOULD DISCUSS THIS WITH EVENTS MISCROSERVICE
res.json(response);
} catch (err) {
} catch (error) { console.error("Error fetching recommendations:", err);
res.status(500).json({ message: 'Error fetching recommendations', error }) res.status(500).json({ message: 'Server error fetching recommendations.' });
} }
}) });
module.exports = router module.exports = router
\ No newline at end of file
...@@ -5,7 +5,7 @@ const Tags = require('../models/tags') ...@@ -5,7 +5,7 @@ const Tags = require('../models/tags')
const User = require('../models/users') const User = require('../models/users')
// get all tag // get all tag
router.get('/tags', async (req, res)=>{ router.get('/', async (req, res)=>{
try { try {
const tagsdb = await Tags.find() const tagsdb = await Tags.find()
res.json(tagsdb) res.json(tagsdb)
...@@ -16,13 +16,6 @@ router.get('/tags', async (req, res)=>{ ...@@ -16,13 +16,6 @@ router.get('/tags', async (req, res)=>{
// save tags, and create user for recommendation microservice // save tags, and create user for recommendation microservice
router.post('/:id/save-tags', async(req, res)=>{ router.post('/:id/save-tags', async(req, res)=>{
// endpoint `GET /likedTags/{id}` from users
// {
// "likedTags": [
// "tag1",
// "tag2"
// ]
// }
try { try {
// depends how we handle api calls, directly or route through frontend? // depends how we handle api calls, directly or route through frontend?
......
...@@ -3,13 +3,15 @@ require('dotenv').config() ...@@ -3,13 +3,15 @@ require('dotenv').config()
const express = require('express') const express = require('express')
const app = express() const app = express()
const mongoose = require('mongoose') const mongoose = require('mongoose')
const cors = require('cors')
mongoose.connect(process.env.DOCKER_DATABASE_URL) mongoose.connect(process.env.LOCAL_DATABASE_URL)
const db = mongoose.connection const db = mongoose.connection
db.on('error', (error) => console.error(error)) db.on('error', (error) => console.error(error))
db.once('open', () => console.log('connected to database')) db.once('open', () => console.log('connected to database'))
app.use(express.json()) app.use(express.json())
app.use(cors())
app.get('/', (req, res) => { app.get('/', (req, res) => {
res.status(200).json({ res.status(200).json({
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment