Skip to content

Commit 36d7b07

Browse files
committed
feat: implement pagination for histories on question page
1 parent 4015266 commit 36d7b07

File tree

10 files changed

+166
-35
lines changed

10 files changed

+166
-35
lines changed

apps/frontend/src/app/question/[id]/page.tsx

Lines changed: 50 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"use client";
22
import Header from "@/components/Header/header";
3-
import { Col, Layout, message, Row, Table } from "antd";
3+
import { Col, Layout, message, PaginationProps, Row, Table } from "antd";
44
import { Content } from "antd/es/layout/layout";
55
import { CodeOutlined, HistoryOutlined } from "@ant-design/icons";
66
import "./styles.scss";
@@ -24,6 +24,13 @@ interface Submission {
2424
historyDocRefId: string;
2525
}
2626

27+
interface TablePagination {
28+
totalCount: number;
29+
totalPages: number;
30+
currentPage: number;
31+
limit: number;
32+
}
33+
2734
export default function QuestionPage() {
2835
const [isLoading, setIsLoading] = useState<boolean>(true); // Store the states related to table's loading
2936

@@ -59,6 +66,12 @@ export default function QuestionPage() {
5966
const [currentSubmissionId, setCurrentSubmissionId] = useState<
6067
string | undefined
6168
>(undefined);
69+
const [paginationParams, setPaginationParams] = useState<TablePagination>({
70+
totalCount: 0,
71+
totalPages: 0,
72+
currentPage: 1,
73+
limit: 3,
74+
});
6275

6376
const state = EditorState.create({
6477
doc: "",
@@ -71,6 +84,33 @@ export default function QuestionPage() {
7184
],
7285
});
7386

87+
// Handler for change in page jumper
88+
const onPageJump: PaginationProps["onChange"] = (pageNumber) => {
89+
setPaginationParams((prev) => {
90+
loadQuestionHistories(pageNumber, paginationParams.limit);
91+
return { ...paginationParams, currentPage: pageNumber };
92+
});
93+
};
94+
95+
async function loadQuestionHistories(currentPage: number, limit: number) {
96+
if (username === undefined) return;
97+
setIsHistoryLoading(true);
98+
GetUserQuestionHistories(username, docRefId, currentPage, limit)
99+
.then((data: any) => {
100+
setUserQuestionHistories(data.histories);
101+
setPaginationParams({
102+
...paginationParams,
103+
totalCount: data.totalCount,
104+
totalPages: data.totalPages,
105+
currentPage: data.currentPage,
106+
limit: data.limit,
107+
});
108+
})
109+
.finally(() => {
110+
setIsHistoryLoading(false);
111+
});
112+
}
113+
74114
// When code editor page is initialised, fetch the particular question, and display in code editor
75115
useEffect(() => {
76116
if (!isLoading) {
@@ -90,15 +130,7 @@ export default function QuestionPage() {
90130
}, [docRefId]);
91131

92132
useEffect(() => {
93-
if (username === undefined) return;
94-
GetUserQuestionHistories(username, docRefId)
95-
.then((data: any) => {
96-
console.log(data);
97-
setUserQuestionHistories(data);
98-
})
99-
.finally(() => {
100-
setIsHistoryLoading(false);
101-
});
133+
loadQuestionHistories(paginationParams.currentPage, paginationParams.limit);
102134
}, [username]);
103135

104136
useEffect(() => {
@@ -108,15 +140,14 @@ export default function QuestionPage() {
108140
}, []);
109141

110142
useEffect(() => {
143+
// Only show history if a history is selected
111144
if (currentSubmissionId === undefined) return;
112145

113146
const view = new EditorView({
114147
state,
115148
parent: editorRef.current || undefined,
116149
});
117150

118-
// TODO: get from a specific history which was selected.
119-
// Show latest history by default, or load specific history
120151
GetHistory(currentSubmissionId).then((data: any) => {
121152
const submittedAt = new Date(data.createdAt);
122153
setSubmission({
@@ -202,8 +233,14 @@ export default function QuestionPage() {
202233
style: { cursor: "pointer" },
203234
};
204235
}}
205-
scroll={{ y: "max-content" }}
206236
loading={isHistoryLoading}
237+
pagination={{
238+
size: "small",
239+
current: paginationParams.currentPage,
240+
total: paginationParams.totalCount,
241+
pageSize: paginationParams.limit,
242+
onChange: onPageJump,
243+
}}
207244
/>
208245
</div>
209246
</div>

apps/frontend/src/app/services/history.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,22 @@ export const GetUserHistories = async (
7777

7878
export const GetUserQuestionHistories = async (
7979
username: string,
80-
questionDocRefId: string
80+
questionDocRefId: string,
81+
currentPage?: number,
82+
limit?: number
8183
): Promise<History[]> => {
84+
let query_params = "";
85+
86+
if (currentPage) {
87+
query_params += `?offset=${(currentPage - 1) * (limit ? limit : 10)}`;
88+
}
89+
90+
if (limit) {
91+
query_params += `${query_params.length > 0 ? "&" : "?"}limit=${limit}`;
92+
}
93+
8294
const response = await fetch(
83-
`${HISTORY_SERVICE_URL}histories/user/${username}/question/${questionDocRefId}`,
95+
`${HISTORY_SERVICE_URL}histories/user/${username}/question/${questionDocRefId}${query_params}`,
8496
{
8597
method: "GET",
8698
headers: {

apps/history-service/handlers/create.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ func (s *Service) CreateHistory(w http.ResponseWriter, r *http.Request) {
1515
ctx := r.Context()
1616

1717
// Parse request
18-
var collaborationHistory models.CollaborationHistory
18+
var collaborationHistory models.SubmissionHistory
1919
if err := utils.DecodeJSONBody(w, r, &collaborationHistory); err != nil {
2020
http.Error(w, err.Error(), http.StatusBadRequest)
2121
return

apps/history-service/handlers/createOrUpdate.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ func (s *Service) CreateOrUpdateHistory(w http.ResponseWriter, r *http.Request)
1919

2020
// Parse request
2121
matchId := chi.URLParam(r, "matchId")
22-
var collaborationHistory models.CollaborationHistory
22+
var collaborationHistory models.SubmissionHistory
2323
if err := utils.DecodeJSONBody(w, r, &collaborationHistory); err != nil {
2424
http.Error(w, err.Error(), http.StatusBadRequest)
2525
return

apps/history-service/handlers/listquestionhistory.go

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"history-service/models"
66
"net/http"
77
"sort"
8+
"strconv"
89

910
"github.com/go-chi/chi/v5"
1011
"google.golang.org/api/iterator"
@@ -31,7 +32,7 @@ func (s *Service) ListUserQuestionHistories(w http.ResponseWriter, r *http.Reque
3132
defer iterMatchedUser.Stop()
3233

3334
// Map data
34-
var histories []models.CollaborationHistory
35+
var histories []models.SubmissionHistory
3536
for {
3637
doc, err := iterUser.Next()
3738
if err == iterator.Done {
@@ -42,7 +43,7 @@ func (s *Service) ListUserQuestionHistories(w http.ResponseWriter, r *http.Reque
4243
return
4344
}
4445

45-
var history models.CollaborationHistory
46+
var history models.SubmissionHistory
4647
if err := doc.DataTo(&history); err != nil {
4748
http.Error(w, "Failed to map history data for user", http.StatusInternalServerError)
4849
return
@@ -62,7 +63,7 @@ func (s *Service) ListUserQuestionHistories(w http.ResponseWriter, r *http.Reque
6263
return
6364
}
6465

65-
var history models.CollaborationHistory
66+
var history models.SubmissionHistory
6667
if err := doc.DataTo(&history); err != nil {
6768
http.Error(w, "Failed to map history data for matched user", http.StatusInternalServerError)
6869
return
@@ -79,7 +80,31 @@ func (s *Service) ListUserQuestionHistories(w http.ResponseWriter, r *http.Reque
7980
// Sort the histories by created at time
8081
sort.Sort(models.HistorySorter(histories))
8182

83+
// Pagination
84+
limitParam := r.URL.Query().Get("limit")
85+
limit := 10
86+
if limitParam != "" {
87+
l, err := strconv.Atoi(limitParam) // convert limit to integer
88+
if err != nil || l <= 0 {
89+
http.Error(w, "Invalid limit: "+strconv.Itoa(l), http.StatusBadRequest)
90+
return
91+
}
92+
limit = l
93+
}
94+
offsetParam := r.URL.Query().Get("offset")
95+
offset := 0
96+
if offsetParam != "" {
97+
o, err := strconv.Atoi(offsetParam) // convert offset to integer
98+
if err != nil {
99+
http.Error(w, "Invalid offset: "+strconv.Itoa(o), http.StatusBadRequest)
100+
return
101+
}
102+
offset = o
103+
}
104+
105+
response := models.PaginateResponse(limit, offset, histories)
106+
82107
w.Header().Set("Content-Type", "application/json")
83108
w.WriteHeader(http.StatusOK)
84-
json.NewEncoder(w).Encode(histories)
109+
json.NewEncoder(w).Encode(response)
85110
}

apps/history-service/handlers/listuserhistory.go

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"history-service/models"
66
"net/http"
77
"sort"
8+
"strconv"
89

910
"github.com/go-chi/chi/v5"
1011
"google.golang.org/api/iterator"
@@ -28,7 +29,7 @@ func (s *Service) ListUserHistories(w http.ResponseWriter, r *http.Request) {
2829
defer iterUser.Stop()
2930

3031
// Map data
31-
var histories []models.CollaborationHistory
32+
var histories []models.SubmissionHistory
3233
for {
3334
doc, err := iterUser.Next()
3435
if err == iterator.Done {
@@ -39,7 +40,7 @@ func (s *Service) ListUserHistories(w http.ResponseWriter, r *http.Request) {
3940
return
4041
}
4142

42-
var history models.CollaborationHistory
43+
var history models.SubmissionHistory
4344
if err := doc.DataTo(&history); err != nil {
4445
http.Error(w, "Failed to map history data for user", http.StatusInternalServerError)
4546
return
@@ -59,7 +60,7 @@ func (s *Service) ListUserHistories(w http.ResponseWriter, r *http.Request) {
5960
return
6061
}
6162

62-
var history models.CollaborationHistory
63+
var history models.SubmissionHistory
6364
if err := doc.DataTo(&history); err != nil {
6465
http.Error(w, "Failed to map history data for matched user", http.StatusInternalServerError)
6566
return
@@ -76,7 +77,31 @@ func (s *Service) ListUserHistories(w http.ResponseWriter, r *http.Request) {
7677
// Sort the histories by created at time
7778
sort.Sort(models.HistorySorter(histories))
7879

80+
// Pagination
81+
limitParam := r.URL.Query().Get("limit")
82+
limit := 10
83+
if limitParam != "" {
84+
l, err := strconv.Atoi(limitParam) // convert limit to integer
85+
if err != nil || l <= 0 {
86+
http.Error(w, "Invalid limit: "+strconv.Itoa(l), http.StatusBadRequest)
87+
return
88+
}
89+
limit = l
90+
}
91+
offsetParam := r.URL.Query().Get("offset")
92+
offset := 0
93+
if offsetParam != "" {
94+
o, err := strconv.Atoi(offsetParam) // convert offset to integer
95+
if err != nil {
96+
http.Error(w, "Invalid offset: "+strconv.Itoa(o), http.StatusBadRequest)
97+
return
98+
}
99+
offset = o
100+
}
101+
102+
response := models.PaginateResponse(limit, offset, histories)
103+
79104
w.Header().Set("Content-Type", "application/json")
80105
w.WriteHeader(http.StatusOK)
81-
json.NewEncoder(w).Encode(histories)
106+
json.NewEncoder(w).Encode(response)
82107
}

apps/history-service/handlers/read.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ func (s *Service) ReadHistory(w http.ResponseWriter, r *http.Request) {
3030
}
3131

3232
// Map data
33-
var collaborationHistory models.CollaborationHistory
33+
var collaborationHistory models.SubmissionHistory
3434
if err := doc.DataTo(&collaborationHistory); err != nil {
3535
http.Error(w, "Failed to map history data", http.StatusInternalServerError)
3636
return

apps/history-service/handlers/update.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ func (s *Service) UpdateHistory(w http.ResponseWriter, r *http.Request) {
1919

2020
// Parse request
2121
matchId := chi.URLParam(r, "matchId")
22-
var updatedHistory models.CollaborationHistory
22+
var updatedHistory models.SubmissionHistory
2323
if err := utils.DecodeJSONBody(w, r, &updatedHistory); err != nil {
2424
http.Error(w, err.Error(), http.StatusBadRequest)
2525
return

apps/history-service/models/models.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package models
22

33
import "time"
44

5-
type CollaborationHistory struct {
5+
type SubmissionHistory struct {
66
// Submission related details
77
Code string `json:"code" firestore:"code"`
88
Language string `json:"language" firestore:"language"`
@@ -25,7 +25,7 @@ type CollaborationHistory struct {
2525
}
2626

2727
// Sorting interface for history, which sorts by created at in desc order
28-
type HistorySorter []CollaborationHistory
28+
type HistorySorter []SubmissionHistory
2929

3030
func (s HistorySorter) Len() int { return len(s) }
3131
func (s HistorySorter) Less(i, j int) bool {
Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,42 @@
11
package models
22

33
type HistoriesResponse struct {
4-
TotalCount int `json:"totalCount"`
5-
TotalPages int `json:"totalPages"`
6-
CurrentPage int `json:"currentPage"`
7-
Limit int `json:"limit"`
8-
HasNextPage bool `json:"hasNextPage"`
9-
Questions []CollaborationHistory `json:"histories"`
4+
TotalCount int `json:"totalCount"`
5+
TotalPages int `json:"totalPages"`
6+
CurrentPage int `json:"currentPage"`
7+
Limit int `json:"limit"`
8+
HasNextPage bool `json:"hasNextPage"`
9+
Questions []SubmissionHistory `json:"histories"`
10+
}
11+
12+
func PaginateResponse(limit, offset int, histories []SubmissionHistory) *HistoriesResponse {
13+
start := offset
14+
end := offset + limit
15+
16+
var paginatedHistory []SubmissionHistory
17+
if start < len(histories) {
18+
if end > len(histories) {
19+
end = len(histories)
20+
}
21+
paginatedHistory = histories[start:end]
22+
}
23+
24+
// Calculate pagination info
25+
totalCount := len(histories)
26+
totalPages := (totalCount + limit - 1) / limit
27+
currentPage := (offset / limit) + 1
28+
if len(paginatedHistory) == 0 {
29+
currentPage = 0
30+
}
31+
hasNextPage := totalPages > currentPage
32+
33+
// Construct response
34+
return &HistoriesResponse{
35+
TotalCount: totalCount,
36+
TotalPages: totalPages,
37+
CurrentPage: currentPage,
38+
Limit: limit,
39+
HasNextPage: hasNextPage,
40+
Questions: paginatedHistory,
41+
}
1042
}

0 commit comments

Comments
 (0)