Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
8dd7b43
implement user info display and ad management
christian-bueno Mar 12, 2024
253e6f7
Update Login.js
h12s Mar 22, 2024
44d1ac8
Resolved merge conflicts
h12s Mar 22, 2024
67a067c
Resolve merge conflicts
h12s Mar 22, 2024
3eac75f
Merge pull request #3 from nikkikapadia/test-authentication
h12s Mar 22, 2024
3661c07
Revert "Test User Authentication (Register / Login Page)"
h12s Mar 22, 2024
0c9248f
Merge pull request #13 from nikkikapadia/revert-3-test-authentication
h12s Mar 22, 2024
50d7dc5
Add back previous commits
h12s Mar 22, 2024
efb8f27
Merge pull request #14 from nikkikapadia/test-authentication
h12s Mar 22, 2024
e3e7e57
Revert to dc47f29
h12s Mar 22, 2024
ef15a26
Merge branch 'main' into user-profile
christian-bueno Mar 28, 2024
e0e60e7
Adds API endpoints to userprofile component
christian-bueno Mar 31, 2024
fee8700
Adds a modal to edit an ad from profile page
christian-bueno Mar 31, 2024
ed446d4
some backend implemenation, not finished
christian-bueno Mar 31, 2024
e82b820
Merge remote-tracking branch 'origin/persist-user-state' into user-pr…
christian-bueno Mar 31, 2024
4ff124a
Adds firebase integration into registration,
christian-bueno Apr 2, 2024
1b6eaa4
adds firebase uid to backend during registration
christian-bueno Apr 2, 2024
85bb466
Fixes "autToken" type
christian-bueno Apr 2, 2024
5a7ebb5
Adds firebase uid to user schema
christian-bueno Apr 2, 2024
265d907
saving attempts to fix authentication issues
christian-bueno Apr 2, 2024
8acce70
Merge branch 'main' into user-profile
h12s Apr 3, 2024
5f9a2ee
Fetch ads made by user
h12s Apr 3, 2024
3e4ccfc
saving progress on editing ads
christian-bueno Apr 3, 2024
475ae6b
sends entire ad as response
christian-bueno Apr 3, 2024
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/node_modules
2 changes: 1 addition & 1 deletion backend/middleware/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,4 @@ class Middleware {
}
}

module.exports = new Middleware();
module.exports = new Middleware();
6 changes: 6 additions & 0 deletions backend/models/UserModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ const userSchema = new mongoose.Schema({
fullName: {
type: String,
required: true,
},
firebaseUID: {
type: String,
required: true,
unique: true,
index: true,
}
}, { versionKey: false });

Expand Down
2 changes: 1 addition & 1 deletion frontend/package-lock.json

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

2 changes: 1 addition & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"@emotion/react": "^11.11.3",
"@emotion/react": "^11.11.4",
"@emotion/styled": "^11.11.0",
"@fontsource/inter": "^5.0.16",
"@mui/icons-material": "^5.15.10",
Expand Down
8 changes: 4 additions & 4 deletions frontend/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { auth } from "./firebase-config";

import { UserContext } from "./contexts/UserContext";
import { useContext } from "react";
import UserProfile from './components/UserProfile'

