Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions backend/controllers/reactionsController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import Reactions from '../models/reactions.js';
import asyncHandler from 'express-async-handler';

export const getReaction = asyncHandler(async (req, res) => {
const { userEmail, eventId } = req.params;

if (!userEmail || !eventId) {
res.status(400);
}

const reaction = await Reactions.findOne({ userEmail, eventId });

if (reaction) {
res.status(200).json(reaction); // Return the found reaction
} else {
res.status(404).json({ message: 'Reaction not found' }); // No reaction found
}

})

export const createReaction = asyncHandler(async (req, res) => {
const { userEmail, eventId, reactionType } = req.body;

// Validate input
if (!userEmail || !eventId || ![1, -1].includes(reactionType)) {
res.status(400);
}

// Check if a reaction already exists
const existingReaction = await Reactions.findOne({ userEmail, eventId });

if (existingReaction) {
// Update the existing reaction
existingReaction.reactionType = reactionType;
await existingReaction.save();
res.status(200).json({
message: 'Reaction updated successfully',
reaction: existingReaction
});
} else {
// Create a new reaction
const newReaction = await Reactions.create({
userEmail,
eventId,
reactionType
});
res.status(201).json({
message: 'Reaction created successfully',
reaction: newReaction
});
}
});

export default {
getReaction,
createReaction
};
2 changes: 2 additions & 0 deletions backend/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import connectMailchimp from './mailchimp/connect-mailchimp.js';
import eventRoutes from './routes/event.js';
import subscriptionRoutes from './routes/emailSubscription.js';
import userRoutes from './routes/user.js';
import reactionsRoutes from './routes/reactions.js'

// initialize the application
const app = express();
Expand Down Expand Up @@ -41,6 +42,7 @@ app.get('/', function (_, res) {
app.use(`${baseApi}`, eventRoutes);
app.use(`${baseApi}/subscribers`, subscriptionRoutes);
app.use(`${baseApi}/users`, userRoutes);
app.use(`${baseApi}/reactions`, reactionsRoutes);

var server = app.listen(PORT, function () {
var port = server.address().port;
Expand Down
22 changes: 22 additions & 0 deletions backend/models/reactions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import mongoose from 'mongoose';
import { Schema, model } from 'mongoose';

const reactionsSchema = new Schema({
userEmail: {
type: String,
required: true
},
eventId: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Event',
required: true
},
reactionType: {
type: Number,
enum: [1, -1], // 1 = like, -1 = dislike
required: true
}
});

// Export model
export default model('Reactions', reactionsSchema);
14 changes: 14 additions & 0 deletions backend/routes/reactions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import express from 'express';
import reactionsController from '../controllers/reactionsController.js';

const router = express.Router();

//POST request for new reaction
router.post('/create', reactionsController.createReaction);

//GET request for user reaction
router.get('/:userEmail/:eventId', reactionsController.getReaction);

// Export router.
export default router;

84 changes: 84 additions & 0 deletions frontend/src/components/Button/ThumbButtons.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import React, { useState, useEffect} from "react";
import ThumbUpIcon from "@mui/icons-material/ThumbUp";
import ThumbDownIcon from "@mui/icons-material/ThumbDown";
import Button from "@mui/material/Button";
import Stack from "@mui/material/Stack";
import axios from "axios";

interface ThumbButtonProps {
userEmail: string;
eventId: string;
}

const ThumbButtons = ({ userEmail, eventId } : ThumbButtonProps) => {
const [selected, setSelected] = useState<1 | -1 | null>(null);
const API = axios.create({ baseURL: `${process.env.REACT_APP_BACKEND_URL}/api/v1` });

useEffect(() => {
const fetchReaction = async () => {
try {
const response = await API.get(`/reactions/${userEmail}/${eventId}`);
if (response.data && response.data.reactionType) {
setSelected(response.data.reactionType);
}
} catch (error) {
console.error("Error fetching reaction:", error);
}
};

fetchReaction();
}, [userEmail, eventId]);

const updateReaction = async (reaction: 1 | -1 | null) => {
try {
await API.post("/reactions/create", {
userEmail,
eventId,
reactionType: reaction,
});
} catch (error) {
console.error("Error updating reaction:", error);
}
};

const handleThumbUp = () => {
const newReaction = selected === 1 ? null : 1;
setSelected(newReaction);
updateReaction(newReaction);
};

const handleThumbDown = () => {
const newReaction = selected === -1 ? null : -1;
setSelected(newReaction);
updateReaction(newReaction);
};

return (
<Stack direction="row" spacing={2}>
{/* Thumbs Up Button */}
<Button
variant="contained"
startIcon={<ThumbUpIcon />}
onClick={handleThumbUp}
style={{
backgroundColor: selected === 1 ? "#1976d2" : "#e0e0e0",
color: selected === 1 ? "#fff" : "#000",
textTransform: "none",
}}
/>
{/* Thumbs Down Button */}
<Button
variant="contained"
startIcon={<ThumbDownIcon />}
onClick={handleThumbDown}
style={{
backgroundColor: selected === -1 ? "#d32f2f" : "#e0e0e0",
color: selected === -1 ? "#fff" : "#000",
textTransform: "none",
}}
/>
</Stack>
);
};

export default ThumbButtons;
Loading