Compare commits

..

7 Commits

Author SHA1 Message Date
05db85eca1 all users front end 2024-08-23 14:26:12 +02:00
f39c000e5d add user be handlers 2024-08-23 14:13:06 +02:00
d16793c01c add user db functions 2024-08-23 14:10:44 +02:00
1971169e2f use sessionStorage & add user admin pages 2024-08-23 13:55:21 +02:00
0e7b9d8c20 improve pagination 2024-08-23 10:51:20 +02:00
0f0c896065 pagination all-subscriptions 2024-08-23 10:13:50 +02:00
c8b032236b pagination all-sales 2024-08-23 10:04:06 +02:00
14 changed files with 399 additions and 33 deletions

View File

@ -403,6 +403,7 @@ func (app *application) VirtualTerminalPaymentSucceeded(w http.ResponseWriter, r
_, err = app.SaveTransaction(txn) _, err = app.SaveTransaction(txn)
if err != nil { if err != nil {
app.badRequest(w, r, err) app.badRequest(w, r, err)
return
} }
app.writeJSON(w, http.StatusOK, txn) app.writeJSON(w, http.StatusOK, txn)
@ -522,12 +523,20 @@ func (app *application) AllSales(w http.ResponseWriter, r *http.Request) {
} }
err := app.readJSON(w, r, &payload) err := app.readJSON(w, r, &payload)
if err != nil { if err != nil {
app.errorLog.Println(err)
app.badRequest(w, r, err) app.badRequest(w, r, err)
return
} }
allSales, lastPage, totalRecords, err := app.DB.GetAllOrdersPaginated(false, 2, 1) allSales, lastPage, totalRecords, err := app.DB.GetAllOrdersPaginated(
false,
payload.PageSize,
payload.CurrentPage,
)
if err != nil { if err != nil {
app.errorLog.Println(err)
app.badRequest(w, r, err) app.badRequest(w, r, err)
return
} }
var resp struct { var resp struct {
@ -538,7 +547,7 @@ func (app *application) AllSales(w http.ResponseWriter, r *http.Request) {
Orders []*models.Order `json:"orders"` Orders []*models.Order `json:"orders"`
} }
resp.CurrentPage = 1 resp.CurrentPage = payload.CurrentPage
resp.PageSize = payload.PageSize resp.PageSize = payload.PageSize
resp.LastPage = lastPage resp.LastPage = lastPage
resp.TotalRecords = totalRecords resp.TotalRecords = totalRecords
@ -548,11 +557,43 @@ func (app *application) AllSales(w http.ResponseWriter, r *http.Request) {
} }
func (app *application) AllSubscriptions(w http.ResponseWriter, r *http.Request) { func (app *application) AllSubscriptions(w http.ResponseWriter, r *http.Request) {
allSubscriptions, err := app.DB.GetAllOrders(true) var payload struct {
if err != nil { PageSize int `json:"page_size"`
app.badRequest(w, r, err) CurrentPage int `json:"page"`
} }
app.writeJSON(w, http.StatusOK, allSubscriptions) err := app.readJSON(w, r, &payload)
if err != nil {
app.errorLog.Println(err)
app.badRequest(w, r, err)
return
}
allSales, lastPage, totalRecords, err := app.DB.GetAllOrdersPaginated(
true,
payload.PageSize,
payload.CurrentPage,
)
if err != nil {
app.errorLog.Println(err)
app.badRequest(w, r, err)
return
}
var resp struct {
CurrentPage int `json:"current_page"`
PageSize int `json:"page_size"`
LastPage int `json:"last_page"`
TotalRecords int `json:"total_records"`
Orders []*models.Order `json:"orders"`
}
resp.CurrentPage = payload.CurrentPage
resp.PageSize = payload.PageSize
resp.LastPage = lastPage
resp.TotalRecords = totalRecords
resp.Orders = allSales
app.writeJSON(w, http.StatusOK, resp)
} }
func (app *application) GetSale(w http.ResponseWriter, r *http.Request) { func (app *application) GetSale(w http.ResponseWriter, r *http.Request) {
@ -562,6 +603,7 @@ func (app *application) GetSale(w http.ResponseWriter, r *http.Request) {
order, err := app.DB.GetOrderByID(orderID) order, err := app.DB.GetOrderByID(orderID)
if err != nil { if err != nil {
app.badRequest(w, r, err) app.badRequest(w, r, err)
return
} }
app.writeJSON(w, http.StatusOK, order) app.writeJSON(w, http.StatusOK, order)
} }
@ -660,3 +702,13 @@ func (app *application) CancelSubscription(w http.ResponseWriter, r *http.Reques
app.writeJSON(w, http.StatusOK, resp) app.writeJSON(w, http.StatusOK, resp)
} }
func (app *application) AllUsers(w http.ResponseWriter, r *http.Request) {
allUsers, err := app.DB.GetAllUsers()
if err != nil {
app.errorLog.Println(err)
app.badRequest(w, r, err)
return
}
app.writeJSON(w, http.StatusOK, allUsers)
}