function App() {
const { user, setUser } = useContext(UserContext);
Expand Down Expand Up @@ -58,11 +59,10 @@ function App() {
path="/postAd"
element={user.isLoggedIn ? <PostAd /> : <Login />}
/>
<Route path="/settings" element={<div></div>} />
<Route path="/profile" element={<div></div>} />
<Route path="/profile" element={user.isLoggedIn ? <UserProfile /> : <Login />} />
<Route path="/myposts" element={<div></div>} />
<Route path="/messages" element={<Messages />} />
<Route path="/messages/:chatId" element={<Messages />} />
<Route path="/messages" element={user.isLoggedIn ? <Messages /> : <Login />} />
<Route path="/messages/:chatId" element={user.isLoggedIn ? <Messages /> : <Login />} />
{user.isAdmin && <Route path="/posts" element={<AllPosts />} />}
{user.isAdmin && <Route path="/users" element={<Users />} />}
<Route path="*" element={<Page404 />} />
Expand Down
65 changes: 65 additions & 0 deletions frontend/src/components/EditAdModal.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// EditAdModal.jsx
import React, { useState } from 'react';
import { Modal, Box, Typography, TextField, Button } from "@mui/material";


function EditAdModal({ open, onClose, adInfo, onSave }) {
const [editedAd, setEditedAd] = useState(adInfo);

const handleSubmit = (e) => {
e.preventDefault();
console.log(editedAd._id)
onSave(editedAd); // Pass the edited ad back to UserProfile
onClose(); // Close the modal
};

const handleChange = (e) => {
const { name, value } = e.target;
setEditedAd({ ...editedAd, [name]: value });
};

// Define modal styles here
const style = {
position: 'absolute',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
width: 400,
bgcolor: 'background.paper',
border: '2px solid #000',
boxShadow: 24,
p: 4,
};

return (
<Modal open={open} onClose={onClose}>
<Box sx={style} component="form" noValidate autoComplete="off" onSubmit={handleSubmit}>
<Typography variant="h6" marginBottom={2}>Edit Ad</Typography>
<TextField
name="title"
label="Title"
value={editedAd.title}
onChange={handleChange}
fullWidth
margin="normal"
/>
<TextField
name="description"
label="Description"
value={editedAd.description}
onChange={handleChange}
fullWidth
margin="normal"
multiline
rows={4}
/>
<Button type="submit" variant="contained" sx={{ mt: 2 }}>
Save Changes
</Button>
</Box>
</Modal>
);
}

export default EditAdModal;

59 changes: 59 additions & 0 deletions frontend/src/components/EditProfileModal.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import React, { useState } from 'react';
import { Modal, Box, Typography, TextField, Button } from "@mui/material";

function EditProfileModal({ open, onClose, userInfo, onSave }) {
const [editedUserInfo, setEditedUserInfo] = useState(userInfo);

const handleChange = (e) => {
const { name, value } = e.target;
setEditedUserInfo(prev => ({ ...prev, [name]: value }));
};

const handleSubmit = (e) => {
e.preventDefault();
onSave(editedUserInfo);
onClose();
};

const style = {
position: 'absolute',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
width: 400,
bgcolor: 'background.paper',
border: '2px solid #000',
boxShadow: 24,
p: 4,
};

return (
<Modal open={open} onClose={onClose}>
<Box sx={style} component="form" noValidate autoComplete="off" onSubmit={handleSubmit}>
<Typography variant="h6" marginBottom={2}>Edit Profile</Typography>
<TextField
name="name"
label="Name"
value={editedUserInfo.name}
onChange={handleChange}
fullWidth
margin="normal"
/>
<TextField
name="email"
label="Email"
value={editedUserInfo.email}
onChange={handleChange}
fullWidth
margin="normal"
/>
{/* Add other fields as necessary */}
<Button type="submit" variant="contained" sx={{ mt: 2 }}>
Save Changes
</Button>
</Box>
</Modal>
);
}

export default EditProfileModal;
182 changes: 182 additions & 0 deletions frontend/src/components/UserProfile.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
import React, { useState, useEffect, useContext } from 'react';
import { Box, Card, CardContent, Typography, TextField, Button } from "@mui/material";
import EditAdModal from './EditAdModal';
import EditProfileModal from './EditProfileModal';

import { UserContext } from "../contexts/UserContext";


const UserProfile = () => {
const [userInfo, setUserInfo] = useState({ name: '', email: '' });
const [ads, setAds] = useState([]);
const [editModalOpen, setEditModalOpen] = useState(false);
const [selectedAd, setSelectedAd] = useState(null)

const { user, setUser } = useContext(UserContext);

// NOTE: user object has all properties you need to display/edit user info

const fetchUserAds = async () => {
const token = user.authToken;
let items = [];
await fetch(`http://localhost:5001/api/ads/get/itemsWanted/author/${user.username}`, {
method: 'GET',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'authorization': `Bearer ${token}`
}
})
.then(res => {
return res.json();
})
.then(data => {
let temp = data;
temp.forEach(ad => { ad.category = 'Items Wanted'; });
items.push(...temp);
return fetch(`http://localhost:5001/api/ads/get/itemsForSale/author/${user.username}`, {
method: 'GET',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'authorization': `Bearer ${token}`
}
});
})
.then(res => {
return res.json();
})
.then(data => {
let temp = data;
temp.forEach(ad => { ad.category = 'Items For Sale'; });
items.push(...temp);
return fetch(`http://localhost:5001/api/ads/get/academicServices/author/${user.username}`, {
method: 'GET',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'authorization': `Bearer ${token}`
}
});
})
.then(res => {
return res.json();
})
.then(data => {
let temp = data;
temp.forEach(ad => { ad.category = 'Academic Services'; });
items.push(...temp);
setAds(items);
console.log('ads by user: ', ads);
});
}

