Skip to content

Commit 1894663

Browse files
committed
migrate my-questions, my-answers to MST store
1 parent a5086f7 commit 1894663

File tree

7 files changed

+9875
-9865
lines changed

7 files changed

+9875
-9865
lines changed

public/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<meta charset="UTF-8">
66
<meta name="viewport" content="width=device-width, initial-scale=1.0">
77
<meta http-equiv="X-UA-Compatible" content="ie=edge">
8-
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline' 'unsafe-eval' https://jmblog.github.io/ https://cdn.jsdelivr.net/ https://api.stackexchange.com/; img-src *">
8+
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline' 'unsafe-eval' https://jmblog.github.io/ https://cdn.jsdelivr.net/ https://api.stackexchange.com/ wss://qa.sockets.stackexchange.com/; img-src *">
99

1010
<title>StackOverflow</title>
1111

src/models/question-store/question-store.ts

Lines changed: 83 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,42 @@ import stackoverflow from '../../uitls/stackexchange-api';
44
import { PaginationController } from '../../hooks/use-pagination';
55
import { promiser } from '../../uitls/promiser';
66
import { ResponseType } from '../../interfaces/Response';
7+
import { AnswerType } from '../../interfaces/AnswerType';
78

8-
export const AllQuestionsFilter =
9+
export const ALL_QUESTIONS_FILTER =
910
'!HzgO6Jg6sME4H_1lyzjHHRxMDyjoWkuK(8Xe125IMyd4rNGmzV(xVm79voQW*H7_CY)rZkEokE8LKn2_KZ4TJ5F0.2rZ1';
1011

