Skip to content

Commit 6a9551c

Browse files
committed
feat(): Adding the streak and sort by feature
1 parent a450ddf commit 6a9551c

12 files changed

Lines changed: 336 additions & 130 deletions

File tree

src/assets/icons/Common/Streak.tsx

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { SVGProps } from 'react';
2+
3+
function StreakIcon(props: SVGProps<SVGSVGElement>) {
4+
return (
5+
<svg
6+
xmlns="http://www.w3.org/2000/svg"
7+
viewBox="0 0 24 24"
8+
width="1em"
9+
height="1em"
10+
{...props}
11+
>
12+
<path
13+
fill="currentColor"
14+
d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10s10-4.48 10-10S17.52 2 12 2m0 18c-4.42 0-8-3.58-8-8s3.58-8 8-8s8 3.58 8 8s-3.58 8-8 8"
15+
></path>
16+
<path
17+
fill="currentColor"
18+
d="M13.54 8.97c-.23-.47-.76-.71-1.26-.53L9 9.65V12h1v-1.65l1.54-.57l-.96 4.89l-2.78-.57l-.2.98l3.76.77l.52-2.64L13 14.42V18h1v-3.97l-1.32-1.44l.41-2.35C13.99 11.46 15.3 12 16 12v-1c-.41 0-1.63-.33-2.46-2.03"
19+
></path>
20+
<circle cx="13.5" cy="7" r="1" fill="currentColor"></circle>
21+
</svg>
22+
);
23+
}
24+
25+
export default StreakIcon;

src/assets/icons/Common/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,5 @@ export { default as InstagramIcon } from './InstagramIcon';
1414
export { default as StarIcon } from './Star';
1515
export { default as StarTrekIcon } from './Startrek';
1616
export { default as Redirect } from './Redirect';
17+
export { default as StreakIcon } from './Streak';
1718
export { default as NpmIcon } from './NpmIcon';

src/screens/articleEditor/ArticleEditor.tsx

