Skip to content

Commit 582d88e

Browse files
Merge pull request CS3219-AY2324S1#1 from cheehongw/zq-23
Use redux to keep track of questions state
2 parents 8e6d141 + c729f17 commit 582d88e

File tree

7 files changed

+132
-45
lines changed

7 files changed

+132
-45
lines changed

frontend/package-lock.json

Lines changed: 47 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

frontend/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
"@chakra-ui/react": "^2.8.1",
88
"@emotion/react": "^11.11.1",
99
"@emotion/styled": "^11.11.0",
10+
"@reduxjs/toolkit": "^1.9.7",
1011
"@testing-library/jest-dom": "^5.17.0",
1112
"@testing-library/react": "^13.4.0",
1213
"@testing-library/user-event": "^13.5.0",

frontend/src/components/QnFilter/QnFilter.component.tsx

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,19 @@ import { Flex, HStack, Input } from "@chakra-ui/react";
22
import { QnFilter } from "../../models/Quesiton.model";
33
import React, { useState } from "react";
44

5-
export interface filterprop extends QnFilter {
6-
onFilterChange?: (filter: QnFilter) => void; // refilters original db
5+
export interface FilterBarProps extends QnFilter {
6+
setFilter : (filter: QnFilter) => void; // refilters original db
77
}
88

99
export const FilterBar = ({
1010
qnFilter = "",
1111
tagFilter = new Set(),
1212
difficultyFilter = [0, 100],
1313
titleAscd = true,
14-
onFilterChange,
15-
}: filterprop) => {
14+
setFilter,
15+
}: FilterBarProps) => {
1616
const [txtFilter, setTextFilter] = useState(qnFilter);
17+
1718
const filterChange = (event: React.FormEvent<HTMLInputElement>) => {
1819
setTextFilter((event.target as HTMLInputElement).value);
1920
const newFilter: QnFilter = {
@@ -23,16 +24,17 @@ export const FilterBar = ({
2324
titleAscd: titleAscd,
2425
};
2526

26-
if (onFilterChange) onFilterChange(newFilter);
27+
if (setFilter) setFilter(newFilter);
2728
};
29+
2830
return (
2931
<Flex w="80%" px="6" py="4" align={"center"} justify={"space-between"}>
3032
<HStack spacing="1">
3133
<Input
3234
variant="outline"
3335
placeholder={qnFilter || "Find Questions"}
3436
borderRadius="15"
35-
onChange={(ev) => filterChange(ev)}
37+
onChange={filterChange}
3638
value={txtFilter}
3739
></Input>
3840
</HStack>

frontend/src/index.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,17 @@ import React from 'react';
22
import ReactDOM from 'react-dom/client';
33
import App from './App';
44
import { ChakraProvider } from "@chakra-ui/react"
5+
import { Provider } from 'react-redux';
6+
import store from './reducers/store';
57

68

79
const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement);
810
root.render(
911
<React.StrictMode>
1012
<ChakraProvider>
11-
<App />
13+
<Provider store={store}>
14+
<App />
15+
</Provider>
1216
</ChakraProvider>
1317
</React.StrictMode>,
1418
);

frontend/src/pages/BankPage/Bank.page.tsx

Lines changed: 15 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,30 @@
1-
import React, { useState } from "react";
1+
import React, { useEffect, useState } from "react";
22
import { QnTable } from "../../components/QnTable/QnTable.component";
33
import { FilterBar } from "../../components/QnFilter/QnFilter.component";
44
import { VStack } from "@chakra-ui/react";
55
import { QnFilter } from "../../models/Quesiton.model";
66
import { Question } from "../../models/Quesiton.model";
77
import { dummyQn } from "../../data/sampleqn";
8+
import { useDispatch, useSelector } from "react-redux";
9+
import { selectFilteredQuestions, setQuestions } from "../../reducers/questionsSlice";
10+
import { RootState } from "../../reducers/store";
811

9-
const filterQn = (questions: Question[], filter: QnFilter) => {
10-
return questions.filter((qn) => {
11-
if (filter.difficultyFilter) {
12-
if (
13-
qn.difficulty > filter.difficultyFilter[1] ||
14-
qn.difficulty < filter.difficultyFilter[0]
15-
)
16-
return false;
17-
}
18-
19-
if (filter.tagFilter && filter.tagFilter.size) {
20-
if (qn.categories.every((tag) => !filter.tagFilter?.has(tag))) {
21-
return false;
22-
}
23-
}
24-
25-
if (filter.qnFilter) {
26-
if (qn.displayedQuestion.toLowerCase().indexOf(filter.qnFilter) === -1) {
27-
return false;
28-
}
29-
}
30-
31-
return true;
32-
});
33-
};
3412

3513
const BankPage = () => {
36-
const allQuestion = dummyQn;
37-
const [filter, changeFilter] = useState<QnFilter>({});
38-
const [filteredQn, setFilteredQn] = useState<Question[]>(
39-
filterQn(allQuestion, filter)
40-
);
41-
const onFilterChange = (newFilter: QnFilter) => {
42-
changeFilter(newFilter);
43-
setFilteredQn(filterQn(allQuestion, newFilter));
44-
};
14+
const [filter, setFilter] = useState<QnFilter>({});
15+
const filteredQns = useSelector((state : RootState) => selectFilteredQuestions(state, filter))
16+
const dispatch = useDispatch();
17+
18+
useEffect(() => {
19+
console.log('dispatching...')
20+
setTimeout(() => dispatch(setQuestions(dummyQn)), 3000) //simulating network fetch
21+
}, [])
22+
4523
return (
4624
<VStack spacing="3">
47-
<FilterBar onFilterChange={onFilterChange} />
25+
<FilterBar setFilter={setFilter} />
4826

49-
<QnTable filteredQn={filteredQn} pageSize={7}></QnTable>
27+
<QnTable filteredQn={filteredQns} pageSize={7}></QnTable>
5028
</VStack>
5129
);
5230
};
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { createSlice } from '@reduxjs/toolkit';
2+
import { RootState } from './store';
3+
import { QnFilter, Question } from '../models/Quesiton.model';
4+
5+
6+
const questionsSlice = createSlice({
7+
name: 'questions',
8+
initialState: {
9+
originalQuestions: [] as Question[]
10+
},
11+
reducers: {
12+
setQuestions: (state, action) => {
13+
state.originalQuestions = action.payload;
14+
}
15+
},
16+
});
17+
18+
export const selectFilteredQuestions = (state: RootState, filter: QnFilter) => {
19+
return state.questions.originalQuestions.filter((qn) => {
20+
if (filter.difficultyFilter) {
21+
if (
22+
qn.difficulty > filter.difficultyFilter[1] ||
23+
qn.difficulty < filter.difficultyFilter[0]
24+
)
25+
return false;
26+
}
27+
28+
if (filter.tagFilter && filter.tagFilter.size) {
29+
if (qn.categories.every((tag) => !filter.tagFilter?.has(tag))) {
30+
return false;
31+
}
32+
}
33+
34+
if (filter.qnFilter) {
35+
if (qn.displayedQuestion.toLowerCase().indexOf(filter.qnFilter) === -1) {
36+
return false;
37+
}
38+
}
39+
40+
return true;
41+
});
42+
}
43+
44+
export const { setQuestions } = questionsSlice.actions;
45+
export default questionsSlice.reducer;

frontend/src/reducers/store.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { configureStore } from '@reduxjs/toolkit';
2+
import questionReducer from './questionsSlice'
3+
4+
const store = configureStore({
5+
reducer: {
6+
questions: questionReducer
7+
}
8+
});
9+
10+
export type RootState = ReturnType<typeof store.getState>;
11+
export default store;

0 commit comments

Comments
 (0)