Skip to content

Commit 610f899

Browse files
Merge pull request #11 from CS3219-AY2425S1/ben/integrate-backend-api
feat: Ben/integrate backend api
2 parents d6f2126 + a4eb139 commit 610f899

File tree

4 files changed

+135
-28
lines changed

4 files changed

+135
-28
lines changed

apps/question-service/src/app/page.tsx

Lines changed: 68 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import {
66
Input,
77
Layout,
88
message,
9+
Pagination,
10+
PaginationProps,
911
Row,
1012
Select,
1113
Table,
@@ -32,10 +34,17 @@ import {
3234
export default function Home() {
3335
// Table States
3436
const [questions, setQuestions] = useState<Question[] | undefined>(undefined); // Store the questions
37+
const [totalCount, setTotalCount] = useState<number | undefined>(undefined); // Store the total count of questions
38+
const [totalPages, setTotalPages] = useState<number | undefined>(undefined); // Store the total number of pages
39+
const [currentPage, setCurrentPage] = useState<number | undefined>(1); // Store the current page
40+
const [limit, setLimit] = useState<number | undefined>(10); // Store the quantity of questions to be displayed
3541
const [isLoading, setIsLoading] = useState<boolean>(true); // Store the states related to table's loading
3642

3743
// Filtering States
3844
const [search, setSearch] = useState<string | undefined>(undefined); // Store the search
45+
const [delayedSearch, setDelayedSearch] = useState<string | undefined>(
46+
undefined
47+
); // Store the delayed search value
3948
const [categories, setCategories] = useState<string[]>([]); // Store the selected filter categories
4049
const [difficulty, setDifficulty] = useState<string[]>([]); // Store the selected difficulty level
4150
const [sortBy, setSortBy] = useState<string | undefined>(undefined); // Store the selected sorting parameter
@@ -66,17 +75,33 @@ export default function Home() {
6675

6776
// Include States for Create/Edit Modal (TODO: Sean)
6877

69-
// When the page is initialised, fetch all the questions ONCE and display in table
78+
// When the page is initialised, fetch all the questions and display in table
79+
// When the dependencies/states change, the useEffect hook will trigger to re-fetch the questions
7080
useEffect(() => {
7181
if (!isLoading) {
7282
setIsLoading(true);
7383
}
7484

75-
GetQuestions().then((data) => {
76-
setQuestions(data);
77-
setIsLoading(false);
78-
});
79-
}, []);
85+
GetQuestions(currentPage, limit, sortBy, difficulty, delayedSearch).then(
86+
(data) => {
87+
setQuestions(data.questions);
88+
setTotalCount(data.totalCount);
89+
setTotalPages(data.totalPages);
90+
setCurrentPage(data.currentPage);
91+
setLimit(data.limit);
92+
setIsLoading(false);
93+
}
94+
);
95+
}, [limit, currentPage, sortBy, difficulty, delayedSearch]); // TODO: (Ryan) Add dependencies for categories and edit the GetQuestion service function
96+
97+
// Delay the fetching of data only after user stops typing for awhile
98+
useEffect(() => {
99+
const timeout = setTimeout(() => {
100+
setDelayedSearch(search);
101+
setCurrentPage(1); // Reset the current page
102+
}, 800);
103+
return () => clearTimeout(timeout);
104+
}, [search]);
80105

81106
// Table column specification
82107
const columns: TableProps<Question>["columns"] = [
@@ -137,6 +162,7 @@ export default function Home() {
137162
// Handler for change in multi-select categories option
138163
const handleCategoriesChange = (value: string[]) => {
139164
setCategories(value);
165+
setCurrentPage(1); // Reset the current page
140166
};
141167

142168
// Handler for clearing the filtering options
@@ -148,8 +174,22 @@ export default function Home() {
148174
};
149175

150176
// Handler for filtering (TODO)
151-
const handleFilter = async () => {
152-
success("Filtered Successfully!");
177+
// const handleFilter = async () => {
178+
// success("Filtered Successfully!");
179+
// };
180+
181+
// Handler for show size change for pagination
182+
const onShowSizeChange: PaginationProps["onShowSizeChange"] = (
183+
current,
184+
pageSize
185+
) => {
186+
setCurrentPage(current);
187+
setLimit(pageSize);
188+
};
189+
190+
// Handler for change in page jumper
191+
const onPageJump: PaginationProps["onChange"] = (pageNumber) => {
192+
setCurrentPage(pageNumber);
153193
};
154194

155195
return (
@@ -177,6 +217,7 @@ export default function Home() {
177217
prefix={<SearchOutlined />}
178218
onChange={(e) => setSearch(e.target.value)}
179219
value={search}
220+
allowClear
180221
/>
181222
</Col>
182223
<Col span={6}>
@@ -190,12 +231,15 @@ export default function Home() {
190231
value={categories}
191232
/>
192233
</Col>
193-
<Col span={4}>
234+
<Col span={6}>
194235
<Select
195236
mode="multiple"
196237
allowClear
197238
placeholder="Difficulty"
198-
onChange={(value: string[]) => setDifficulty(value)}
239+
onChange={(value: string[]) => {
240+
setDifficulty(value);
241+
setCurrentPage(1); //Reset the currentpage since filter params changed
242+
}}
199243
options={DifficultyOption}
200244
className="difficulty-select"
201245
value={difficulty}
@@ -211,15 +255,17 @@ export default function Home() {
211255
value={sortBy}
212256
/>
213257
</Col>
214-
<Col span={4}>
215-
<Button onClick={handleClear}>Clear</Button>
216-
<Button
258+
<Col span={2}>
259+
<Button onClick={handleClear} className="clear-button">
260+
Clear
261+
</Button>
262+
{/* <Button
217263
type="primary"
218264
className="filter-button"
219265
onClick={handleFilter}
220266
>
221267
Filter
222-
</Button>
268+
</Button> */}
223269
</Col>
224270
</Row>
225271
</div>
@@ -228,6 +274,14 @@ export default function Home() {
228274
dataSource={questions}
229275
columns={columns}
230276
loading={isLoading}
277+
pagination={{
278+
current: currentPage,
279+
total: totalCount,
280+
showSizeChanger: true,
281+
onShowSizeChange: onShowSizeChange,
282+
// showQuickJumper: true,
283+
onChange: onPageJump,
284+
}}
231285
/>
232286
</div>
233287
</div>

apps/question-service/src/app/services/question.ts

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
export interface Question {
2-
id: string;
2+
id: number;
3+
docRefId: string;
34
title: string;
45
description?: string;
56
categories: string[]; // enum[]
@@ -11,9 +12,57 @@ export interface Question {
1112
testCases?: string[];
1213
}
1314

15+
export interface QuestionListResponse {
16+
totalCount: number;
17+
totalPages: number;
18+
currentPage: number;
19+
limit: number;
20+
hasNextPage: boolean;
21+
questions: Question[];
22+
}
23+
1424
// GET request to fetch all the questions (TODO: Ben --> Fetch with filtering/sorting etc)
15-
export const GetQuestions = async (): Promise<Question[]> => {
16-
const response = await fetch(`${process.env.NEXT_PUBLIC_API_URL}questions`);
25+
export const GetQuestions = async (
26+
currentPage?: number,
27+
limit?: number,
28+
sortBy?: string,
29+
difficulty?: string[],
30+
title?: string
31+
): Promise<QuestionListResponse> => {
32+
let query_url = `${process.env.NEXT_PUBLIC_API_URL}questions`;
33+
let query_params = "";
34+
35+
if (currentPage) {
36+
query_params += `?offset=${(currentPage - 1) * 10}`;
37+
}
38+
39+
if (limit) {
40+
query_params += `${query_params.length > 0 ? "&" : "?"}limit=${limit}`;
41+
}
42+
43+
if (sortBy) {
44+
const [field, order] = sortBy.split(" ");
45+
query_params += `${
46+
query_params.length > 0 ? "&" : "?"
47+
}sortField=${field}&sortValue=${order}`;
48+
}
49+
50+
if (difficulty && difficulty.length > 0) {
51+
const value = difficulty.join(","); // Change them from ["easy", "medium"] to "easy,medium"
52+
query_params += `${query_params.length > 0 ? "&" : "?"}complexity=${value}`;
53+
}
54+
55+
if (title && title != "") {
56+
const urlEncodedTitle = encodeURIComponent(title);
57+
query_params += `${
58+
query_params.length > 0 ? "&" : "?"
59+
}title=${urlEncodedTitle}`;
60+
}
61+
62+
// TODO: (Ryan) Filtering via categories
63+
64+
query_url += query_params;
65+
const response = await fetch(query_url);
1766
const data = await response.json();
1867
return data;
1968
};

apps/question-service/src/app/styles.scss

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@
4444
box-shadow: 0 2px 0 rgba(0, 0, 0, 0.02) !important;
4545
}
4646

47+
.clear-button {
48+
width: 100%;
49+
}
50+
4751
.categories-multi-select,
4852
.difficulty-select,
4953
.order-select {

apps/question-service/src/app/utils/SelectOptions.ts

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -78,49 +78,49 @@ export const CategoriesOption = [
7878
export const DifficultyOption = [
7979
{
8080
label: "Easy",
81-
value: "Easy",
81+
value: "easy",
8282
},
8383
{
8484
label: "Medium",
85-
value: "Medium",
85+
value: "medium",
8686
},
8787
{
8888
label: "Hard",
89-
value: "Hard",
89+
value: "hard",
9090
},
9191
];
9292

9393
export const OrderOption = [
9494
{
9595
label: "Id (ASC)",
96-
value: "Id (ASC)",
96+
value: "id asc",
9797
},
9898
{
9999
label: "Id (DESC)",
100-
value: "Id (DESC)",
100+
value: "id desc",
101101
},
102102
{
103103
label: "Most Recent",
104-
value: "Most Recent",
104+
value: "createdAt desc",
105105
},
106106
{
107107
label: "Oldest",
108-
value: "Oldest",
108+
value: "createdAt asc",
109109
},
110110
{
111111
label: "Alphabetical (A-Z)",
112-
value: "Alphabetical (A-Z)", // TODO: Edit the values based on backend in the future
112+
value: "title asc",
113113
},
114114
{
115115
label: "Alphabetical (Z-A)",
116-
value: "Alphabetical (Z-A)", // TODO: Edit the values based on backend in the future
116+
value: "title desc",
117117
},
118118
{
119119
label: "Difficulty (ASC)",
120-
value: "Difficulty (ASC)",
120+
value: "complexity asc",
121121
},
122122
{
123123
label: "Difficulty (DESC)",
124-
value: "Difficulty (DESC)",
124+
value: "complexity desc",
125125
},
126126
];

0 commit comments

Comments
 (0)