View File

@ -37,6 +37,7 @@ func (app *application) routes() http.Handler {
mux.Post("/get-sale/{id}", app.GetSale) mux.Post("/get-sale/{id}", app.GetSale)
mux.Post("/refund", app.RefundCharge) mux.Post("/refund", app.RefundCharge)
mux.Post("/cancel-subscription", app.CancelSubscription) mux.Post("/cancel-subscription", app.CancelSubscription)
mux.Post("/all-users", app.AllUsers)
}) })
mux.Post("/api/forgot-password", app.SendPasswordResetEmail) mux.Post("/api/forgot-password", app.SendPasswordResetEmail)
mux.Post("/api/reset-password", app.ResetPassword) mux.Post("/api/reset-password", app.ResetPassword)

View File

@ -417,3 +417,15 @@ func (app *application) ShowSubscriptions(w http.ResponseWriter, r *http.Request
app.errorLog.Println(err) app.errorLog.Println(err)
} }
} }
func (app *application) AllUsers(w http.ResponseWriter, r *http.Request) {
if err := app.renderTemplate(w, r, "all-users", &templateData{}); err != nil {
app.errorLog.Println(err)
}
}
func (app *application) OneUser(w http.ResponseWriter, r *http.Request) {
if err := app.renderTemplate(w, r, "one-user", &templateData{}); err != nil {
app.errorLog.Println(err)
}
}

View File

@ -19,6 +19,8 @@ func (app *application) routes() http.Handler {
mux.Get("/all-subscriptions", app.AllSubscriptions) mux.Get("/all-subscriptions", app.AllSubscriptions)
mux.Get("/sales/{id}", app.ShowSale) mux.Get("/sales/{id}", app.ShowSale)
mux.Get("/subscriptions/{id}", app.ShowSubscriptions) mux.Get("/subscriptions/{id}", app.ShowSubscriptions)
mux.Get("/all-users", app.AllUsers)
mux.Get("/all-users/{id}", app.OneUser)
}) })
// mux.Post("/virtual-terminal-payment-succeeded", app.VirtualTerminalPaymentSucceeded) // mux.Post("/virtual-terminal-payment-succeeded", app.VirtualTerminalPaymentSucceeded)

View File

@ -18,10 +18,21 @@ All Sales
<tbody> <tbody>
</tbody> </tbody>
</table> </table>
<nav>
<ul id="paginator" class="pagination">
</ul>
</nav>
{{ end }} {{ end }}
{{ define "js" }} {{ define "js" }}
<script type="module"> <script type="module">
import {showTable} from "/static/js/all-sales.js" import {pageSize} from "/static/js/common.js"
showTable({{.API}}); import {showTable, currentPage} from "/static/js/all-sales.js"
let curPage = currentPage;
if (sessionStorage.getItem("cur-page") !== null) {
curPage = sessionStorage.getItem("cur-page");
sessionStorage.removeItem("cur-page");
}
showTable({{.API}}, pageSize, curPage);
</script> </script>
{{ end }} {{ end }}

View File

@ -20,11 +20,22 @@ All Subscriptions
<tbody> <tbody>
</tbody> </tbody>
</table> </table>
<nav>
<ul id="paginator" class="pagination">
</ul>
</nav>
{{end}} {{end}}
{{define "js"}} {{define "js"}}
<script type="module"> <script type="module">
import {showTable} from "/static/js/all-subscriptions.js" import {pageSize} from "/static/js/common.js"
showTable({{.API}}); import {showTable, currentPage} from "/static/js/all-subscriptions.js"
let curPage = currentPage;
if (sessionStorage.getItem("cur-page") !== null) {
curPage = sessionStorage.getItem("cur-page");
sessionStorage.removeItem("cur-page");
}
showTable({{.API}}, pageSize, curPage);
</script> </script>
{{end}} {{end}}

