-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Add new translations - Implement comments with all functionalities, - Create base functionality for reactions - Create share button Refs: CU-8697jhjf Signed-off-by: Patryk Kłosiński <[email protected]>
- Loading branch information
Showing
28 changed files
with
1,072 additions
and
145 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import {Center, Loader} from "@mantine/core"; | ||
import {useEffect, useState} from "react"; | ||
import {useParams} from "react-router-dom"; | ||
import {PostDTO} from "../shared/types"; | ||
import {Post} from "../shared/components/Cards/Post"; | ||
import api from "../shared/services/api.ts"; | ||
|
||
export const SharedPost = () => { | ||
const [post, setPost] = useState<PostDTO | null>(null); | ||
const [isPostLoading, setIsPostLoading] = useState(true); | ||
const {postId} = useParams() | ||
|
||
useEffect(() => { | ||
api.get(`/api/posts/${postId}`).then(r => { | ||
if (r.status === 200) { | ||
setPost(r.data); | ||
setIsPostLoading(false); | ||
} | ||
}); | ||
}, []); | ||
|
||
return ( | ||
<Center h={'100vh'}> | ||
{isPostLoading && <Loader size="xl"/>} | ||
{post && | ||
<Post | ||
id={post.id} | ||
content={post.content} | ||
createdAt={post.createdAt} | ||
numberOfComments={post.numberOfComments} | ||
author={post.author} | ||
/> | ||
} | ||
</Center> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export {SharedPost} from './SharedPost'; |
145 changes: 145 additions & 0 deletions
145
frontend/src/Features/shared/components/Cards/Post/DetailedPost.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
import {Avatar, Badge, Button, Divider, Group, Stack, Text, Textarea} from "@mantine/core"; | ||
import {PostDTO} from "../../../types"; | ||
import {TFunction} from "i18next"; | ||
import {useEffect, useState} from "react"; | ||
import {CommentDTO} from "./types"; | ||
import api from "../../../services/api.ts"; | ||
import {CommentsSection} from "./components/CommentsSection"; | ||
import {useAlert} from "../../../../../Providers/AlertProvider.tsx"; | ||
import {IconMessage} from "@tabler/icons-react"; | ||
import {DateFormatter, RenderPhotos} from "../../../utils"; | ||
import {InnerHtmlHandler} from "../../InnerHtmlHandler"; | ||
import {MenuPost} from "./components/MenuPost"; | ||
import {useAuthStore} from "../../../services/authStore.ts"; | ||
import {ReactionButton} from "./components/ReactionButton"; | ||
import {ShareButton} from "./components/ShareButton"; | ||
|
||
type PostProps = PostDTO & { | ||
t: TFunction<string, undefined> | ||
modal: string | ||
} | ||
|
||
export const DetailedPost = (props: PostProps) => { | ||
const auth = useAuthStore(); | ||
const isOwner = auth.user?.login === props.author.login; | ||
const [comments, setComments] = useState<CommentDTO[]>([]); | ||
const [commentValue, setCommentValue] = useState(""); | ||
const alert = useAlert(); | ||
|
||
const handleCommentEdit = (id: string, content: string) => { | ||
const updatedComments = comments.map((comment) => | ||
comment.id === id ? {...comment, content} : comment | ||
); | ||
setComments(updatedComments); | ||
}; | ||
|
||
const handleCommentDelete = (id: string) => { | ||
setComments(comments.filter((comment) => comment.id !== id)); | ||
}; | ||
|
||
const handleSentComment = async () => { | ||
if (commentValue.length > 0) { | ||
try { | ||
const response = await api.post(`/api/comments`, null, { | ||
params: { | ||
postId: props.id, | ||
content: commentValue, | ||
}, | ||
}); | ||
if (response.status === 200) { | ||
alert.showError({ | ||
title: props.t("detailedPost.alert.title"), | ||
message: props.t("detailedPost.alert.message"), | ||
level: "INFO", | ||
timestamp: new Date().toISOString(), | ||
}); | ||
|
||
setComments([...comments, response.data.content]); | ||
setCommentValue(""); | ||
} | ||
} catch (error) { | ||
console.error("Failed to send comment", error); | ||
} | ||
} | ||
}; | ||
|
||
useEffect(() => { | ||
const fetchComments = async () => { | ||
try { | ||
const response = await api.get(`/api/comments/post/${props.id}`); | ||
if (response.status === 200) { | ||
setComments(response.data.content); | ||
} | ||
} catch (error) { | ||
console.error("Failed to fetch comments", error); | ||
} | ||
}; | ||
|
||
fetchComments().then(r => r); | ||
}, []); | ||
|
||
return ( | ||
<Stack> | ||
<Group justify="space-between"> | ||
<Group style={{cursor: "pointer"}}> | ||
<Avatar src={props.author.profilePictureUrl} size={"lg"} radius={180}/> | ||
<Stack gap={0}> | ||
<Text>{props.author.name} {props.author.surname}</Text> | ||
<Text c="dimmed">{DateFormatter(props.createdAt)}</Text> | ||
</Stack> | ||
</Group> | ||
{isOwner && | ||
<MenuPost postId={props.id} content={props.content}/> | ||
} | ||
</Group> | ||
|
||
<InnerHtmlHandler innerHtml={props.content}/> | ||
|
||
{/*// Show photos if they exist*/} | ||
{props.pictures && props.pictures.length > 0 && ( | ||
<RenderPhotos pictures={props.pictures}/> | ||
)} | ||
|
||
<Divider my={"xs"}/> | ||
|
||
<Group grow preventGrowOverflow={false}> | ||
<ReactionButton onReact={console.log}> | ||
{props.t('buttons.reaction.label')} | ||
</ReactionButton> | ||
<Button | ||
variant={"subtle"} | ||
color={"gray"} | ||
leftSection={<IconMessage stroke={1.5}/>} | ||
rightSection={<Badge color={"gray"} circle>{props.numberOfComments}</Badge>} | ||
> | ||
{props.t('buttons.comment.label')} | ||
</Button> | ||
<ShareButton postId={props.id}> | ||
{props.t('buttons.share.label')} | ||
</ShareButton> | ||
</Group> | ||
|
||
<Divider my={"xs"}/> | ||
|
||
<Textarea | ||
radius="md" | ||
label={props.t('detailedPost.textArea.label')} | ||
placeholder={props.t('detailedPost.textArea.placeholder')} | ||
value={commentValue} | ||
onChange={(e) => setCommentValue(e.currentTarget.value)} | ||
/> | ||
<Group justify={"flex-end"}> | ||
<Button variant="outline" color="blue" onClick={handleSentComment}> | ||
{props.t('detailedPost.textArea.children')} | ||
</Button> | ||
</Group> | ||
<Divider my={"xs"}/> | ||
<CommentsSection | ||
comments={comments} | ||
onCommentDelete={handleCommentDelete} | ||
onCommentEdit={handleCommentEdit} | ||
modal={props.modal} | ||
/> | ||
</Stack> | ||
); | ||
}; |
Oops, something went wrong.