Skip to content
Open
Show file tree
Hide file tree
Changes from 2 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
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';
Loading