View File

@ -0,0 +1,28 @@
{{ template "base". }}
{{ define "title" }}
All Users
{{ end }}
{{ define "content" }}
<h2 class="mt-5">All Admin users</h2>
<hr>
<div class="float-end">
<a class="btn btn-outline-secondary" href="/admin/all-users/0">Add User</a>
</div>
<div class="clearfix"></div>
<table id="user-table" class="table table-striped">
<thead>
<tr>
<th>User</th>
<th>Email</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
{{ end }}
{{ define "js" }}
<script type="module">
import {showUsers} from "/static/js/all-users.js"
showUsers({{.API}});
</script>
{{ end }}

View File

@ -70,6 +70,12 @@
<li> <li>
<hr class="dropdown-divider"> <hr class="dropdown-divider">
</li> </li>
<li>
<a class="dropdown-item" href="/admin/all-users">All Users</a>
</li>
<li>
<hr class="dropdown-divider">
</li>
<li> <li>
<a class="dropdown-item" href="/logout">Logout</a> <a class="dropdown-item" href="/logout">Logout</a>
</li> </li>

View File

@ -0,0 +1,11 @@
{{ template "base". }}
{{ define "title" }}
Admin User
{{ end }}
{{ define "content" }}
<h2 class="mt-5">Admin user</h2>
<hr>
{{ end }}
{{ define "js" }}
{{ end }}

View File

