Skip to content

Commit 77a3b7a

Browse files
committed
feat(): Adding the update article feature
1 parent aaef43d commit 77a3b7a

9 files changed

Lines changed: 144 additions & 38 deletions

File tree

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { SVGProps } from 'react';
2+
const RefreshIcon = (props: SVGProps<SVGSVGElement>) => (
3+
<svg
4+
xmlns="http://www.w3.org/2000/svg"
5+
viewBox="0 0 24 24"
6+
width="1em"
7+
height="1em"
8+
{...props}
9+
>
10+
<path
11+
fill="currentColor"
12+
d="M17.65 6.35A7.96 7.96 0 0 0 12 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08A5.99 5.99 0 0 1 12 18c-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 11h7V4z"
13+
></path>
14+
</svg>
15+
);
16+
export default RefreshIcon;

src/assets/icons/Common/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ export { default as MusicIcon } from './Music';
55
export { default as MusicOffIcon } from './MusicOff';
66
export { default as ArrowIcon } from './ArrowIcon';
77
export { default as RobotIcon } from './Robot';
8+
export { default as RefreshIcon } from './RefreshIcon';
89
export { default as LinkedInIcon } from './LinkedInIcon';
910
export { default as GithubIcon } from './GithubIcon';
1011
export { default as GetInTouch } from './GetInTouch';

src/components/MdPreview/css/Markdown.module.css

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,21 +17,25 @@
1717

1818
.markdown h3 {
1919
cursor: pointer;
20-
font-size: 1.2rem;
20+
font-size: 1.4rem;
2121
font-weight: 500;
2222
color: #ffffffa0;
2323
}
2424

2525
.markdown h2 {
2626
cursor: pointer;
27-
font-size: 1.6rem;
27+
font-size: 1.8rem;
2828
font-weight: 700;
2929
margin-top: 2rem;
3030
color: #fffffff0;
3131
}
3232

3333
.markdown h1 {
34-
display: none;
34+
cursor: pointer;
35+
font-size: 2.4rem;
36+
font-weight: 700;
37+
margin-top: 2rem;
38+
color: #fffffff0;
3539
}
3640

3741
.markdown div ul {

src/screens/articleEditor/ArticleEditor.tsx

Lines changed: 65 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,57 @@
1-
import { Box, Button, HStack, Input, Text, VStack } from '@chakra-ui/react';
2-
import { MDXEditor } from '@mdxeditor/editor';
3-
import { ALL_PLUGINS } from './AllPlugins';
1+
import {
2+
Box,
3+
Button,
4+
Divider,
5+
HStack,
6+
Input,
7+
Radio,
8+
RadioGroup,
9+
Text,
10+
Textarea,
11+
VStack,
12+
} from '@chakra-ui/react';
413
import '@mdxeditor/editor/style.css';
5-
import { ArticleCard, useCursor } from '@components';
14+
import { ArticleCard, MdPreview, useCursor } from '@components';
615
import { useCallback, useLayoutEffect, useState } from 'react';
716
import { ARTICLE_DEFAULT } from './constants';
817
import { ArticleWithContent } from './types';
918
import { getRequestObject, isValidArticle } from './utils';
10-
import { useAddArticle, useGetEditorArticleData } from '@services';
11-
import ArticlePreviewDrawer from './ArticlePreviewDrawar';
19+
import {
20+
useAddArticle,
21+
useGetEditorArticleData,
22+
useUpdateArticle,
23+
} from '@services';
1224

1325
const ArticleEditor = () => {
1426
const { setCursorType } = useCursor();
1527
const [articleKey, setArticleKey] = useState<string>('');
28+
const [articleType, setArticleType] = useState<'New' | 'Update'>('New');
1629
const [queryArticleKey, setQueryArticleKey] = useState<string>('');
1730
const [state, setState] = useState<ArticleWithContent>(ARTICLE_DEFAULT);
1831
const { data, isPending } = useGetEditorArticleData(queryArticleKey);
19-
const { mutate } = useAddArticle();
32+
const { mutate: addArticleMutation } = useAddArticle();
33+
const { mutate: updateArticleMutation } = useUpdateArticle();
2034

2135
useLayoutEffect(() => {
2236
setCursorType('none');
2337
}, [setCursorType]);
2438

2539
const onSubmit = useCallback(() => {
26-
mutate(getRequestObject(state));
27-
console.log('Submitting article', state);
28-
}, [mutate, state]);
40+
console.log('State', articleType);
41+
42+
if (articleType === 'New') {
43+
addArticleMutation(getRequestObject(state));
44+
return;
45+
}
46+
47+
updateArticleMutation(getRequestObject(state));
48+
}, [addArticleMutation, articleType, state, updateArticleMutation]);
2949

