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
10 changes: 0 additions & 10 deletions client/my-react-app/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

277 changes: 277 additions & 0 deletions client/my-react-app/src/AddReviewPage.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,277 @@
import { useState } from 'react';
import { useParams, Link, useNavigate } from 'react-router-dom';
import { getSpotById, getBuildingById } from './mockData.js';

export default function AddReviewPage() {
const { spotId } = useParams();
const navigate = useNavigate();
const spot = getSpotById(spotId);

// Form state
const [rating, setRating] = useState(5);
const [reviewTitle, setReviewTitle] = useState('');
const [reviewBody, setReviewBody] = useState('');

if (!spot) {
return (
<div style={{ padding: '20px' }}>
<Link to="/locations">← Back to Locations</Link>
<h1>Spot Not Found</h1>
<p>Sorry, we couldn't find that study spot.</p>
</div>
);
}

const building = getBuildingById(spot.buildingId);

const handleSubmit = (e) => {
e.preventDefault();

// Create review object (for now just log it)
const newReview = {
id: `rev-${Date.now()}`, // temporary ID
spotId: spotId,
reviewerName: 'Anonymous User', // hardcoded for now
rating: rating,
title: reviewTitle,
body: reviewBody,
date: new Date().toISOString().split('T')[0],
comments: []
};

console.log('New review submitted:', newReview);

// Show success message (could be improved with a toast/modal)
alert('Review submitted successfully! (Note: This is mock data and will not persist)');

// Navigate back to spot page
navigate(`/spot/${spotId}`);
};

const handleCancel = () => {
if (reviewTitle || reviewBody) {
const confirmCancel = window.confirm('Are you sure you want to cancel? Your review will not be saved.');
if (confirmCancel) {
navigate(`/spot/${spotId}`);
}
} else {
navigate(`/spot/${spotId}`);
}
};

return (
<div style={{ padding: '20px', maxWidth: '700px', margin: '0 auto' }}>
{/* Breadcrumb navigation */}
<div style={{ marginBottom: '16px', color: '#666' }}>
<Link to="/locations" style={{ color: '#4a90e2', textDecoration: 'none' }}>
Locations
</Link>
{' > '}
<Link
to={`/building/${spot.buildingId}`}
style={{ color: '#4a90e2', textDecoration: 'none' }}
>
{building?.name || 'Building'}
</Link>
{' > '}
<Link
to={`/spot/${spotId}`}
style={{ color: '#4a90e2', textDecoration: 'none' }}
>
{spot.name}
</Link>
{' > '}
<span>Add Review</span>
</div>

{/* Page header */}
<h1 style={{ marginBottom: '8px' }}>Write a Review</h1>
<h2 style={{
fontSize: '1.2rem',
fontWeight: 'normal',
color: '#666',
marginTop: '0'
}}>
{spot.name}
</h2>

{/* Review form */}
<form onSubmit={handleSubmit} style={{ marginTop: '32px' }}>
{/* Rating selection */}
<div style={{ marginBottom: '24px' }}>
<label style={{
display: 'block',
fontWeight: '600',
marginBottom: '8px',
fontSize: '1rem'
}}>
Rating *
</label>
<div style={{ display: 'flex', gap: '12px', flexWrap: 'wrap' }}>
{[1, 2, 3, 4, 5].map((star) => (
<label
key={star}
style={{
display: 'flex',
alignItems: 'center',
cursor: 'pointer',
padding: '8px 16px',
border: `2px solid ${rating === star ? '#4a90e2' : '#ddd'}`,
borderRadius: '6px',
backgroundColor: rating === star ? '#e3f2fd' : 'white',
transition: 'all 0.2s ease'
}}
>
<input
type="radio"
name="rating"
value={star}
checked={rating === star}
onChange={(e) => setRating(Number(e.target.value))}
style={{ marginRight: '8px' }}
/>
<span>{'⭐'.repeat(star)} {star}</span>
</label>
))}
</div>
</div>

{/* Review title */}
<div style={{ marginBottom: '24px' }}>
<label style={{
display: 'block',
fontWeight: '600',
marginBottom: '8px',
fontSize: '1rem'
}}>
Review Title (optional)
</label>
<input
type="text"
value={reviewTitle}
onChange={(e) => setReviewTitle(e.target.value)}
placeholder="Summarize your experience..."
maxLength={100}
style={{
width: '100%',
padding: '12px',
fontSize: '1rem',
border: '2px solid #ddd',
borderRadius: '6px',
boxSizing: 'border-box',
fontFamily: 'inherit'
}}
/>
<small style={{ color: '#888', fontSize: '0.85rem' }}>
{reviewTitle.length}/100 characters
</small>
</div>

{/* Review body */}
<div style={{ marginBottom: '24px' }}>
<label style={{
display: 'block',
fontWeight: '600',
marginBottom: '8px',
fontSize: '1rem'
}}>
Your Review *
</label>
<textarea
value={reviewBody}
onChange={(e) => setReviewBody(e.target.value)}
placeholder="Share your experience with this study spot. What did you like? What could be improved?"
required
rows={8}
maxLength={1000}
style={{
width: '100%',
padding: '12px',
fontSize: '1rem',
border: '2px solid #ddd',
borderRadius: '6px',
boxSizing: 'border-box',
fontFamily: 'inherit',
resize: 'vertical'
}}
/>
<small style={{ color: '#888', fontSize: '0.85rem' }}>
{reviewBody.length}/1000 characters
</small>
</div>

{/* Form buttons */}
<div style={{
display: 'flex',
gap: '12px',
marginTop: '32px',
paddingTop: '24px',
borderTop: '1px solid #e0e0e0'
}}>
<button
type="submit"
disabled={!reviewBody.trim()}
style={{
flex: '1',
backgroundColor: reviewBody.trim() ? '#4a90e2' : '#ccc',
color: 'white',
border: 'none',
padding: '14px 24px',
fontSize: '1rem',
borderRadius: '6px',
cursor: reviewBody.trim() ? 'pointer' : 'not-allowed',
fontWeight: '600',
transition: 'background-color 0.3s ease'
}}
onMouseOver={(e) => {
if (reviewBody.trim()) e.target.style.backgroundColor = '#357abd';
}}
onMouseOut={(e) => {
if (reviewBody.trim()) e.target.style.backgroundColor = '#4a90e2';
}}
>
Submit Review
</button>
<button
type="button"
onClick={handleCancel}
style={{
flex: '1',
backgroundColor: 'white',
color: '#666',
border: '2px solid #ddd',
padding: '14px 24px',
fontSize: '1rem',
borderRadius: '6px',
cursor: 'pointer',
fontWeight: '600',
transition: 'all 0.3s ease'
}}
onMouseOver={(e) => {
e.target.style.borderColor = '#999';
e.target.style.color = '#333';
}}
onMouseOut={(e) => {
e.target.style.borderColor = '#ddd';
e.target.style.color = '#666';
}}
>
Cancel
</button>
</div>
</form>

{/* Helper text */}
<div style={{
marginTop: '24px',
padding: '16px',
backgroundColor: '#fff3e0',
borderRadius: '6px',
fontSize: '0.9rem',
color: '#f57c00'
}}>
<strong>Note:</strong> This is a demo form. Reviews are not saved to a database yet.
</div>
</div>
);
}
8 changes: 8 additions & 0 deletions client/my-react-app/src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,21 @@
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import Home from './Home.jsx';
import Locations from './locations.jsx';
import BuildingPage from './BuildingPage.jsx';
import SpotPage from './SpotPage.jsx';
import AddReviewPage from './AddReviewPage.jsx';
import ReviewPage from './ReviewPage.jsx';

export default function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/locations" element={<Locations />} />
<Route path="/building/:buildingId" element={<BuildingPage />} />
<Route path="/spot/:spotId" element={<SpotPage />} />
<Route path="/spot/:spotId/add-review" element={<AddReviewPage />} />
<Route path="/review/:reviewId" element={<ReviewPage />} />
</Routes>
</BrowserRouter>
);
Expand Down
Loading