12+
async function getMyAnswersQuestionIds(page: number, perPage: number) {
13+
const [response, error] = await promiser<ResponseType<AnswerType>>(
14+
stackoverflow.get('me/answers', {
15+
order: 'desc',
16+
sort: 'creation',
17+
page,
18+
pagesize: perPage,
19+
filter: '!AH)b5JZk)e5p'
20+
})
21+
);
22+
23+
const ids = response.items.map((answer: AnswerType) => answer.question_id);
24+
25+
return [ids, response.total];
26+
}
27+
1128
export const QuestionStoreModel = types
1229
.model('QuestionStore')
1330
.props({
1431
isQuestionsFetching: false,
15-
isBookmarksFetching: false,
32+
isMyBookmarksFetching: false,
33+
isMyQuestionsFetching: false,
34+
isMyAnswersFetching: false,
1635
questionsFilter: types.optional(
1736
types.enumeration('QuestionsFilter', ['interesting', 'bountied', 'hot']),
1837
'interesting'
1938
),
2039
questions: types.optional(types.array(QuestionModel), []),
21-
myBookmarks: types.optional(types.array(QuestionModel), [])
40+
myBookmarks: types.optional(types.array(QuestionModel), []),
41+
myQuestions: types.optional(types.array(QuestionModel), []),
42+
myAnswers: types.optional(types.array(QuestionModel), [])
2243
})
2344
.actions((self) => ({
2445
setQuestions(questions: QuestionType[]) {
@@ -27,11 +48,23 @@ export const QuestionStoreModel = types
2748
setMyBookmarks(questions: QuestionType[]) {
2849
self.myBookmarks.replace(questions);
2950
},
51+
setMyQuestions(questions: QuestionType[]) {
52+
self.myQuestions.replace(questions);
53+
},
54+
setMyAnswers(questions: QuestionType[]) {
55+
self.myAnswers.replace(questions);
56+
},
3057
setIsQuestionsFetching(state: boolean) {
3158
self.isQuestionsFetching = state;
3259
},
33-
setIsBookmarksFetching(state: boolean) {
34-
self.isBookmarksFetching = state;
60+
setIsMyBookmarksFetching(state: boolean) {
61+
self.isMyBookmarksFetching = state;
62+
},
63+
setIsMyQuestionsFetching(state: boolean) {
64+
self.isMyQuestionsFetching = state;
65+
},
66+
setIsMyAnswersFetching(state: boolean) {
67+
self.isMyAnswersFetching = state;
3568
},
3669
setQuestionsFilter(filter: 'interesting' | 'bountied' | 'hot') {
3770
self.questionsFilter = filter;
@@ -48,7 +81,7 @@ export const QuestionStoreModel = types
4881
sort: 'creation',
4982
page: pagination.page,
5083
pagesize: pagination.perPage,
51-
filter: AllQuestionsFilter
84+
filter: ALL_QUESTIONS_FILTER
5285
};
5386

5487
if (filter === 'bountied') {
@@ -65,22 +98,62 @@ export const QuestionStoreModel = types
6598
pagination.setTotal(response.total);
6699
self.setIsQuestionsFetching(false);
67100
},
68-
async getBookmarks(pagination: PaginationController) {
69-
self.setIsBookmarksFetching(true);
101+
async getMyBookmarks(pagination: PaginationController) {
102+
self.setIsMyBookmarksFetching(true);
70103

71104
const [response, error] = await promiser<ResponseType<QuestionType>>(
72105
stackoverflow.get('me/favorites', {
73106
order: 'desc',
74107
sort: 'added',
75108
page: pagination.page,
76109
pagesize: pagination.perPage,
77-
filter: '!HzgO6Jg6sME4H_1lyzjHHRxMDyjoWkuK(8Xe125IMyd4rNGmzV(xVm79voQW*H7_CY)rZkEokE8LKn2_KZ4TJ5F0.2rZ1'
110+
filter: ALL_QUESTIONS_FILTER
78111
})
79112
);
80113

81114
self.setMyBookmarks(response.items);
82115
pagination.setTotal(response.total);
83-
self.setIsBookmarksFetching(false);
116+
self.setIsMyBookmarksFetching(false);
117+
},
118+
async getMyQuestions(pagination: PaginationController) {
119+
self.setIsMyQuestionsFetching(true);
120+
121+
const [response, error] = await promiser<ResponseType<QuestionType>>(
122+
stackoverflow.get('me/questions', {
123+
order: 'desc',
124+
sort: 'creation',
125+
page: pagination.page,
126+
pagesize: pagination.perPage,
127+
filter: ALL_QUESTIONS_FILTER
128+
})
129+
);
130+
131+
self.setMyQuestions(response.items);
132+
pagination.setTotal(response.total);
133+
self.setIsMyQuestionsFetching(false);
134+
},
135+
async getMyAnswers(pagination: PaginationController) {
136+
self.setIsMyAnswersFetching(true);
137+
138+
const [questionIds, answerTotal] = await getMyAnswersQuestionIds(pagination.page, pagination.perPage);
139+
140+
if (questionIds.length === 0) {
141+
self.setIsMyAnswersFetching(false);
142+
return;
143+
}
144+
145+
const [response, error] = await promiser<ResponseType<QuestionType>>(
146+
stackoverflow.get(`questions/${questionIds.join(';')}`, {
147+
order: 'desc',
148+
sort: 'creation',
149+
filter: ALL_QUESTIONS_FILTER
150+
})
151+
);
152+
153+
self.setMyAnswers(response.items);
154+
pagination.setTotal(answerTotal);
155+
console.log('toggle flag');
156+
self.setIsMyAnswersFetching(false);
84157
}
85158
}));
86159

src/models/user-store/user.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { Instance, types } from 'mobx-state-tree';
22

33
export const UserModel = types.model({
4+
user_type: types.enumeration('UserType', ['registered', 'unregistered', 'does_not_exist']),
45
about_me: types.maybe(types.string),
56
account_id: types.maybe(types.number),
67
answer_count: types.maybe(types.number),
@@ -10,7 +11,7 @@ export const UserModel = types.model({
1011
location: types.maybe(types.string),
1112
profile_image: types.maybe(types.string),
1213
question_count: types.maybe(types.number),
13-
reputation: types.number,
14+
reputation: types.maybe(types.number),
1415
user_id: types.maybe(types.number),
1516
view_count: types.maybe(types.number),
1617
website_url: types.maybe(types.string)

src/pages/MyAnswersPage.tsx

Lines changed: 13 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,21 @@
1-
import { useEffect, useState } from 'react';
2-
import { QuestionType } from '../interfaces/QuestionType';
1+
import { useEffect } from 'react';
32
import { QuestionListItem } from '../components/posts/QuestionListItem';
4-
import stackoverflow from '../uitls/stackexchange-api';
5-
import { Box, Center, Stack, Text } from "@chakra-ui/react";
3+
import { Box, Center, Stack, Text } from '@chakra-ui/react';
64
import { QuestionListItemSkeleton } from '../components/posts/QuestionListItem.skeleton';
7-
import { AnswerType } from '../interfaces/AnswerType';
85
import { Pagination } from '../components/ui/Pagination';
96
import { usePagination } from '../hooks/use-pagination';
10-
import { GoTriangleUp } from "react-icons/go";
7+
import { useStores } from '../models';
8+
import { observer } from 'mobx-react-lite';
119

12-
export function MyAnswersPage() {
10+
export const MyAnswersPage = observer(() => {
11+
const { questionStore } = useStores();
1312
const pagination = usePagination();
14-
const [isLoaded, setIsLoaded] = useState(false);
15-
const [questions, setQuestions] = useState<QuestionType[]>([]);
1613

1714
useEffect(() => {
18-
(async () => {
19-
setIsLoaded(false);
20-
21-
const questionIds = await getAnswersQuestionIds(pagination.page, pagination.perPage);
22-
23-
if (questionIds.length === 0) {
24-
setIsLoaded(true);
25-
return;
26-
}
27-
28-
const response: any = await stackoverflow.get(`questions/${questionIds.join(';')}`, {
29-
order: 'desc',
30-
sort: 'creation',
31-
filter: '!HzgO6Jg6sME4H_1lyzjHHRxMDyjoWkuK(8Xe125IMyd4rNGmzV(xVm79voQW*H7_CY)rZkEokE8LKn2_KZ4TJ5F0.2rZ1'
32-
});
33-
34-
setQuestions(response.items);
35-
setIsLoaded(true);
36-
})();
15+
questionStore.getMyAnswers(pagination);
3716
}, [pagination.page, pagination.perPage]);
3817

39-
function getAnswersQuestionIds(page: number, perPage: number) {
40-
return stackoverflow
41-
.get('me/answers', {
42-
order: 'desc',
43-
sort: 'creation',
44-
page,
45-
pagesize: perPage,
46-
filter: '!AH)b5JZk)e5p'
47-
})
48-
.then((response: any) => {
49-
pagination.setTotal(response.total);
50-
51-
return response.items.map((answer: AnswerType) => answer.question_id);
52-
});
53-
}
54-
55-
if (isLoaded && !questions.length) {
18+
if (!questionStore.isMyAnswersFetching && !questionStore.myAnswers.length) {
5619
return (
5720
<Center color="gray.500" height="200px">
5821
You have no any answers yet.
@@ -64,9 +27,11 @@ export function MyAnswersPage() {
6427
<>
6528
<Stack spacing="8px">
6629
{/* Skeletons */}
67-
{!isLoaded && [...Array(pagination.perPage)].map((_, index) => <QuestionListItemSkeleton key={index} />)}
30+
{questionStore.isMyAnswersFetching &&
31+
[...Array(pagination.perPage)].map((_, index) => <QuestionListItemSkeleton key={index} />)}
6832

69-
{isLoaded && questions.map((question) => <QuestionListItem item={question} key={question.question_id} />)}
33+
{!questionStore.isMyAnswersFetching &&
34+
questionStore.myAnswers.map((question) => <QuestionListItem item={question} key={question.question_id} />)}
7035
</Stack>
7136

7237
{pagination.totalPages > 0 && (
@@ -76,4 +41,4 @@ export function MyAnswersPage() {
7641
)}
7742
</>
7843
);
79-
}
44+
});

src/pages/MyBookmarksPage.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@ export function MyBookmarksPage() {
1111
const pagination = usePagination();
1212

1313
useEffect(() => {
14-
questionStore.getBookmarks(pagination);
14+
questionStore.getMyBookmarks(pagination);
1515
}, [pagination.page, pagination.perPage]);
1616

17-
if (!questionStore.isBookmarksFetching && !questionStore.myBookmarks.length) {
17+
if (!questionStore.isMyBookmarksFetching && !questionStore.myBookmarks.length) {
1818
return (
1919
<Center color="gray.500" height="200px">
2020
You have no any bookmarks yet.
@@ -26,10 +26,10 @@ export function MyBookmarksPage() {
2626
<>
2727
<Stack spacing="8px">
2828
{/* Skeletons */}
29-
{questionStore.isBookmarksFetching &&
29+
{questionStore.isMyBookmarksFetching &&
3030
[...Array(pagination.perPage)].map((_, index) => <QuestionListItemSkeleton key={index} />)}
3131

32-
{!questionStore.isBookmarksFetching &&
32+
{!questionStore.isMyBookmarksFetching &&
3333
questionStore.myBookmarks.map((question) => <QuestionListItem item={question} key={question.question_id} />)}
3434
</Stack>
3535

src/pages/MyQuestionsPage.tsx

Lines changed: 13 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,21 @@
1-
import { useEffect, useState } from 'react';
2-
import { QuestionType } from '../interfaces/QuestionType';
1+
import { useEffect } from 'react';
32
import { QuestionListItem } from '../components/posts/QuestionListItem';
4-
import stackoverflow from '../uitls/stackexchange-api';
5-
import { Box, Center, Stack } from "@chakra-ui/react";
3+
import { Box, Center, Stack } from '@chakra-ui/react';
64
import { QuestionListItemSkeleton } from '../components/posts/QuestionListItem.skeleton';
75
import { Pagination } from '../components/ui/Pagination';
86
import { usePagination } from '../hooks/use-pagination';
7+
import { observer } from 'mobx-react-lite';
8+
import { useStores } from '../models';
99

10-
export function MyQuestionsPage() {
10+
export const MyQuestionsPage = observer(() => {
11+
const { questionStore } = useStores();
1112
const pagination = usePagination();
12-
const [isLoaded, setIsLoaded] = useState(false);
13-
const [questions, setQuestions] = useState<QuestionType[]>([]);
1413

1514
useEffect(() => {
16-
stackoverflow
17-
.get('me/questions', {
18-
order: 'desc',
19-
sort: 'creation',
20-
page: pagination.page,
21-
pagesize: pagination.perPage,
22-
filter: '!HzgO6Jg6sME4H_1lyzjHHRxMDyjoWkuK(8Xe125IMyd4rNGmzV(xVm79voQW*H7_CY)rZkEokE8LKn2_KZ4TJ5F0.2rZ1'
23-
})
24-
.then((response) => {
25-
pagination.setTotal((response as any).total);
26-
setQuestions((response as any).items);
27-
setIsLoaded(true);
28-
});
15+
questionStore.getMyQuestions(pagination);
2916
}, [pagination.page, pagination.perPage]);
3017

31-
if (isLoaded && !questions.length) {
18+
if (!questionStore.isMyQuestionsFetching && !questionStore.myQuestions.length) {
3219
return (
3320
<Center color="gray.500" height="200px">
3421
You have no any questions yet.
@@ -40,9 +27,11 @@ export function MyQuestionsPage() {
4027
<>
4128
<Stack spacing="8px">
4229
{/* Skeletons */}
43-
{!isLoaded && [...Array(10)].map((_, index) => <QuestionListItemSkeleton key={index} />)}
30+
{questionStore.isMyQuestionsFetching &&
31+
[...Array(10)].map((_, index) => <QuestionListItemSkeleton key={index} />)}
4432

45-
{isLoaded && questions.map((question) => <QuestionListItem item={question} key={question.question_id} />)}
33+
{!questionStore.isMyQuestionsFetching &&
34+
questionStore.myQuestions.map((question) => <QuestionListItem item={question} key={question.question_id} />)}
4635
</Stack>
4736

4837
{pagination.totalPages > 0 && (
@@ -52,4 +41,4 @@ export function MyQuestionsPage() {
5241
)}
5342
</>
5443
);
55-
}
44+
});

0 commit comments

Comments
 (0)