3050
useLayoutEffect(() => {
3151
if (data) {
32-
console.log('Data', (data as any)?.data.rows[0]);
33-
console.log('state', state);
34-
setState((data as any)?.data.rows[0]);
52+
const dataFromReq = (data as any)?.data.rows[0];
53+
setState({ ...dataFromReq, author: JSON.parse(dataFromReq.author).name });
54+
setQueryArticleKey('');
3555
}
3656
}, [data, state]);
3757

@@ -55,6 +75,15 @@ const ArticleEditor = () => {
5575
>
5676
Article editor
5777
</Text>
78+
<RadioGroup
79+
value={articleType}
80+
onChange={(value) => {
81+
setArticleType(value as 'New' | 'Update');
82+
}}
83+
>
84+
<Radio value="New">New Article</Radio>
85+
<Radio value="Update">Update Article</Radio>
86+
</RadioGroup>
5887
<Button
5988
onClick={() => {
6089
setState(ARTICLE_DEFAULT);
@@ -144,7 +173,7 @@ const ArticleEditor = () => {
144173
onClick={onSubmit}
145174
isDisabled={!isValidArticle(state)}
146175
>
147-
Submit Article
176+
{articleType === 'New' ? 'Submit' : 'Update'} Article
148177
</Button>
149178
</VStack>
150179
<VStack borderLeft={'1px solid gray'} p={1}>
@@ -165,29 +194,38 @@ const ArticleEditor = () => {
165194
<ArticleCard {...state} />
166195
</VStack>
167196
</HStack>
168-
<Box w={'100%'} h={'100%'} borderRadius={'md'}>
169-
<ArticlePreviewDrawer mdString={state.md_data} />
170-
</Box>
197+
<Divider />
198+
<Text fontSize={'xl'} fontWeight={'bold'} color={'white'}>
199+
Article Content
200+
</Text>
171201
<HStack
172202
width={'100%'}
203+
height={'100%'}
173204
border={'1px solid white'}
174205
borderRadius={'md'}
175206
p={2}
176207
className=" min-h-[100vh]"
177208
align={'start'}
178209
>
179-
<MDXEditor
180-
className="bg-white"
181-
markdown={state.md_data}
182-
plugins={ALL_PLUGINS}
183-
spellCheck={true}
184-
contentEditableClassName="min-h-[100vh] px-6 py-6 prose"
185-
onChange={(md) => {
210+
<Box
211+
w={'50%'}
212+
height={'100%'}
213+
minH={'100vh'}
214+
borderRight={'1px solid white'}
215+
>
216+
<MdPreview mdString={state.md_data} />
217+
</Box>
218+
<Textarea
219+
w={'50%'}
220+
h={'100%'}
221+
minH={'100vh'}
222+
value={state.md_data}
223+
onChange={(e) =>
186224
setState((prev) => ({
187225
...prev,
188-
md_data: md,
189-
}));
190-
}}
226+
md_data: e.target.value,
227+
}))
228+
}
191229
/>
192230
</HStack>
193231
</VStack>

src/screens/common/NavigationBar.tsx

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import { Box, HStack, Img, Spinner, Text } from '@chakra-ui/react';
1+
import { Box, HStack, IconButton, Img, Text } from '@chakra-ui/react';
22
import { LinkButton, useCursor } from '@components';
33
import AmitRaikwarLogo from '@assets/images/AmitRaikwarLogo.png';
4-
import { SearchIcon } from '@assets';
4+
import { RefreshIcon, SearchIcon } from '@assets';
55
import { useRef } from 'react';
66
import { useTranslation } from 'react-i18next';
77
import { useLocation, useNavigate } from 'react-router-dom';
@@ -36,7 +36,7 @@ const ArticleLink = {
3636

3737
const NavigationBar = () => {
3838
const moveToTop = useMoveToTop();
39-
const { data } = usePingTest();
39+
const { data, refetch, isPending } = usePingTest();
4040
const location = useLocation();
4141
const pathName = location.pathname;
4242
const navigate = useNavigate();
@@ -138,13 +138,22 @@ const NavigationBar = () => {
138138
<HStack
139139
onClick={() => {}} // eslint-disable-line
140140
>
141-
<Box
141+
<HStack
142142
display={pathName === BASE_URL_ROUTE ? 'none' : 'flex'}
143143
border={'1px solid gray'}
144+
p={2}
144145
>
145-
<Text color={'white'} fontSize={'lg'} p={2}>
146+
<IconButton
147+
size={'sm'}
148+
aria-label={''}
149+
icon={<RefreshIcon />}
150+
isDisabled={isPending}
151+
isLoading={isPending}
152+
onClick={() => refetch()}
153+
/>
154+
<Text color={'white'} fontSize={'lg'}>
146155
Server :{' '}
147-
{isUndefined(data) ? (
156+
{isUndefined(data) || isPending ? (
148157
<>
149158
<Box
150159
as="span"
@@ -154,7 +163,6 @@ const NavigationBar = () => {
154163
bg={'red.500'}
155164
display="inline-block"
156165
/>
157-
<Spinner size="xs" color="white" />
158166
</>
159167
) : (
160168
<Box
@@ -167,7 +175,7 @@ const NavigationBar = () => {
167175
/>
168176
)}
169177
</Text>
170-
</Box>
178+
</HStack>
171179
<Box
172180
onMouseEnter={onMouseEnter}
173181
onMouseLeave={onMouseLeave}

src/services/backend/articles/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,6 @@ export { default as addComment } from './addComment';
77
export { default as getComments } from './getComments';
88

99
export { default as getEditorArticleData } from './getEditorArticleData';
10+
export { default as updateArticle } from './updateArticle';
1011

1112
export { default as pingTest } from './pingTest';
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { PostRequest } from '../client/client';
2+
import { UPDATE_ARTICLE_URL } from './constants';
3+
4+
const updateArticle = async (data: unknown) =>
5+
PostRequest(UPDATE_ARTICLE_URL, data);
6+
7+
export default updateArticle;

src/services/hooks/articles/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@ export { default as useLikeArticleData } from './useLikeArticleData';
55
export { default as useAddArticle } from './useAddArticle';
66
export { default as useAddComment } from './useAddComment';
77
export { default as useGetComments } from './useGetComments';
8+
export { default as useUpdateArticle } from './useUpdateArticle';
89

910
export { default as usePingTest } from './usePingTest';
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { useToast } from '@chakra-ui/react';
2+
import { updateArticle } from '../../backend';
3+
import { useCallSBMutation } from '../common';
4+
5+
const useUpdateArticle = () => {
6+
const toast = useToast();
7+
return useCallSBMutation({
8+
method: (data) => updateArticle(data),
9+
mutationOptions: {
10+
onSuccess: () => {
11+
toast({
12+
title: 'Article updated.',
13+
status: 'success',
14+
duration: 3000,
15+
isClosable: true,
16+
});
17+
},
18+
onError: () => {
19+
toast({
20+
title: 'Error.',
21+
status: 'error',
22+
duration: 3000,
23+
isClosable: true,
24+
});
25+
},
26+
},
27+
});
28+
};
29+
30+
export default useUpdateArticle;

0 commit comments

Comments
 (0)