Lines changed: 1 addition & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,4 @@
11
import {
2-
AlertDialog,
3-
AlertDialogBody,
4-
AlertDialogContent,
5-
AlertDialogFooter,
6-
AlertDialogHeader,
7-
AlertDialogOverlay,
82
Box,
93
Button,
104
Divider,
@@ -14,7 +8,6 @@ import {
148
RadioGroup,
159
Text,
1610
Textarea,
17-
useDisclosure,
1811
VStack,
1912
} from '@chakra-ui/react';
2013
import '@mdxeditor/editor/style.css';
@@ -25,77 +18,10 @@ import { ArticleWithContent } from './types';
2518
import { getRequestObject, isValidArticle } from './utils';
2619
import {
2720
useAddArticle,
28-
useDeleteArticle,
2921
useGetEditorArticleData,
3022
useUpdateArticle,
3123
} from '@services';
32-
import React from 'react';
33-
import { isEmpty } from 'lodash';
34-
35-
const DeleteArticleButton = ({
36-
articleKey,
37-
onDelete,
38-
}: {
39-
articleKey: string;
40-
onDelete: () => void;
41-
}) => {
42-
const { mutate } = useDeleteArticle();
43-
const { isOpen, onOpen, onClose } = useDisclosure();
44-
const cancelRef = React.useRef<HTMLButtonElement>(null);
45-
const [articleKeyValidation, setArticleKeyValidation] = useState<string>('');
46-
47-
return (
48-
<>
49-
<Button
50-
colorScheme="red"
51-
onClick={onOpen}
52-
isDisabled={isEmpty(articleKey)}
53-
>
54-
Delete Article
55-
</Button>
56-
<AlertDialog
57-
isOpen={isOpen}
58-
leastDestructiveRef={cancelRef}
59-
onClose={onClose}
60-
>
61-
<AlertDialogOverlay>
62-
<AlertDialogContent>
63-
<AlertDialogHeader fontSize="lg" fontWeight="bold">
64-
Delete Customer
65-
</AlertDialogHeader>
66-
67-
<AlertDialogBody>
68-
{`Are you sure of deleting the article? You can't undo this action afterwards.`}
69-
<Input
70-
mt={3}
71-
placeholder={`Type ${articleKey} to confirm`}
72-
value={articleKeyValidation}
73-
onChange={(e) => setArticleKeyValidation(e.target.value)}
74-
/>
75-
</AlertDialogBody>
76-
<AlertDialogFooter>
77-
<Button ref={cancelRef} onClick={onClose}>
78-
Cancel
79-
</Button>
80-
<Button
81-
colorScheme="red"
82-
onClick={() => {
83-
mutate({ articleKey });
84-
onClose();
85-
onDelete();
86-
}}
87-
isDisabled={articleKeyValidation !== articleKey}
88-
ml={3}
89-
>
90-
Delete
91-
</Button>
92-
</AlertDialogFooter>
93-
</AlertDialogContent>
94-
</AlertDialogOverlay>
95-
</AlertDialog>
96-
</>
97-
);
98-
};
24+
import { DeleteArticleButton } from './components';
9925

10026
const ArticleEditor = () => {
10127
const { setCursorType } = useCursor();

src/screens/articleEditor/ArticlePreviewDrawar.tsx

Lines changed: 0 additions & 49 deletions
This file was deleted.
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import {
2+
useDisclosure,
3+
Button,
4+
AlertDialog,
5+
AlertDialogOverlay,
6+
AlertDialogContent,
7+
AlertDialogHeader,
8+
AlertDialogBody,
9+
Input,
10+
AlertDialogFooter,
11+
} from '@chakra-ui/react';
12+
import { useDeleteArticle } from '@services';
13+
import { isEmpty } from 'lodash';
14+
import React, { useState } from 'react';
15+
16+
const DeleteArticleButton = ({
17+
articleKey,
18+
onDelete,
19+
}: {
20+
articleKey: string;
21+
onDelete: () => void;
22+
}) => {
23+
const { mutate } = useDeleteArticle();
24+
const { isOpen, onOpen, onClose } = useDisclosure();
25+
const cancelRef = React.useRef<HTMLButtonElement>(null);
26+
const [articleKeyValidation, setArticleKeyValidation] = useState<string>('');
27+
28+
return (
29+
<>
30+
<Button
31+
colorScheme="red"
32+
onClick={onOpen}
33+
isDisabled={isEmpty(articleKey)}
34+
>
35+
Delete Article
36+
</Button>
37+
<AlertDialog
38+
isOpen={isOpen}
39+
leastDestructiveRef={cancelRef}
40+
onClose={onClose}
41+
>
42+
<AlertDialogOverlay>
43+
<AlertDialogContent>
44+
<AlertDialogHeader fontSize="lg" fontWeight="bold">
45+
Delete Customer
46+
</AlertDialogHeader>
47+
48+
<AlertDialogBody>
49+
{`Are you sure of deleting the article? You can't undo this action afterwards.`}
50+
<Input
51+
mt={3}
52+
placeholder={`Type ${articleKey} to confirm`}
53+
value={articleKeyValidation}
54+
onChange={(e) => setArticleKeyValidation(e.target.value)}
55+
/>
56+
</AlertDialogBody>
57+
<AlertDialogFooter>
58+
<Button ref={cancelRef} onClick={onClose}>
59+
Cancel
60+
</Button>
61+
<Button
62+
colorScheme="red"
63+
onClick={() => {
64+
mutate({ articleKey });
65+
onClose();
66+
onDelete();
67+
}}
68+
isDisabled={articleKeyValidation !== articleKey}
69+
ml={3}
70+
>
71+
Delete
72+
</Button>
73+
</AlertDialogFooter>
74+
</AlertDialogContent>
75+
</AlertDialogOverlay>
76+
</AlertDialog>
77+
</>
78+
);
79+
};
80+
81+
export default DeleteArticleButton;
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { default as DeleteArticleButton } from './DeleteArticleButton';

src/screens/articles/ArticlesScreen.tsx

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@ import { Button, HStack, Text, VStack, Wrap } from '@chakra-ui/react';
22
import { ArticleCard, LoadingSpinner } from '@components';
33
import { useGetArticlesData } from '@services';
44
import { useLocation, useNavigate } from 'react-router-dom';
5-
import { MarkdownViewer } from './components';
5+
import { MarkdownViewer, StreakStalker } from './components';
66
import { useMemo, useState } from 'react';
7-
import { groupBy } from 'lodash';
7+
import { groupBy, sortBy } from 'lodash';
88
import { BASE_NAV_ROUTE } from '@router';
9+
import SortBy, { SortByType } from './components/SortBy';
910

1011
const CategoryButton = ({
1112
category,
@@ -47,6 +48,7 @@ const ArticlesScreen = () => {
4748
const location = useLocation();
4849
const [category, setCategory] = useState('All');
4950
const secondPath = location.pathname.split('/')[3];
51+
const [sortByName, setSortBy] = useState<SortByType>('none');
5052

5153
const articles = useMemo(
5254
() =>
@@ -58,10 +60,29 @@ const ArticlesScreen = () => {
5860

5961
const filteredArticles = groupBy(articles, 'group_name');
6062

63+
const articleToShow =
64+
category && category !== 'All' ? filteredArticles[category] : articles;
65+
66+
const sortByApplied = useMemo(() => {
67+
if (sortByName === 'none') {
68+
return articleToShow;
69+
} else if (sortByName === 'publishedAt') {
70+
return sortBy(articleToShow, 'last_updated').reverse();
71+
} else if (sortByName === 'a-z') {
72+
return sortBy(articleToShow, 'title');
73+
} else if (sortByName === 'z-a') {
74+
return sortBy(articleToShow, 'title').reverse();
75+
} else {
76+
return articleToShow;
77+
}
78+
}, [articleToShow, sortByName]);
79+
6180
if (!data) {
6281
return <LoadingSpinner />;
6382
}
6483

84+
const date = articles.map((article: any) => article.last_updated as string);
85+
6586
return (
6687
<VStack bg={'black'} w={'100vw'} minH={'100vh'}>
6788
<Text
@@ -95,6 +116,10 @@ const ArticlesScreen = () => {
95116
top={'12vh'}
96117
marginTop={'12vh'}
97118
>
119+
<HStack>
120+
<StreakStalker dates={date} />
121+
<SortBy sortBy={sortByName} setSortBy={setSortBy} />
122+
</HStack>
98123
<CategoryButton
99124
category={'All'}
100125
setCategory={setCategory}
@@ -128,10 +153,7 @@ const ArticlesScreen = () => {
128153
justify="start"
129154
justifyContent={'space-between'}
130155
>
131-
{(category && category !== 'All'
132-
? filteredArticles[category]
133-
: articles
134-
)?.map((article: any) => (
156+
{sortByApplied?.map((article: any) => (
135157
<ArticleCard key={article.id} {...article} />
136158
))}
137159
</Wrap>
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { HStack, Text } from '@chakra-ui/react';
2+
3+
export type SortByType = 'none' | 'publishedAt' | 'a-z' | 'z-a';
4+
5+
const SortBy = ({
6+
sortBy = 'publishedAt',
7+
setSortBy,
8+
}: {
9+
sortBy: SortByType;
10+
setSortBy: (sortBy: SortByType) => void;
11+
}) => {
12+
return (
13+
<HStack spacing={0}>
14+
<Text fontSize={'sm'} fontWeight={'400'} color={'gray.500'} mr={1}>
15+
Sort By
16+
</Text>
17+
<select
18+
value={sortBy}
19+
onChange={(e) => setSortBy(e.target.value as SortByType)}
20+
>
21+
<option value="none">None</option>
22+
<option value="publishedAt">Published Date</option>
23+
<option value="a-z">A-Z</option>
24+
<option value="z-a">Z-A</option>
25+
</select>
26+
</HStack>
27+
);
28+
};
29+
30+
export default SortBy;

0 commit comments

Comments
 (0)