Browse Source

Add pagination to the lists page

Kailash Nadh 6 years ago
parent
commit
d9585a7365
4 changed files with 80 additions and 15 deletions
  1. 53 6
      frontend/my/src/Lists.js
  2. 21 7
      lists.go
  3. 4 0
      models/models.go
  4. 2 2
      queries.sql

+ 53 - 6
frontend/my/src/Lists.js

@@ -184,9 +184,28 @@ class CreateFormDef extends React.PureComponent {
 const CreateForm = Form.create()(CreateFormDef)
 
 class Lists extends React.PureComponent {
+  defaultPerPage = 20
   state = {
     formType: null,
-    record: {}
+    record: {},
+    queryParams: {}
+  }
+
+  // Pagination config.
+  paginationOptions = {
+    hideOnSinglePage: false,
+    showSizeChanger: true,
+    showQuickJumper: true,
+    defaultPageSize: this.defaultPerPage,
+    pageSizeOptions: ["20", "50", "70", "100"],
+    position: "both",
+    showTotal: (total, range) => `${range[0]} to ${range[1]} of ${total}`,
+    onChange: (page, perPage) => {
+      this.fetchRecords({ page: page, per_page: perPage })
+    },
+    onShowSizeChange: (page, perPage) => {
+      this.fetchRecords({ page: page, per_page: perPage })
+    }
   }
 
   constructor(props) {
@@ -295,8 +314,28 @@ class Lists extends React.PureComponent {
     this.fetchRecords()
   }
 
-  fetchRecords = () => {
-    this.props.modelRequest(cs.ModelLists, cs.Routes.GetLists, cs.MethodGet)
+  fetchRecords = params => {
+    let qParams = {
+      page: this.state.queryParams.page,
+      per_page: this.state.queryParams.per_page
+    }
+    if (params) {
+      qParams = { ...qParams, ...params }
+    }
+
+    this.props
+      .modelRequest(cs.ModelLists, cs.Routes.GetLists, cs.MethodGet, qParams)
+      .then(() => {
+        this.setState({
+          queryParams: {
+            ...this.state.queryParams,
+            total: this.props.data[cs.ModelLists].total,
+            perPage: this.props.data[cs.ModelLists].per_page,
+            page: this.props.data[cs.ModelLists].page,
+            query: this.props.data[cs.ModelLists].query
+          }
+        })
+      })
   }
 
   deleteRecord = record => {
@@ -340,7 +379,7 @@ class Lists extends React.PureComponent {
       <section className="content">
         <Row>
           <Col span={22}>
-            <h1>Lists ({this.props.data[cs.ModelLists].length}) </h1>
+            <h1>Lists ({this.props.data[cs.ModelLists].total}) </h1>
           </Col>
           <Col span={2}>
             <Button
@@ -358,9 +397,17 @@ class Lists extends React.PureComponent {
           className="lists"
           columns={this.columns}
           rowKey={record => record.uuid}
-          dataSource={this.props.data[cs.ModelLists]}
+          dataSource={(() => {
+            if (
+              !this.props.data[cs.ModelLists] ||
+              !this.props.data[cs.ModelLists].hasOwnProperty("results")
+            ) {
+              return []
+            }
+            return this.props.data[cs.ModelLists].results
+          })()}
           loading={this.props.reqStates[cs.ModelLists] !== cs.StateDone}
-          pagination={false}
+          pagination={{ ...this.paginationOptions, ...this.state.queryParams }}
         />
 
         <CreateForm

+ 21 - 7
lists.go

@@ -13,12 +13,21 @@ import (
 	"github.com/labstack/echo"
 )
 
+type listsWrap struct {
+	Results []models.List `json:"results"`
+
+	Total   int `json:"total"`
+	PerPage int `json:"per_page"`
+	Page    int `json:"page"`
+}
+
 // handleGetLists handles retrieval of lists.
 func handleGetLists(c echo.Context) error {
 	var (
 		app = c.Get("app").(*App)
-		out []models.List
+		out listsWrap
 
+		pg        = getPagination(c.QueryParams())
 		listID, _ = strconv.Atoi(c.Param("id"))
 		single    = false
 	)
@@ -28,27 +37,32 @@ func handleGetLists(c echo.Context) error {
 		single = true
 	}
 
-	err := app.Queries.GetLists.Select(&out, listID)
+	err := app.Queries.GetLists.Select(&out.Results, listID, pg.Offset, pg.Limit)
 	if err != nil {
 		return echo.NewHTTPError(http.StatusInternalServerError,
 			fmt.Sprintf("Error fetching lists: %s", pqErrMsg(err)))
-	} else if single && len(out) == 0 {
+	} else if single && len(out.Results) == 0 {
 		return echo.NewHTTPError(http.StatusBadRequest, "List not found.")
-	} else if len(out) == 0 {
+	} else if len(out.Results) == 0 {
 		return c.JSON(http.StatusOK, okResp{[]struct{}{}})
 	}
 
 	// Replace null tags.
-	for i, v := range out {
+	for i, v := range out.Results {
 		if v.Tags == nil {
-			out[i].Tags = make(pq.StringArray, 0)
+			out.Results[i].Tags = make(pq.StringArray, 0)
 		}
 	}
 
 	if single {
-		return c.JSON(http.StatusOK, okResp{out[0]})
+		return c.JSON(http.StatusOK, okResp{out.Results[0]})
 	}
 
+	// Meta.
+	out.Total = out.Results[0].Total
+	out.Page = pg.Page
+	out.PerPage = pg.PerPage
+
 	return c.JSON(http.StatusOK, okResp{out})
 }
 

+ 4 - 0
models/models.go

@@ -121,6 +121,10 @@ type List struct {
 
 	// This is only relevant when querying the lists of a subscriber.
 	SubscriptionStatus string `db:"subscription_status" json:"subscription_status,omitempty"`
+
+	// Pseudofield for getting the total number of subscribers
+	// in searches and queries.
+	Total int `db:"total" json:"-"`
 }
 
 // Campaign represents an e-mail campaign.

+ 2 - 2
queries.sql

@@ -226,11 +226,11 @@ UPDATE subscriber_lists SET status='unsubscribed', updated_at=NOW()
 
 -- lists
 -- name: get-lists
-SELECT lists.*, COUNT(subscriber_lists.subscriber_id) AS subscriber_count
+SELECT COUNT(*) OVER () AS total, lists.*, COUNT(subscriber_lists.subscriber_id) AS subscriber_count
     FROM lists LEFT JOIN subscriber_lists
 	ON (subscriber_lists.list_id = lists.id AND subscriber_lists.status != 'unsubscribed')
     WHERE ($1 = 0 OR id = $1)
-    GROUP BY lists.id ORDER BY lists.created_at;
+    GROUP BY lists.id ORDER BY lists.created_at OFFSET $2 LIMIT $3;
 
 -- name: create-list
 INSERT INTO lists (uuid, name, type, tags) VALUES($1, $2, $3, $4) RETURNING id;