mirror of
https://github.com/bubblecup-12/VogelSocialMedia.git
synced 2025-07-06 05:58:47 +00:00
Added user feed, Post Design improvement, Anchor
This commit is contained in:
parent
d11f92e11a
commit
5f9e3a24f7
7 changed files with 326 additions and 163 deletions
|
@ -1,4 +1,3 @@
|
|||
|
||||
import React, { use } from 'react';
|
||||
import logo from './logo.svg';
|
||||
import './App.css';
|
||||
|
@ -10,18 +9,21 @@ import "./styles/colors.css";
|
|||
import "./styles/fonts.css";
|
||||
import "./styles/sizes.css";
|
||||
import Footer from "./components/footer/Footer";
|
||||
import Header from "./components/Header";
|
||||
import Feed, {UserFeedRoute} from "./components/feed/Feed";
|
||||
import Header from './components/header/Header';
|
||||
import Profile from "./pages/Profile";
|
||||
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
|
||||
import { Auth } from "./api/Auth";
|
||||
import { NotFound } from "./pages/404Page/NotFoundPage";
|
||||
import Feed from './components/feed/Feed';
|
||||
import ScrollToAnchor from "./components/ScrollToAnchor";
|
||||
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<Auth>
|
||||
<Router>
|
||||
<Header />
|
||||
<ScrollToAnchor />
|
||||
<div className="App">
|
||||
<Routes>
|
||||
<Route path="*" element={<NotFound />} />
|
||||
|
@ -35,6 +37,8 @@ function App() {
|
|||
></Route>
|
||||
<Route path="/profile/:username" element={<Profile />}></Route>
|
||||
<Route path="/createpost" element={<PostCreation />}></Route>
|
||||
<Route path="/profile" element={<Profile />}></Route>
|
||||
<Route path="/feed/:user" element={<UserFeedRoute />}></Route>
|
||||
</Routes>
|
||||
<Footer />
|
||||
</div>
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
import * as React from 'react';
|
||||
import { styled, StyledEngineProvider } from '@mui/material/styles';
|
||||
import Card from '@mui/material/Card';
|
||||
import CardHeader from '@mui/material/CardHeader';
|
||||
import CardMedia from '@mui/material/CardMedia';
|
||||
import CardContent from '@mui/material/CardContent';
|
||||
import CardActions from '@mui/material/CardActions';
|
||||
import Collapse from '@mui/material/Collapse';
|
||||
import Avatar from '@mui/material/Avatar';
|
||||
import IconButton, { IconButtonProps } from '@mui/material/IconButton';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import { red } from '@mui/material/colors';
|
||||
import FavoriteIcon from '@mui/icons-material/Favorite';
|
||||
import ShareIcon from '@mui/icons-material/Share';
|
||||
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
|
||||
import MoreVertIcon from '@mui/icons-material/MoreVert';
|
||||
import * as React from "react";
|
||||
import { styled, StyledEngineProvider } from "@mui/material/styles";
|
||||
import Card from "@mui/material/Card";
|
||||
import CardHeader from "@mui/material/CardHeader";
|
||||
import CardMedia from "@mui/material/CardMedia";
|
||||
import CardContent from "@mui/material/CardContent";
|
||||
import CardActions from "@mui/material/CardActions";
|
||||
import Collapse from "@mui/material/Collapse";
|
||||
import Avatar from "@mui/material/Avatar";
|
||||
import IconButton, { IconButtonProps } from "@mui/material/IconButton";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import { red } from "@mui/material/colors";
|
||||
import FavoriteIcon from "@mui/icons-material/Favorite";
|
||||
import ShareIcon from "@mui/icons-material/Share";
|
||||
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
||||
import MoreVertIcon from "@mui/icons-material/MoreVert";
|
||||
import api from "../api/axios";
|
||||
import { Url } from 'url';
|
||||
import { LogLevel } from 'vite';
|
||||
import "./post.css"
|
||||
|
||||
import { Url } from "url";
|
||||
import { LogLevel } from "vite";
|
||||
import "./post.css";
|
||||
import UserAvatar from "./UserAvatar";
|
||||
|
||||
interface ExpandMoreProps extends IconButtonProps {
|
||||
expand: boolean;
|
||||
|
@ -44,18 +44,18 @@ interface PostResponse {
|
|||
url: string;
|
||||
}[];
|
||||
following: boolean;
|
||||
hasLiked: boolean; // <-- add this
|
||||
hasLiked: boolean;
|
||||
}
|
||||
|
||||
const ExpandMore = styled((props: ExpandMoreProps) => {
|
||||
const { expand, ...other } = props;
|
||||
return <IconButton {...other} />;
|
||||
})<ExpandMoreProps>(({ theme, expand }) => ({
|
||||
marginLeft: 'auto',
|
||||
transition: theme.transitions.create('transform', {
|
||||
marginLeft: "auto",
|
||||
transition: theme.transitions.create("transform", {
|
||||
duration: theme.transitions.duration.shortest,
|
||||
}),
|
||||
transform: expand ? 'rotate(180deg)' : 'rotate(0deg)',
|
||||
transform: expand ? "rotate(180deg)" : "rotate(0deg)",
|
||||
}));
|
||||
|
||||
export default function Post({ postId }: PostProps) {
|
||||
|
@ -70,9 +70,11 @@ export default function Post({ postId }: PostProps) {
|
|||
|
||||
async function getPostbyID(): Promise<void> {
|
||||
try {
|
||||
const response = await api.get<PostResponse>(`/posts/getPost/{postId}?postId=${postId}`);
|
||||
const response = await api.get<PostResponse>(
|
||||
`/posts/getPost/{postId}?postId=${postId}`
|
||||
);
|
||||
setPost(response.data);
|
||||
setLike(response.data.hasLiked); // <-- initialize like state
|
||||
setLike(response.data.hasLiked);
|
||||
setCurrentImage(0);
|
||||
} catch (error) {
|
||||
console.error("Failed to fetch post:", error);
|
||||
|
@ -81,7 +83,7 @@ export default function Post({ postId }: PostProps) {
|
|||
|
||||
if (!post) {
|
||||
return (
|
||||
<Card sx={{ maxWidth: 400, width: '100%', margin: 2 }}>
|
||||
<Card sx={{ maxWidth: 400, width: "100%", margin: 2 }}>
|
||||
<CardContent>
|
||||
<Typography>Loading...</Typography>
|
||||
</CardContent>
|
||||
|
@ -107,15 +109,11 @@ export default function Post({ postId }: PostProps) {
|
|||
if (!like) {
|
||||
await api.post(`/posts/like/${postId}`);
|
||||
setLike(true);
|
||||
setPost((prev) =>
|
||||
prev ? { ...prev, likes: prev.likes + 1 } : prev
|
||||
);
|
||||
setPost((prev) => (prev ? { ...prev, likes: prev.likes + 1 } : prev));
|
||||
} else {
|
||||
await api.delete(`/posts/removeLike/${postId}`);
|
||||
setLike(false);
|
||||
setPost((prev) =>
|
||||
prev ? { ...prev, likes: prev.likes - 1 } : prev
|
||||
);
|
||||
setPost((prev) => (prev ? { ...prev, likes: prev.likes - 1 } : prev));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Failed to update like:", error);
|
||||
|
@ -124,100 +122,89 @@ export default function Post({ postId }: PostProps) {
|
|||
|
||||
return (
|
||||
<StyledEngineProvider injectFirst>
|
||||
<Card className="body-l" sx={{ maxWidth: 600, width: '100%', margin: 2 }}>
|
||||
<CardHeader
|
||||
avatar={
|
||||
<Avatar sx={{ bgcolor: red[500] }} aria-label="user">
|
||||
{post.user.name.charAt(0).toUpperCase()}
|
||||
</Avatar>
|
||||
}
|
||||
action={
|
||||
<IconButton aria-label="settings">
|
||||
<MoreVertIcon />
|
||||
</IconButton>
|
||||
}
|
||||
title={post.user.name}
|
||||
/>
|
||||
{images.length > 0 && (
|
||||
<div className="post-image-carousel">
|
||||
<CardMedia
|
||||
component="img"
|
||||
image={images[currentImage].url}
|
||||
alt={images[currentImage].originalName}
|
||||
className="post-image"
|
||||
/>
|
||||
{hasMultipleImages && (
|
||||
<>
|
||||
<IconButton
|
||||
aria-label="previous image"
|
||||
onClick={handlePrev}
|
||||
className="post-carousel-arrow left"
|
||||
size="small"
|
||||
>
|
||||
{"<"}
|
||||
</IconButton>
|
||||
<IconButton
|
||||
aria-label="next image"
|
||||
onClick={handleNext}
|
||||
className="post-carousel-arrow right"
|
||||
size="small"
|
||||
>
|
||||
{">"}
|
||||
</IconButton>
|
||||
<div className="post-image-counter">
|
||||
{currentImage + 1} / {images.length}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
<CardContent>
|
||||
<Typography variant="body1" sx={{ fontWeight: 600 }}>
|
||||
{post.description}
|
||||
</Typography>
|
||||
<Typography variant="body2" color="text.secondary" sx={{ mb: 1 }}>
|
||||
Tags: {post.tags.join(", ")}
|
||||
</Typography>
|
||||
</CardContent>
|
||||
<CardActions disableSpacing>
|
||||
<IconButton aria-label="like" onClick={handleLike}>
|
||||
<FavoriteIcon
|
||||
className="post-like-icon"
|
||||
sx={{
|
||||
color: like ? "#d32f2f" : "#fff",
|
||||
stroke: !like ? "grey" : "none",
|
||||
strokeWidth: !like ? 2 : 0
|
||||
}}
|
||||
/>
|
||||
<span className="post-like-count">{post.likes}</span>
|
||||
</IconButton>
|
||||
<ExpandMore
|
||||
expand={expanded}
|
||||
onClick={() => setExpanded(!expanded)}
|
||||
aria-expanded={expanded}
|
||||
aria-label="show more"
|
||||
>
|
||||
<ExpandMoreIcon />
|
||||
</ExpandMore>
|
||||
</CardActions>
|
||||
<Collapse in={expanded} timeout="auto" unmountOnExit>
|
||||
<Card className="body-l" sx={{ maxWidth: 600, width: "100%", margin: 2 }}>
|
||||
<CardHeader
|
||||
avatar={<UserAvatar username={post.user.name} size={60} />}
|
||||
/>
|
||||
{images.length > 0 && (
|
||||
<div className="post-image-carousel">
|
||||
<CardMedia
|
||||
component="img"
|
||||
image={images[currentImage].url}
|
||||
alt={images[currentImage].originalName}
|
||||
className="post-image"
|
||||
/>
|
||||
{hasMultipleImages && (
|
||||
<>
|
||||
<IconButton
|
||||
aria-label="previous image"
|
||||
onClick={handlePrev}
|
||||
className="post-carousel-arrow left"
|
||||
size="small"
|
||||
>
|
||||
{"<"}
|
||||
</IconButton>
|
||||
<IconButton
|
||||
aria-label="next image"
|
||||
onClick={handleNext}
|
||||
className="post-carousel-arrow right"
|
||||
size="small"
|
||||
>
|
||||
{">"}
|
||||
</IconButton>
|
||||
<div className="post-image-counter">
|
||||
{currentImage + 1} / {images.length}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
<CardContent>
|
||||
<Typography variant="body2" color="text.secondary" sx={{ mb: 1 }}>
|
||||
Following: {post.following ? "Ja" : "Nein"}
|
||||
</Typography>
|
||||
<Typography variant="body2" color="text.secondary" sx={{ mb: 1 }}>
|
||||
Status: {post.status}
|
||||
</Typography>
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
Erstellt am: {new Date(post.createdAt).toLocaleString()}
|
||||
<Typography variant="body1" sx={{ fontWeight: 600 }}>
|
||||
{post.description}
|
||||
</Typography>
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
Zuletzt aktualisiert: {new Date(post.updatedAt).toLocaleString()}
|
||||
</Typography>
|
||||
|
||||
</CardContent>
|
||||
</Collapse>
|
||||
</Card>
|
||||
<CardActions disableSpacing>
|
||||
<IconButton aria-label="like" onClick={handleLike}>
|
||||
<FavoriteIcon
|
||||
className="post-like-icon"
|
||||
sx={{
|
||||
color: like ? "#d32f2f" : "#fff",
|
||||
stroke: !like ? "grey" : "none",
|
||||
strokeWidth: !like ? 2 : 0,
|
||||
}}
|
||||
/>
|
||||
<span className="post-like-count">{post.likes}</span>
|
||||
</IconButton>
|
||||
<ExpandMore
|
||||
expand={expanded}
|
||||
onClick={() => setExpanded(!expanded)}
|
||||
aria-expanded={expanded}
|
||||
aria-label="show more"
|
||||
>
|
||||
<ExpandMoreIcon />
|
||||
</ExpandMore>
|
||||
</CardActions>
|
||||
<Collapse in={expanded} timeout="auto" unmountOnExit>
|
||||
<CardContent>
|
||||
<Typography variant="body2" color="text.secondary" sx={{ mb: 1 }}>
|
||||
Tags: {post.tags.join(", ")}
|
||||
</Typography>
|
||||
<Typography variant="body2" color="text.secondary" sx={{ mb: 1 }}>
|
||||
Following: {post.following ? "Ja" : "Nein"}
|
||||
</Typography>
|
||||
<Typography variant="body2" color="text.secondary" sx={{ mb: 1 }}>
|
||||
Status: {post.status}
|
||||
</Typography>
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
Erstellt am: {new Date(post.createdAt).toLocaleString()}
|
||||
</Typography>
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
Zuletzt aktualisiert: {new Date(post.updatedAt).toLocaleString()}
|
||||
</Typography>
|
||||
</CardContent>
|
||||
</Collapse>
|
||||
</Card>
|
||||
</StyledEngineProvider>
|
||||
);
|
||||
}
|
||||
|
|
26
code/frontend/src/components/ScrollToAnchor.tsx
Normal file
26
code/frontend/src/components/ScrollToAnchor.tsx
Normal file
|
@ -0,0 +1,26 @@
|
|||
import { useEffect, useRef } from 'react';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
// use like this: onClick={() => navigate(`/feed/${username}#${post.id}`)}
|
||||
|
||||
function ScrollToAnchor() {
|
||||
const location = useLocation();
|
||||
const lastHash = useRef('');
|
||||
|
||||
useEffect(() => {
|
||||
if (location.hash) {
|
||||
lastHash.current = location.hash.slice(1);
|
||||
}
|
||||
if (lastHash.current && document.getElementById(lastHash.current)) {
|
||||
setTimeout(() => {
|
||||
document
|
||||
.getElementById(lastHash.current)
|
||||
?.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
||||
lastHash.current = '';
|
||||
}, 100);
|
||||
}
|
||||
}, [location]);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export default ScrollToAnchor;
|
|
@ -26,6 +26,7 @@ export default function UserAvatar({ username, size = 40 }: UserAvatarProps) {
|
|||
<Box sx={{ display: "flex", alignItems: "center", gap: 1, maxWidth: "600px"}}>
|
||||
<Avatar
|
||||
src={pb}
|
||||
alt={username || "avatar"}
|
||||
sx={{
|
||||
width: size,
|
||||
height: size,
|
||||
|
@ -33,7 +34,7 @@ export default function UserAvatar({ username, size = 40 }: UserAvatarProps) {
|
|||
fontWeight: 500,
|
||||
}}
|
||||
>
|
||||
username[0];
|
||||
{username ? username[0].toUpperCase() : ""}
|
||||
</Avatar>
|
||||
<Typography
|
||||
component="span"
|
||||
|
|
|
@ -6,9 +6,7 @@ import { create } from "axios";
|
|||
import WelcomeMessage from "./welcomeMessage/welcomeMessage";
|
||||
import { useAuth } from "../../api/Auth";
|
||||
import ButtonRotkehlchen from "../ButtonRotkehlchen";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
|
||||
|
||||
import { useNavigate, useParams } from "react-router-dom";
|
||||
|
||||
interface PostListItem {
|
||||
id: string;
|
||||
|
@ -16,7 +14,11 @@ interface PostListItem {
|
|||
description: string;
|
||||
}
|
||||
|
||||
function Feed() {
|
||||
interface FeedProps {
|
||||
username?: string;
|
||||
}
|
||||
|
||||
function Feed({ username }: FeedProps) {
|
||||
const [posts, setPosts] = useState<PostListItem[]>([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [hasMore, setHasMore] = useState(true);
|
||||
|
@ -30,23 +32,27 @@ function Feed() {
|
|||
if (loading || !hasMore) return;
|
||||
setLoading(true);
|
||||
try {
|
||||
let url = `/feed?limit=${PAGE_SIZE}`;
|
||||
if (nextCursor) {
|
||||
url = `/feed?createdAt=${encodeURIComponent(
|
||||
nextCursor
|
||||
)}&limit=${PAGE_SIZE}`;
|
||||
let url: string;
|
||||
if (username) {
|
||||
url = `/posts/getUserPosts/${encodeURIComponent(username)}`;
|
||||
const response = await api.get<{ posts: PostListItem[] }>(url);
|
||||
setPosts(response.data.posts);
|
||||
setHasMore(false);
|
||||
} else {
|
||||
url = `/feed?limit=${PAGE_SIZE}`;
|
||||
if (nextCursor) {
|
||||
url = `/feed?createdAt=${encodeURIComponent(nextCursor)}&limit=${PAGE_SIZE}`;
|
||||
}
|
||||
interface FeedResponse {
|
||||
posts: PostListItem[];
|
||||
nextCursor: string | null;
|
||||
}
|
||||
const response = await api.get<FeedResponse>(url);
|
||||
const { posts: newPosts, nextCursor: newCursor } = response.data;
|
||||
setPosts((prev) => [...prev, ...newPosts]);
|
||||
setNextCursor(newCursor);
|
||||
setHasMore(!!newCursor && newPosts.length > 0);
|
||||
}
|
||||
|
||||
interface FeedResponse {
|
||||
posts: PostListItem[];
|
||||
nextCursor: string | null;
|
||||
}
|
||||
const response = await api.get<FeedResponse>(url);
|
||||
console.log("Feed response:", response.data);
|
||||
const { posts: newPosts, nextCursor: newCursor } = response.data;
|
||||
setPosts((prev) => [...prev, ...newPosts]);
|
||||
setNextCursor(newCursor);
|
||||
setHasMore(!!newCursor && newPosts.length > 0);
|
||||
} catch (error) {
|
||||
console.error("Error fetching posts:", error);
|
||||
} finally {
|
||||
|
@ -59,6 +65,8 @@ function Feed() {
|
|||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (username) return;
|
||||
|
||||
const onScroll = () => {
|
||||
if (loading || !hasMore) return;
|
||||
if (
|
||||
|
@ -72,7 +80,14 @@ function Feed() {
|
|||
return () => {
|
||||
window.removeEventListener("scroll", onScroll);
|
||||
};
|
||||
}, [loading, hasMore, nextCursor]);
|
||||
}, [loading, hasMore, nextCursor, username]);
|
||||
|
||||
useEffect(() => {
|
||||
setPosts([]);
|
||||
setNextCursor(null);
|
||||
setHasMore(true);
|
||||
fetchPosts();
|
||||
}, [username]);
|
||||
|
||||
return (
|
||||
<div className={user ? "loggedInfeedContainer" : "feedContainer"}>
|
||||
|
@ -96,7 +111,9 @@ function Feed() {
|
|||
<main className="feedContent" ref={feedRef}>
|
||||
{posts.length === 0 && !loading && <div>Keine Posts gefunden.</div>}
|
||||
{posts.map((post) => (
|
||||
<Post key={post.id} postId={post.id} />
|
||||
<div id={post.id} key={post.id}>
|
||||
<Post postId={post.id} />
|
||||
</div>
|
||||
))}
|
||||
{loading && <div className="loading">Loading more posts...</div>}
|
||||
{!hasMore && <div>No more posts</div>}
|
||||
|
@ -105,4 +122,9 @@ function Feed() {
|
|||
);
|
||||
}
|
||||
|
||||
export function UserFeedRoute() {
|
||||
const { user } = useParams<{ user: string }>();
|
||||
return <Feed username={user} />;
|
||||
}
|
||||
|
||||
export default Feed;
|
||||
|
|
|
@ -31,12 +31,13 @@
|
|||
display: grid;
|
||||
grid-template-columns: 40% 60%;
|
||||
}
|
||||
.loggedInfeedContainer {
|
||||
|
||||
}
|
||||
.welcome-for-logged-out {
|
||||
position: sticky;
|
||||
top: 2rem;
|
||||
top: 5rem;
|
||||
left: 5rem;
|
||||
right: 1rem;
|
||||
align-self: center;
|
||||
align-self: flex-start;
|
||||
}
|
||||
.feedContent {
|
||||
|
|
|
@ -1,17 +1,139 @@
|
|||
import "./header.css";
|
||||
|
||||
import React, { useState } from "react";
|
||||
import {
|
||||
List,
|
||||
ListItem,
|
||||
ListItemButton,
|
||||
ListItemIcon,
|
||||
ListItemText,
|
||||
SwipeableDrawer,
|
||||
} from "@mui/material";
|
||||
import Box from "@mui/material/Box";
|
||||
import AddAPhotoIcon from "@mui/icons-material/AddAPhoto";
|
||||
import DynamicFeedIcon from "@mui/icons-material/DynamicFeed";
|
||||
import PersonIcon from "@mui/icons-material/Person";
|
||||
import InfoIcon from "@mui/icons-material/Info";
|
||||
import LogoutIcon from "@mui/icons-material/Logout";
|
||||
import ExitToAppIcon from "@mui/icons-material/ExitToApp";
|
||||
import FollowTheSignsIcon from "@mui/icons-material/FollowTheSigns";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { useAuth } from "../../api/Auth";
|
||||
|
||||
function Header() {
|
||||
interface ListItemAttributes {
|
||||
text: string;
|
||||
icon: React.ElementType;
|
||||
onClick: () => void;
|
||||
onlyShowWhen: "loggedIn" | "loggedOut" | "always";
|
||||
}
|
||||
const navigate = useNavigate();
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const toggleMenu = () => {
|
||||
setIsOpen(!isOpen);
|
||||
};
|
||||
const { logout, user } = useAuth();
|
||||
const ListItems: ListItemAttributes[] = [
|
||||
{
|
||||
text: "Feed",
|
||||
icon: DynamicFeedIcon,
|
||||
onClick: () => navigate("/feed", { replace: true }),
|
||||
onlyShowWhen: "always",
|
||||
},
|
||||
{
|
||||
text: "Create Post",
|
||||
icon: AddAPhotoIcon,
|
||||
onClick: () => navigate("/createpost", { replace: true }),
|
||||
onlyShowWhen: "loggedIn",
|
||||
},
|
||||
{
|
||||
text: "Profile",
|
||||
icon: PersonIcon,
|
||||
onClick: () => navigate("/profile", { replace: true }),
|
||||
onlyShowWhen: "loggedIn",
|
||||
},
|
||||
{
|
||||
text: "About",
|
||||
icon: InfoIcon,
|
||||
onClick: () => navigate("/about", { replace: true }),
|
||||
onlyShowWhen: "always",
|
||||
},
|
||||
{
|
||||
text: "Log Out",
|
||||
icon: LogoutIcon,
|
||||
onClick: logout,
|
||||
onlyShowWhen: "loggedIn",
|
||||
},
|
||||
{
|
||||
text: "Log In",
|
||||
icon: ExitToAppIcon,
|
||||
onClick: () => navigate("/login", { replace: true }),
|
||||
onlyShowWhen: "loggedOut",
|
||||
},
|
||||
{
|
||||
text: "Sign Up",
|
||||
icon: FollowTheSignsIcon,
|
||||
onClick: () => navigate("/register", { replace: true }),
|
||||
onlyShowWhen: "loggedOut",
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<header className="base-header">
|
||||
<div className="base-header-icon"> <img src='/assets/icons/feather_black.svg' alt="featherIcon" /> </div>
|
||||
<p className="header-title small-title">
|
||||
Feather Feed
|
||||
</p>
|
||||
<div className="base-header-icon"> <img src="/assets/icons/three_menu_stripes_black.svg" alt="menuIcon" /> </div>
|
||||
</header>
|
||||
);
|
||||
const DrawerList = (
|
||||
<Box role="menu" onClick={() => setIsOpen(false)}>
|
||||
<List className="drawer-list">
|
||||
{ListItems.map((ListItemObject, index) =>
|
||||
ListItemObject.onlyShowWhen == "always" ||
|
||||
(ListItemObject.onlyShowWhen == "loggedIn" && user) ||
|
||||
(ListItemObject.onlyShowWhen == "loggedOut" && !user) ? (
|
||||
<ListItem
|
||||
className="drawer-list-item"
|
||||
key={ListItemObject.text}
|
||||
disablePadding
|
||||
>
|
||||
<ListItemButton
|
||||
className="drawer-list-item-button"
|
||||
onClick={ListItemObject.onClick}
|
||||
>
|
||||
<ListItemIcon className="drawer-list-item">
|
||||
{React.createElement(ListItemObject.icon)}
|
||||
</ListItemIcon>
|
||||
<ListItemText
|
||||
className="drawer-list-item"
|
||||
primary={ListItemObject.text}
|
||||
/>
|
||||
</ListItemButton>
|
||||
</ListItem>
|
||||
) : null
|
||||
)}
|
||||
</List>
|
||||
</Box>
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<header className="base-header blue-background">
|
||||
<img
|
||||
className="header-icon header-icon-feather"
|
||||
src="/assets/icons/BirdIconO.ico"
|
||||
alt="featherIcon"
|
||||
/>
|
||||
<p className="header-title small-title">Feather Feed</p>
|
||||
<img
|
||||
className="header-icon header-icon-menu"
|
||||
src="/assets/icons/menu_orange.svg"
|
||||
alt="menu"
|
||||
onClick={toggleMenu}
|
||||
/>
|
||||
</header>
|
||||
<SwipeableDrawer
|
||||
anchor={"right"}
|
||||
open={isOpen}
|
||||
onClose={() => setIsOpen(false)}
|
||||
onOpen={() => setIsOpen(true)}
|
||||
>
|
||||
{DrawerList}
|
||||
</SwipeableDrawer>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default Header;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue