-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
24 user profile #60
24 user profile #60
Changes from all commits
0fa7cb5
a787b65
e077784
065f049
cf660dd
55a27ed
6804a20
d930a7e
d3a35e3
b90d85f
206fb86
896f39e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,165 @@ | ||
import axios from "axios"; | ||
import Popup from "./popup"; | ||
import { useEffect, useState } from "react"; | ||
import { Typography, CssBaseline, AppBar, Toolbar, Container, Card, Grid, CardMedia, CardContent, CardActions, Button} from "@mui/material" | ||
import { makeStyles } from "@mui/styles"; | ||
import {Post} from "../../interfaces/interfaces"; | ||
import "./styles.css"; | ||
import { Link } from "react-router-dom"; | ||
|
||
const APP_URI = process.env.REACT_APP_URI; | ||
|
||
const useStyles = makeStyles((theme) => ({ | ||
container : { | ||
backgroundColor: "#FAF8F1", | ||
paddingTop: "2rem", | ||
paddingBottom: "2rem", | ||
display: 'flex', | ||
flexDirection: 'column', | ||
}, | ||
picture :{ | ||
width: '30%', | ||
height: '30%', | ||
borderRadius: '50%', | ||
display: 'block', | ||
marginLeft: 'auto', | ||
marginRight: 'auto', | ||
marginTop: '20px', | ||
marginBottom: '20px' | ||
}, | ||
cardGrid: { | ||
paddingTop: "2rem", | ||
paddingBottom: "2rem", | ||
dislpay: 'flex', | ||
flexDirection: 'column', | ||
}, | ||
card: { | ||
width: '100%', | ||
height: '100%' | ||
}, | ||
customLink: { | ||
color: "white", | ||
textDecoration: "none !important" | ||
} | ||
})); | ||
|
||
const ProfilePage = () => { | ||
|
||
const [AuthorData, setAuthorData] = useState(""); | ||
const [posts, setPosts] = useState<Post[]>([]); | ||
const [openPopups, setOpenPopups] = useState<boolean[]>(Array(posts.length).fill(false)); | ||
|
||
const togglePopup = (index: number) => { | ||
const newOpenPopups = [...openPopups]; | ||
newOpenPopups[index] = !newOpenPopups[index]; | ||
setOpenPopups(newOpenPopups); | ||
}; | ||
|
||
const fetchAuthors = async () => { | ||
// TODO: replace hardcoded author id with AUTHOR_ID | ||
const url = `${APP_URI}author/5ba6d758-257f-4f47-b0b7-d3d5f5e32561/`; | ||
|
||
try { | ||
const response = await axios.get(url); | ||
setAuthorData(response.data.displayName); | ||
} catch (error) { | ||
console.error("Error fetching author", error); | ||
} | ||
}; | ||
|
||
const fetchPosts = async () => { | ||
// TODO: replace hardcoded author id with AUTHOR_ID | ||
const url = `${APP_URI}author/5ba6d758-257f-4f47-b0b7-d3d5f5e32561/posts/`; | ||
|
||
try { | ||
const response = await axios.get(url); | ||
setPosts(response.data); | ||
} catch (error) { | ||
console.error("Error fetching posts:", error); | ||
} | ||
}; | ||
|
||
useEffect(() => { | ||
fetchAuthors(); | ||
fetchPosts(); | ||
}, []); | ||
|
||
const username = AuthorData; | ||
const classes = useStyles(); | ||
|
||
function limitContentTo100Words(content: string): string { | ||
const words: string[] = content.split(' '); | ||
|
||
if (words.length > 100) { | ||
const limitedContent: string = words.slice(0, 100).join(' '); | ||
return limitedContent + ' ...'; | ||
} else { | ||
return content; | ||
} | ||
} | ||
|
||
return ( | ||
<> | ||
<CssBaseline /> | ||
<AppBar position="relative"> | ||
<Toolbar> | ||
<Link to="/home-page"> | ||
<Typography variant="h6" className={classes.customLink} style={{ textDecoration: 'none' }}> | ||
SocialDistribution | ||
</Typography> | ||
</Link> | ||
</Toolbar> | ||
</AppBar> | ||
<main> | ||
<div className={classes.container}> | ||
<Container maxWidth="sm"> | ||
<img src={require("../../assets/defaultprofile.jpg")} alt="profile-pic" className={classes.picture}/> | ||
<Typography variant="h2" align="center" color="black" style={{ fontFamily: "Bree Serif, serif" }}> | ||
{username} | ||
</Typography> | ||
</Container> | ||
</div> | ||
<Container className={classes.cardGrid} maxWidth="md"> | ||
<Grid container spacing={4}> | ||
{posts.map((post, index) => ( | ||
<Grid item key={index} xs={12} sm={12} md={12}> | ||
<Card className={classes.card}> | ||
<CardContent> | ||
<Typography variant="h3" style={{ fontFamily: "Bree Serif, serif" }}> | ||
{post.title} | ||
</Typography> | ||
<Typography variant="h5" style={{ fontFamily: "Bree Serif, serif" }}> | ||
{post.description} | ||
</Typography> | ||
<Typography variant="body1" style={{ fontFamily: "Bree Serif, serif" }}> | ||
{limitContentTo100Words(post.content ? post.content : '')} | ||
</Typography> | ||
</CardContent> | ||
<CardActions> | ||
<Button size="small" color="primary" onClick={() => togglePopup(index)}> | ||
View | ||
</Button> | ||
<Popup trigger={openPopups[index]} setTrigger={() => togglePopup(index)}> | ||
<Typography variant="h3" style={{ fontFamily: "Bree Serif, serif" }}> | ||
{post.title} | ||
</Typography> | ||
<Typography variant="h5" style={{ fontFamily: "Bree Serif, serif" }}> | ||
{post.description} | ||
</Typography> | ||
<Typography variant="body1" style={{ fontFamily: "Bree Serif, serif" }}> | ||
{post.content} | ||
</Typography> | ||
</Popup> | ||
<Button size="small" color="primary">Delete</Button> | ||
</CardActions> | ||
</Card> | ||
</Grid> | ||
))} | ||
</Grid> | ||
</Container> | ||
</main> | ||
</> | ||
) | ||
} | ||
|
||
export default ProfilePage |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
.modal { | ||
display: none; | ||
position: fixed; | ||
top: 0; | ||
left: 0; | ||
width: 100%; | ||
height: 100%; | ||
background-color: rgba(0, 0, 0, 0.5); | ||
z-index: 1000; | ||
display: flex; | ||
justify-content: center; | ||
align-items: center; | ||
} | ||
|
||
.popup-inner { | ||
background-color: #fff; | ||
padding: 20px; | ||
border-radius: 8px; | ||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.3); | ||
} | ||
|
||
.close-btn { | ||
position: absolute; | ||
top: 16px; | ||
right: 16px; | ||
font-size: 20px; | ||
color: #333; | ||
cursor: pointer; | ||
background-color: #fff; /* White background */ | ||
padding: 8px; /* Adjust padding as needed */ | ||
border-radius: 10%; /* Rounded borders for a circular button */ | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import React from 'react'; | ||
import './popup.css'; | ||
|
||
type PopupProps = { | ||
trigger: boolean; | ||
setTrigger: (value: boolean) => void; | ||
children: React.ReactNode; | ||
}; | ||
|
||
const Popup: React.FC<PopupProps> = (props) => { | ||
return props.trigger ? ( | ||
<div className='modal'> | ||
<div className='popup-inner'> | ||
<button className='close-btn' onClick={() => props.setTrigger(false)}>close</button> | ||
{props.children} | ||
</div> | ||
</div> | ||
) : null; | ||
}; | ||
|
||
export default Popup; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
@import url("https://fonts.googleapis.com/css2?family=Bree+Serif&display=swap"); |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,6 +18,12 @@ class AuthorView(APIView): | |
queryset = Author.objects.all() | ||
serializer_class = AuthorSerializer | ||
|
||
def get(self, request, author_id): | ||
# get the author data whose id is AUTHOR_ID | ||
author = Author.objects.get(id=author_id) | ||
serializer = AuthorSerializer(author) | ||
return Response(serializer.data, status=status.HTTP_200_OK) | ||
|
||
Comment on lines
+21
to
+26
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can be done later on but the api needs to have an updated serializer. On the project reqs, a call to a single author has "type", has an id url for the id field instead of the uuid, etc.. I don't think it's needed for this profile page, so this can be updated as we work more on these api calls. |
||
|
||
class PostsView(APIView): | ||
# add allowed HTTP requests | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't need to do for this PR: I see that home page and profile page have different app bars, I'll add an issue to create a header component to have them be consistent.