useEffect(() => {
fetchUserAds();
}, []);


const handleUpdateUserInfo = (e) => {
e.preventDefault();
console.log('Updated Info:', userInfo);
};

const handleEditAd = (ad) => {
console.log(ad._id);
setSelectedAd(ad);
setEditModalOpen(true);
};

const handleSaveAdChanges = async (editedAd) => {
const token = user.authToken;
const { title, description } = editedAd; // Destructure the needed properties

try {
const response = await fetch(`http://localhost:5001/api/ads/update/${editedAd.category}/id/${editedAd._id}`, {
method: "PATCH",
headers: {
"Accept": "application/json",
"Content-Type": "application/json",
"Authorization": `Bearer ${token}`,
},
body: JSON.stringify({ editedAd }),
});

if (!response.ok) {
throw new Error(`Failed to update ad. Status: ${response.status}`);
}

const data = await response.json();
console.log('Update successful:', data);

// Update local state or re-fetch ads to reflect changes
fetchUserAds();
} catch (error) {
console.error('Error updating ad:', error);
}
};

// const handleSaveProfile = async (updatedUserInfo) => {
// const token = user.authToken;
// try {
// const response = await fetch('/api/users/update/me', {
// method: 'PATCH',
// headers: {
// 'Authorization': `Bearer ${token}`,
// 'Content-Type': 'application/json',
// },
// body: JSON.stringify(updatedUserInfo),
// });

// if (!response.ok) {
// throw new Error('Failed to update user info');
// }

// const data = await response.json();
// setEditModalOpen(false);
// } catch (error) {
// console.error('Error updating user info:', error)
// }
// };


return (
<>
<Card sx={{ maxWidth: 800, mx: "auto", mt: 5, borderRadius: "10px" }}>
<CardContent>
<Typography variant="h4" sx={{ mb: 2 }}>User Profile</Typography>
<Box sx={{ mb: 4 }}>
<Typography variant="h6" sx={{ mb: 1 }}>Personal Information</Typography>
<Typography>Username: {user.username}</Typography>
<Typography>Email: {user.email}</Typography>
</Box>
<Box sx={{ mb: 4 }}>
<Typography variant="h6" sx={{ mb: 1 }}>Your Ads</Typography>
{ads.map((ad) => (
<Box key={ad._id} sx={{ mb: 2, display: 'flex', flexDirection: 'column', justifyContent: 'space-between' }}>
<Typography variant="h5">{ad.title}</Typography>
<Typography>{ad.description}</Typography>
{/* Render photos */}
{ad.photos.map((photoUrl, index) => (
<img key={index} src={photoUrl} alt={`Ad photo ${index + 1}`} style={{ maxWidth: '100%', maxHeight: '300px', objectFit: 'contain' }} />
))}
<Button onClick={() => handleEditAd(ad)} variant="contained" sx={{ mt: 2 }}>Edit</Button>
</Box>
))}
</Box>

</CardContent>
</Card>
{selectedAd && (
<EditAdModal
open={editModalOpen}
onClose={() => setEditModalOpen(false)}
adInfo={selectedAd}
onSave={handleSaveAdChanges}
/>
)}
</>
);
};

export default UserProfile;
5 changes: 4 additions & 1 deletion frontend/src/firebase.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
// https://firebase.google.com/docs/web/setup#available-libraries
import { initializeApp } from "firebase/app";
import { getStorage } from "firebase/storage";
import { getAuth } from "firebase/auth";


// Your web app's Firebase configuration
const firebaseConfig = {
Expand All @@ -15,4 +17,5 @@ const firebaseConfig = {

// Initialize Firebase
const app = initializeApp(firebaseConfig);
export const firebaseStorage = getStorage(app);
export const firebaseStorage = getStorage(app);
export const auth = getAuth(app);
Loading