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
2 changes: 0 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@ If you have a disability that prevents you from walking around campus, getting a

The **Rider App** branch can be found [here](https://github.com/cornell-dti/carriage-rider). The **Driver App** branch can be found [here](https://github.com/cornell-dti/carriage-driver).

## Contributors:

## Contributors

### Current Contributors
Expand Down
69 changes: 68 additions & 1 deletion frontend/src/components/RideDetails/RideOverview.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from 'react';
import React, { useState } from 'react';
import {
Box,
Typography,
Expand All @@ -18,6 +18,8 @@ import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
import dayjs, { Dayjs } from 'dayjs';
import CalendarTodayIcon from '@mui/icons-material/CalendarToday';
import FavoriteIcon from '@mui/icons-material/Favorite';
import FavoriteBorderIcon from '@mui/icons-material/FavoriteBorder';
import AccessTimeIcon from '@mui/icons-material/AccessTime';
import InfoIcon from '@mui/icons-material/Info';
import DirectionsCarIcon from '@mui/icons-material/DirectionsCar';
Expand All @@ -39,6 +41,7 @@ import RiderList from './RiderList';
import { isNewRide } from '../../util/modelFixtures';
import { validateRideTimes } from './TimeValidation';
import styles from './RideOverview.module.css';
import axios from '../../util/axios';

interface RideOverviewProps {
userRole: 'rider' | 'driver' | 'admin';
Expand Down Expand Up @@ -205,6 +208,7 @@ const RideOverview: React.FC<RideOverviewProps> = ({ userRole }) => {
const ride = editedRide!;
const temporalType = getTemporalType(ride);
const showRecurrence = userRole !== 'driver'; // Hide recurrence for drivers
const [isClicked, setIsClicked] = useState(false);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You might want a more descriptive variable name here than isClicked, something more descriptive about what the state represents.


const formatDateTime = (dateTimeString: string) => {
const date = new Date(dateTimeString);
Expand Down Expand Up @@ -313,6 +317,51 @@ const RideOverview: React.FC<RideOverviewProps> = ({ userRole }) => {
updateRideField('type', event.target.value);
};

/**
* handleFavorite
*
* Triggered when a user clicks the favorite or unfavorite button for a past ride
* Intended to send a POST or DELETE request to database then be added or unadded
* as a favorites card
*
* Current status:
* - Function is implemented and makes both requests.
* - Issue: Favoriting and deleting favorites are currently failing with a 500
* Internal Server Error
*
* TODO:
* - Fix backend schema mismatch or ensure correct key format
* - Add responsivity for button icon
*/

const handleFavorite = async () => {
if (!isClicked) {
//user favorited icon
setIsClicked(true);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function might have a mismatched state between isClicked and the actual result of the favoriting operation because of the catch statements below.

try {
await axios.post('/api/favorites', {
rideId: ride.id,
});
} catch (error: any) {
console.error(
'Error favoriting ride:',
error.response?.data || error.message
);
}
} else {
//user unfavorited icon
setIsClicked(false);
try {
await axios.delete('/api/favorites/ride.id');
} catch (error: any) {
console.error(
'Error unfavoriting ride:',
error.response?.data || error.message
);
}
}
};

const renderPersonSection = () => {
if (userRole === 'admin') return null; // Admin overview shows only ride info, people are in separate tab

Expand Down Expand Up @@ -377,6 +426,24 @@ const RideOverview: React.FC<RideOverviewProps> = ({ userRole }) => {
<div className={styles.sectionTitle}>
<DirectionsCarIcon color="primary" />
<Typography variant="h6">Ride Overview</Typography>

{userRole === 'rider' && (
<div>
<IconButton
onClick={handleFavorite}
size="small"
sx={{
marginLeft: '90px',
}}
>
{isClicked ? (
<FavoriteIcon color="primary" />
) : (
<FavoriteBorderIcon color="primary" />
)}
</IconButton>
</div>
)}
</div>
<div className={styles.contentArea}>
{/* Schedule Section */}
Expand Down
2 changes: 2 additions & 0 deletions server/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import upload from './router/upload';
import auth from './router/auth';
import stats from './router/stats';
import initSchedule from './util/repeatingRide';
import favorites from './router/favorites';
import notification from './router/notification';
import initDynamoose from './util/dynamoose';

Expand Down Expand Up @@ -55,6 +56,7 @@ app.use('/api/auth', auth);
app.use('/api/upload', upload);
app.use('/api/notification', notification);
app.use('/api/stats', stats);
app.use('/api/favorites', favorites);
app.get('/api/health-check', (_, response) => response.status(200).send('OK'));

// Serve static files from frontend
Expand Down
2 changes: 1 addition & 1 deletion server/src/models/favorite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const schema = new dynamoose.Schema({
// we store references because storing the ride duplicates the data, comp key for efficiency and better normalization
userId: { type: String, required: true, hashKey: true },
rideId: { type: String, required: true, rangeKey: true },
favoritedAt: { type: Date, default: () => new Date() },
favoritedAt: { type: String, default: () => new Date().toISOString() },
});

export const Favorite = dynamoose.model(
Expand Down
1 change: 1 addition & 0 deletions server/src/models/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ export { Admin as Admin } from './admin';
export { Notification as Notification } from './notification';
export { Stats as Stats } from './stats';
export { Rider as Rider } from './rider';
export { Favorite as Favorite } from './favorite';
56 changes: 47 additions & 9 deletions server/src/router/favorites.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,17 @@ router.post('/', validateUser('User'), async (req, res) => {
const { rideId } = req.body;
const userId = res.locals.user.id;

console.log(rideId);

if (!rideId) {
return res.status(400).send({ err: 'rideId is required' });
}

console.log(rideId);

const ride = await new Promise((resolve) => {
console.log('reach1 getting ride id')

db.getById(res, Ride, rideId, 'Rides', (rideData) => {
resolve(rideData);
});
Expand All @@ -30,23 +36,55 @@ router.post('/', validateUser('User'), async (req, res) => {
});
}

const existingFavorite = await new Promise((resolve) => {
db.getById(res, Favorite, { userId, rideId }, tableName, (fav) => {
resolve(fav);
});
});
console.log('reach2 before existing fav');

if (existingFavorite) {
return res.status(222).send({ msg: 'Ride already favorited' });
}
console.log("Checking Favorite.get key:", { userId, rideId });


const existingFavorite = await Favorite.query('userId').eq(userId)
.filter('rideId').eq(rideId)
.exec();


// await new Promise((resolve) => {
// console.log('reach3 in existing favs');

// db.getById(res, Favorite, { userId, rideId }, tableName, (fav) => {
// resolve(fav);
// });
// console.log('reach4 after existing favs call');

// });

console.log('reach4.125 before checking existing');


if (existingFavorite.count > 0) {
// already favorited
}

console.log('reach4.25 before creating of new FavRid');




const favoriteRide = new Favorite({
userId,
rideId,
favoritedAt: new Date(),
});

db.create(res, favoriteRide, (doc) => res.send(doc));
console.log('reach4.5 before try');


try {
console.log('reach5 before creating new fav ride')
db.create(res, favoriteRide, (doc) => res.send(doc));
} catch (err) {
console.log('reach5 after creating new fav ride');
console.log(err);
}

});

// Get all favorite rides for the current user
Expand Down
Loading