@ -150,7 +150,7 @@ func (m *DBModel) InsertTransaction(txn Transaction) (int, error) {
(amount, currency, last_four, expiry_month, expiry_year, (amount, currency, last_four, expiry_month, expiry_year,
payment_intent, payment_method, bank_return_code, payment_intent, payment_method, bank_return_code,
transaction_status_id, created_at, updated_at) transaction_status_id, created_at, updated_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)` VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);`
result, err := m.DB.ExecContext(ctx, stmt, result, err := m.DB.ExecContext(ctx, stmt,
txn.Amount, txn.Amount,
@ -183,7 +183,7 @@ func (m *DBModel) InsertOrder(order Order) (int, error) {
stmt := `INSERT INTO orders stmt := `INSERT INTO orders
(widget_id, transaction_id, customer_id, status_id, quantity, (widget_id, transaction_id, customer_id, status_id, quantity,
amount, created_at, updated_at) amount, created_at, updated_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)` VALUES (?, ?, ?, ?, ?, ?, ?, ?);`
result, err := m.DB.ExecContext(ctx, stmt, result, err := m.DB.ExecContext(ctx, stmt,
order.WidgetID, order.WidgetID,
@ -212,7 +212,7 @@ func (m *DBModel) InsertCustomer(customer Customer) (int, error) {
stmt := `INSERT INTO customers stmt := `INSERT INTO customers
(first_name, last_name, email, created_at, updated_at) (first_name, last_name, email, created_at, updated_at)
VALUES (?, ?, ?, ?, ?)` VALUES (?, ?, ?, ?, ?);`
result, err := m.DB.ExecContext(ctx, stmt, result, err := m.DB.ExecContext(ctx, stmt,
customer.FirstName, customer.FirstName,
@ -241,7 +241,7 @@ func (m *DBModel) GetUserByEmail(email string) (User, error) {
query := `SELECT id, first_name, last_name, email, password, created_at, updated_at query := `SELECT id, first_name, last_name, email, password, created_at, updated_at
FROM users FROM users
WHERE email = ?` WHERE email = ?;`
row := m.DB.QueryRowContext(ctx, query, email) row := m.DB.QueryRowContext(ctx, query, email)
@ -268,7 +268,7 @@ func (m *DBModel) Authenticate(email, password string) (int, error) {
var id int var id int
var hashedPassword string var hashedPassword string
row := m.DB.QueryRowContext(ctx, "SELECT id, password from users WHERE email = ?", email) row := m.DB.QueryRowContext(ctx, "SELECT id, password from users WHERE email = ?;", email)
err := row.Scan(&id, &hashedPassword) err := row.Scan(&id, &hashedPassword)
if err != nil { if err != nil {
return 0, err return 0, err
@ -288,7 +288,7 @@ func (m *DBModel) UpdatePasswordForUser(u User, hash string) error {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel() defer cancel()
stmt := `UPDATE users SET password = ? where id = ?` stmt := `UPDATE users SET password = ? where id = ?;`
_, err := m.DB.ExecContext(ctx, stmt, hash, u.ID) _, err := m.DB.ExecContext(ctx, stmt, hash, u.ID)
if err != nil { if err != nil {
@ -317,7 +317,7 @@ func (m *DBModel) GetAllOrders(isRecurring bool) ([]*Order, error) {
WHERE WHERE
w.is_recurring = ? w.is_recurring = ?
ORDER BY ORDER BY
o.created_at DESC o.created_at DESC;
` `
rows, err := m.DB.QueryContext(ctx, query, isRecurring) rows, err := m.DB.QueryContext(ctx, query, isRecurring)
@ -387,7 +387,7 @@ func (m *DBModel) GetAllOrdersPaginated(
w.is_recurring = ? w.is_recurring = ?
ORDER BY ORDER BY
o.created_at DESC o.created_at DESC
LIMIT ? OFFSET ? LIMIT ? OFFSET ?;
` `
rows, err := m.DB.QueryContext(ctx, query, isRecurring, pageSize, offset) rows, err := m.DB.QueryContext(ctx, query, isRecurring, pageSize, offset)
@ -433,7 +433,7 @@ func (m *DBModel) GetAllOrdersPaginated(
SELECT COUNT(o.id) SELECT COUNT(o.id)
FROM orders o FROM orders o
LEFT JOIN widgets w on (o.widget_id = w.id) LEFT JOIN widgets w on (o.widget_id = w.id)
WHERE w.is_recurring = ? WHERE w.is_recurring = ?;
` `
var totalRecords int var totalRecords int
@ -444,6 +444,9 @@ func (m *DBModel) GetAllOrdersPaginated(
} }
lastPage := totalRecords / pageSize lastPage := totalRecords / pageSize
if totalRecords%pageSize != 0 {
lastPage++
}
return orders, lastPage, totalRecords, nil return orders, lastPage, totalRecords, nil
} }
@ -464,7 +467,7 @@ func (m *DBModel) GetOrderByID(ID int) (Order, error) {
LEFT JOIN transactions t on (o.transaction_id = t.id) LEFT JOIN transactions t on (o.transaction_id = t.id)
LEFT JOIN customers c on (o.customer_id = c.id) LEFT JOIN customers c on (o.customer_id = c.id)
WHERE WHERE
o.id = ? o.id = ?;
` `
var o Order var o Order
@ -513,3 +516,118 @@ func (m *DBModel) UpdateOrderStatus(id, statusID int) error {
} }
return nil return nil
} }
func (m *DBModel) GetAllUsers() ([]*User, error) {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
var users []*User
query := `
SELECT id, last_name, first_name, email, created_at, updated_at
FROM users
ORDER BY last_name, first_name;
`
rows, err := m.DB.QueryContext(ctx, query)
if err != nil {
return nil, err
}
defer rows.Close()
for rows.Next() {
var u User
err = rows.Scan(
&u.ID,
&u.LastName,
&u.FirstName,
&u.Email,
&u.CreatedAt,
&u.UpdatedAt,
)
if err != nil {
return nil, err
}
users = append(users, &u)
}
return users, nil
}
func (m *DBModel) GetOneUser(id int) (User, error) {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
var u User
query := `
SELECT id, last_name, first_name, email, created_at, updated_at
FROM users
WHERE id = ?;
`
row := m.DB.QueryRowContext(ctx, query, id)
err := row.Scan(
&u.ID,
&u.LastName,
&u.FirstName,
&u.Email,
&u.CreatedAt,
&u.UpdatedAt,
)
if err != nil {
return u, err
}
return u, nil
}
func (m *DBModel) EditUser(u User) error {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
stmt := `
UPDATE users
SET last_name = ?, first_name = ?, email = ?, updated_at = ?
WHERE id = ?;
`
_, err := m.DB.ExecContext(ctx, stmt, u.LastName, u.FirstName, u.Email, time.Now(), u.ID)
if err != nil {
return err
}
return nil
}
func (m *DBModel) AddUser(u User, hash string) error {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
stmt := `
INSERT INTO users
(last_name, first_name, email, password, created_at, updated_at)
VALUES (?, ?, ?, ?, ?, ?);
`
_, err := m.DB.ExecContext(ctx, stmt,
u.LastName, u.FirstName, u.Email, hash, time.Now(), time.Now())
if err != nil {
return err
}
return nil
}
func (m *DBModel) DeleteUser(id int) error {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
stmt := `
DELETE FROM users
WHERE id = ?;
`
_, err := m.DB.ExecContext(ctx, stmt, id)
if err != nil {
return err
}
return nil
}

View File

@ -1,8 +1,20 @@
import { formatCurrency } from "./common.js" import { formatCurrency, paginator } from "./common.js"
export function showTable(api) { //TODO: This should be put into the localStorage if we click into a sale and
let token = localStorage.getItem("token"); //get back, we may want to stay at the same page before.
let tbody = document.getElementById("sales-table").getElementsByTagName("tbody")[0]; export let currentPage = 1;
export function showTable(api, ps, cp) {
const token = localStorage.getItem("token");
const tbody = document.getElementById("sales-table").getElementsByTagName("tbody")[0];
// reset tbody
tbody.innerHTML = ``
const body = {
page_size: parseInt(ps, 10),
page: parseInt(cp, 10),
};
const requestOptions = { const requestOptions = {
method: 'post', method: 'post',
@ -11,17 +23,25 @@ export function showTable(api) {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'Authorization': 'Bearer ' + token, 'Authorization': 'Bearer ' + token,
}, },
body: JSON.stringify(body),
}; };
fetch(api + "/api/admin/all-sales", requestOptions) fetch(api + "/api/admin/all-sales", requestOptions)
.then(response => response.json()) .then(response => response.json())
.then(function (data) { .then(function (data) {
if (data) { if (data.orders) {
data.forEach(function (i) { data.orders.forEach(function (i) {
let newRow = tbody.insertRow(); let newRow = tbody.insertRow();
let newCell = newRow.insertCell(); let newCell = newRow.insertCell();
newCell.innerHTML = `<a href="/admin/sales/${i.id}">Order ${i.id}</a>`; newCell.innerHTML = `<a href="#!">Order ${i.id}</a>`;
newCell.addEventListener("click", function (evt) {
// put the current_page into sessionStorage
sessionStorage.setItem("cur-page", data.current_page);
// redirect
location.href = `/admin/sales/${i.id}`;
});
newCell = newRow.insertCell(); newCell = newRow.insertCell();
let item = document.createTextNode(i.customer.last_name + ", " + i.customer.first_name); let item = document.createTextNode(i.customer.last_name + ", " + i.customer.first_name);
@ -42,12 +62,14 @@ export function showTable(api) {
} else { } else {
newCell.innerHTML = `<span class="badge bg-success">Charged</span>` newCell.innerHTML = `<span class="badge bg-success">Charged</span>`
} }
paginator(api, data.last_page, data.current_page, showTable)
}); });
} else { } else {
let newRow = tbody.insertRow(); let newRow = tbody.insertRow();
let newCell = newRow.insertCell(); let newCell = newRow.insertCell();
newCell.setAttribute("colspan", "4"); newCell.setAttribute("colspan", "5");
newCell.innerHTML = "No data available"; newCell.innerHTML = "No data available";
} }
}); });
} }

View File

@ -1,9 +1,19 @@
import { formatCurrency } from "./common.js" import { formatCurrency, paginator } from "./common.js"
export function showTable(api) { export let currentPage = 1;
export function showTable(api, ps, cp) {
let token = localStorage.getItem("token"); let token = localStorage.getItem("token");
let tbody = document.getElementById("subscriptions-table").getElementsByTagName("tbody")[0]; let tbody = document.getElementById("subscriptions-table").getElementsByTagName("tbody")[0];
// reset tbody
tbody.innerHTML = ``
const body = {
page_size: parseInt(ps, 10),
page: parseInt(cp, 10),
};
const requestOptions = { const requestOptions = {
method: 'post', method: 'post',
headers: { headers: {
@ -11,17 +21,25 @@ export function showTable(api) {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'Authorization': 'Bearer ' + token, 'Authorization': 'Bearer ' + token,
}, },
body: JSON.stringify(body),
}; };
fetch(api + "/api/admin/all-subscriptions", requestOptions) fetch(api + "/api/admin/all-subscriptions", requestOptions)
.then(response => response.json()) .then(response => response.json())
.then(function (data) { .then(function (data) {
if (data) { if (data.orders) {
data.forEach(function (i) { data.orders.forEach(function (i) {
let newRow = tbody.insertRow(); let newRow = tbody.insertRow();
let newCell = newRow.insertCell(); let newCell = newRow.insertCell();
newCell.innerHTML = `<a href="/admin/subscriptions/${i.id}">Order ${i.id}</a>`; newCell.innerHTML = `<a href="#!">Order ${i.id}</a>`;
newCell.addEventListener("click", function (evt) {
// put the current_page into sessionStorage
sessionStorage.setItem("cur-page", data.current_page);
// redirect
location.href = `/admin/subscriptions/${i.id}`;
});
newCell = newRow.insertCell(); newCell = newRow.insertCell();
let item = document.createTextNode(i.customer.last_name + ", " + i.customer.first_name); let item = document.createTextNode(i.customer.last_name + ", " + i.customer.first_name);
@ -42,6 +60,7 @@ export function showTable(api) {
} else { } else {
newCell.innerHTML = `<span class="badge bg-success">Charged</span>` newCell.innerHTML = `<span class="badge bg-success">Charged</span>`
} }
paginator(api, data.last_page, data.current_page, showTable)
}); });
} else { } else {
let newRow = tbody.insertRow(); let newRow = tbody.insertRow();

36
static/js/all-users.js Normal file
View File

@ -0,0 +1,36 @@
export function showUsers(api) {
const tbody = document.getElementById("user-table").getElementsByTagName("tbody")[0];
const token = localStorage.getItem("token");
const requestOptions = {
method: 'post',
headers: {
'Accept': `application/json`,
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + token,
},
};
fetch(api + "/api/admin/all-users", requestOptions)
.then(response => response.json())
.then(function (data) {
if (data) {
data.forEach(i => {
let newRow = tbody.insertRow();
let newCell = newRow.insertCell();
newCell.innerHTML = `<a href="/admin/all-users/${i.id}">${i.last_name}, ${i.first_name}</a>`;
newCell = newRow.insertCell();
let item = document.createTextNode(i.email);
newCell.appendChild(item);
});
} else {
let newRow = tbody.insertRow();
let newCell = newRow.insertCell();
newCell.setAttribute("colspan", "2");
newCell.innerHTML = "no data available";
}
});
}

View File

@ -3,6 +3,8 @@ export let stripe;
const payButton = document.getElementById("pay-button"); const payButton = document.getElementById("pay-button");
export const processing = document.getElementById("processing-payment"); export const processing = document.getElementById("processing-payment");
export let pageSize = 2;
export function hidePayButton() { export function hidePayButton() {
payButton.classList.add("d-none"); payButton.classList.add("d-none");
processing.classList.remove("d-none"); processing.classList.remove("d-none");
@ -98,3 +100,38 @@ export function formatCurrency(amount) {
currency: "EUR", currency: "EUR",
}); });
} }
export function paginator(api, pages, curPage, showTable) {
// Check the border case
if (curPage >= pages) {
curPage = pages
}
const p = document.getElementById("paginator")
let html = `<li class="page-item"><a href="#!" class="page-link pager" data-page="${curPage - 1}">&lt;</a></li>`;
for (var i = 0; i < pages; i++) {
if (i + 1 == curPage) {
html += `<li class="page-item"><a href="#!" class="page-link pager active" data-page="${i + 1}">${i + 1}</a></li>`;
} else {
html += `<li class="page-item"><a href="#!" class="page-link pager" data-page="${i + 1}">${i + 1}</a></li>`;
}
}
html += `<li class="page-item"><a href="#!" class="page-link pager" data-page="${curPage + 1}">&gt;</a></li>`;
p.innerHTML = html;
let pageBtns = document.getElementsByClassName("pager");
for (var j = 0; j < pageBtns.length; j++) {
pageBtns[j].addEventListener("click", function (evt) {
let desiredPage = evt.target.getAttribute("data-page");
if ((desiredPage > 0) && (desiredPage <= pages)) {
console.log("would go to page", desiredPage);
showTable(api, pageSize, desiredPage);
}
})
}
}