Skip to content

Commit 21d365f

Browse files
committed
feat(): Adding add comment feature + like + view - ui
1 parent a27974b commit 21d365f

11 files changed

Lines changed: 216 additions & 69 deletions

File tree

src/screens/articles/ArticlesScreen.tsx

Lines changed: 54 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,45 @@ import { useMemo, useState } from 'react';
77
import { groupBy } from 'lodash';
88
import { BASE_NAV_ROUTE } from '@router';
99

10+
const CategoryButton = ({
11+
category,
12+
setCategory,
13+
secondPath,
14+
isSelected,
15+
}: {
16+
category: string;
17+
setCategory: (category: string) => void;
18+
secondPath: string;
19+
isSelected: boolean;
20+
}) => {
21+
const navigate = useNavigate();
22+
return (
23+
<Button
24+
w={'100%'}
25+
color={'white'}
26+
py={3}
27+
px={5}
28+
bg={isSelected ? 'gray.800' : ''}
29+
fontSize={20}
30+
variant={'ghost'}
31+
border={'1px solid gray'}
32+
_hover={{ bg: 'gray.600', cursor: 'pointer', color: 'violet' }}
33+
onClick={() => {
34+
if (secondPath) {
35+
navigate(BASE_NAV_ROUTE + 'articles');
36+
}
37+
setCategory(category);
38+
}}
39+
>
40+
{category}
41+
</Button>
42+
);
43+
};
44+
1045
const ArticlesScreen = () => {
1146
const { data } = useGetArticlesData();
1247
const location = useLocation();
13-
const navigate = useNavigate();
14-
const [category, setCategory] = useState('');
48+
const [category, setCategory] = useState('All');
1549
const secondPath = location.pathname.split('/')[3];
1650

1751
const articles = useMemo(
@@ -61,29 +95,21 @@ const ArticlesScreen = () => {
6195
top={'12vh'}
6296
marginTop={'12vh'}
6397
>
98+
<CategoryButton
99+
category={'All'}
100+
setCategory={setCategory}
101+
secondPath={secondPath}
102+
isSelected={'All' === category}
103+
/>
64104
{Object.keys(filteredArticles).map(
65105
(group_name: any, index: number) => (
66-
<Button
67-
w={'100%'}
106+
<CategoryButton
68107
key={index}
69-
py={3}
70-
color={'white'}
71-
px={5}
72-
bg={group_name === category ? 'gray.800' : ''}
73-
fontSize={20}
74-
m={0}
75-
variant={'ghost'}
76-
border={'1px solid gray'}
77-
_hover={{ bg: 'gray.600', cursor: 'pointer', color: 'violet' }}
78-
onClick={() => {
79-
if (secondPath) {
80-
navigate(BASE_NAV_ROUTE + 'articles');
81-
}
82-
setCategory(group_name);
83-
}}
84-
>
85-
{group_name}
86-
</Button>
108+
category={group_name}
109+
setCategory={setCategory}
110+
secondPath={secondPath}
111+
isSelected={group_name === category}
112+
/>
87113
),
88114
)}
89115
</VStack>
@@ -102,9 +128,12 @@ const ArticlesScreen = () => {
102128
justify="start"
103129
justifyContent={'space-between'}
104130
>
105-
{(category ? filteredArticles[category] : articles)?.map(
106-
(article: any) => <ArticleCard key={article.id} {...article} />,
107-
)}
131+
{(category && category !== 'All'
132+
? filteredArticles[category]
133+
: articles
134+
)?.map((article: any) => (
135+
<ArticleCard key={article.id} {...article} />
136+
))}
108137
</Wrap>
109138
)}
110139
{secondPath && <MarkdownViewer articleKey={secondPath} />}

src/screens/articles/components/CommentBox.tsx

Lines changed: 46 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,15 @@ import {
88
VStack,
99
Text,
1010
} from '@chakra-ui/react';
11-
import { useState } from 'react';
11+
import { useAddComment, useGetComments } from '@services';
12+
import { useMemo, useState } from 'react';
13+
14+
const CommentBox = ({ articleKey }: { articleKey: string }) => {
15+
const { data, refetch } = useGetComments(articleKey);
16+
const { mutate } = useAddComment();
17+
18+
const comments = useMemo(() => (data as any)?.data?.rows, [data]);
1219

13-
const CommentBox = ({
14-
comments,
15-
}: {
16-
comments: { comment: string; user: string; email: string }[];
17-
}) => {
1820
const [state, setState] = useState<{
1921
email: string;
2022
name: string;
@@ -24,6 +26,19 @@ const CommentBox = ({
2426
const isDisabled =
2527
state.email === '' || state.name === '' || state.comment === '';
2628

29+
const handleSubmit = () => {
30+
mutate({
31+
articleKey,
32+
comment: {
33+
comment: state.comment,
34+
email: state.email,
35+
name: state.name,
36+
},
37+
});
38+
setState({ email: '', name: '', comment: '' });
39+
refetch();
40+
};
41+
2742
return (
2843
<Box
2944
w={'100%'}
@@ -37,21 +52,26 @@ const CommentBox = ({
3752
<Heading size={'md'}>Comments</Heading>
3853
<Divider />
3954
{comments ? (
40-
comments?.map((comment, index) => (
41-
<Box
42-
key={index}
43-
p={2}
44-
px={4}
45-
borderRadius={'md'}
46-
mt={4}
47-
bg={'gray.800'}
48-
>
49-
<Heading size={'md'}>
50-
🤖{comment.user} 📫{comment.email}
51-
</Heading>
52-
<Box paddingStart={2}>{comment.comment}</Box>
53-
</Box>
54-
))
55+
comments?.map(
56+
(
57+
comment: { name: string; email: string; comment: string },
58+
index: number,
59+
) => (
60+
<Box
61+
key={index}
62+
p={2}
63+
px={4}
64+
borderRadius={'md'}
65+
mt={4}
66+
bg={'gray.800'}
67+
>
68+
<Heading size={'md'}>
69+
🤖{comment.name} 📫{comment.email}
70+
</Heading>
71+
<Box paddingStart={2}>{comment.comment}</Box>
72+
</Box>
73+
),
74+
)
5575
) : (
5676
<Text alignSelf={'start'} color={'gray.500'} p={4}>
5777
No Comments
@@ -79,7 +99,11 @@ const CommentBox = ({
7999
value={state.comment}
80100
onChange={(e) => setState({ ...state, comment: e.target.value })}
81101
/>
82-
<Button alignSelf={'start'} isDisabled={isDisabled}>
102+
<Button
103+
alignSelf={'start'}
104+
isDisabled={isDisabled}
105+
onClick={handleSubmit}
106+
>
83107
Submit
84108
</Button>
85109
</VStack>

src/screens/articles/components/MarkdownViewer.tsx

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,17 @@ const MarkdownViewer = ({ articleKey }: { articleKey: string }) => {
99
const { data } = useGetArticleData(articleKey);
1010

1111
const mdString = useMemo(
12-
() => (data as any)?.data?.rows?.[0].md_data,
12+
() => (data as any)?.data?.rows?.[0]?.md_data ?? '',
1313
[data],
1414
);
1515

16-
const comments = useMemo(
17-
() => (data as any)?.data?.rows?.[0].comments,
16+
const likes = useMemo(
17+
() => (data as any)?.data?.rows?.[0]?.likes ?? '',
18+
[data],
19+
);
20+
21+
const views = useMemo(
22+
() => (data as any)?.data?.rows?.[0]?.views ?? '',
1823
[data],
1924
);
2025

@@ -32,9 +37,9 @@ const MarkdownViewer = ({ articleKey }: { articleKey: string }) => {
3237
>
3338
<Box width={'80%'} id="md-preview-flex-box">
3439
<MdPreview mdString={mdString ?? ''} />
35-
<CommentBox comments={JSON.parse(comments).comments} />
40+
<CommentBox articleKey={articleKey} />
3641
</Box>
37-
<SideViewer mdString={mdString ?? ''} />
42+
<SideViewer mdString={mdString ?? ''} likes={likes} views={views} />
3843
</HStack>
3944
);
4045
};

src/screens/articles/components/SideViewer.tsx

Lines changed: 40 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,17 @@
1-
import { Box, Button, Text } from '@chakra-ui/react';
1+
import { Box, Button, Divider, HStack, Text } from '@chakra-ui/react';
22
import { useMemo } from 'react';
33
import { HEADING_TYPE_REGEX } from './constants';
44
import { useLikeArticleData } from '@services';
55

6-
const SideViewer = ({ mdString }: { mdString: string }) => {
6+
const SideViewer = ({
7+
mdString,
8+
likes,
9+
views,
10+
}: {
11+
mdString: string;
12+
likes: number;
13+
views: number;
14+
}) => {
715
const { mutate } = useLikeArticleData();
816
// Extract headings from the markdown string and remove dots.
917
const headings = useMemo(
@@ -44,22 +52,37 @@ const SideViewer = ({ mdString }: { mdString: string }) => {
4452
rowGap={1}
4553
flexDir={'column'}
4654
>
47-
<Button size={'sm'} onClick={mutate}>
48-
Like 👍
49-
</Button>
50-
<Button
51-
size={'sm'}
52-
as={'a'}
53-
href={'#comments'}
54-
onClick={() =>
55-
document.getElementById('comments')?.scrollIntoView({
56-
behavior: 'smooth',
57-
block: 'center',
58-
})
59-
}
55+
<HStack w={'100%'} justifyContent={'space-evenly'}>
56+
<Text>Likes👍: {likes}</Text>
57+
<Text>Views👀: {views}</Text>
58+
</HStack>
59+
<Divider />
60+
61+
<HStack w={'100%'} justifyContent={'space-evenly'}>
62+
<Button size={'sm'} onClick={mutate}>
63+
Like Article👍
64+
</Button>
65+
<Button
66+
size={'sm'}
67+
as={'a'}
68+
href={'#comments'}
69+
onClick={() => scrollToComponent('comments')}
70+
>
71+
Comments 💬
72+
</Button>
73+
</HStack>
74+
<Divider />
75+
<Text
76+
fontSize={'large'}
77+
color={'primary'}
78+
style={{
79+
padding: 2,
80+
width: '100%',
81+
}}
82+
fontWeight={'bold'}
6083
>
61-
Comments 💬
62-
</Button>
84+
ON THIS PAGE
85+
</Text>
6386
{headings.map(({ marginStart, itemName, link }, index) => (
6487
<>
6588
<Text
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { PostRequest } from '../client/client';
2+
import { ADD_COMMENT_URL } from './constants';
3+
4+
const addComment = async (data: unknown) => PostRequest(ADD_COMMENT_URL, data);
5+
6+
export default addComment;

src/services/backend/articles/constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ export const LEARNING_BACKEND_URL = 'https://amitraikwar-services.onrender.com';
55
export const ALL_ARTICLES_URL = `/all_articles`;
66
export const ARTICLES_URL = `/get_article`;
77
export const LIKE_ARTICLE_URL = `/like_article`;
8+
export const GET_COMMENTS_URL = `/get_comments`;
89

910
// Mutation
1011
export const ADD_ARTICLE_URL = `/add_article`;
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { GetRequest } from '../client/client';
2+
import { GET_COMMENTS_URL } from './constants';
3+
import { StandardResponse } from './types';
4+
5+
const getComments = async (articleKey: string): Promise<StandardResponse> => {
6+
return await GetRequest(GET_COMMENTS_URL + '?articleKey=' + articleKey);
7+
};
8+
9+
export default getComments;

src/services/backend/articles/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,5 @@ export { default as getArticleData } from './getArticleData';
33
export { default as likePageArticleData } from './likePageArticleData';
44

55
export { default as addArticle } from './addArticle';
6+
export { default as addComment } from './addComment';
7+
export { default as getComments } from './getComments';

src/services/hooks/articles/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,5 @@ export { default as useGetArticlesData } from './useGetAllArticlesData';
22
export { default as useGetArticleData } from './useGetArticleData';
33
export { default as useLikeArticleData } from './useLikeArticleData';
44
export { default as useAddArticle } from './useAddArticle';
5+
export { default as useAddComment } from './useAddComment';
6+
export { default as useGetComments } from './useGetComments';
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { useToast } from '@chakra-ui/react';
2+
import { addComment } from '../../backend';
3+
import { useCallSBMutation } from '../common';
4+
import { useQueryClient } from '@tanstack/react-query';
5+
6+
const useAddComment = () => {
7+
const toast = useToast();
8+
const queryClient = useQueryClient();
9+
return useCallSBMutation({
10+
method: (data) => addComment(data),
11+
mutationOptions: {
12+
onSuccess: () => {
13+
toast({
14+
title: 'Comment added.',
15+
status: 'success',
16+
duration: 3000,
17+
isClosable: true,
18+
});
19+
queryClient.invalidateQueries({ queryKey: ['comments'] });
20+
},
21+
onError: () => {
22+
toast({
23+
title: 'Error.',
24+
status: 'error',
25+
duration: 3000,
26+
isClosable: true,
27+
});
28+
},
29+
},
30+
});
31+
};
32+
33+
export default useAddComment;

0 commit comments

Comments
 (0)