adds pagination
This commit is contained in:
parent
7f1ea8ba72
commit
aa3b63095c
@ -9,18 +9,32 @@ import (
|
|||||||
|
|
||||||
func (h *Handler) CustomerList(w http.ResponseWriter, r *http.Request) {
|
func (h *Handler) CustomerList(w http.ResponseWriter, r *http.Request) {
|
||||||
search := r.URL.Query().Get("search")
|
search := r.URL.Query().Get("search")
|
||||||
customers, err := models.CustomerGetAll(h.DB, search)
|
page, _ := strconv.Atoi(r.URL.Query().Get("page"))
|
||||||
|
if page < 1 {
|
||||||
|
page = 1
|
||||||
|
}
|
||||||
|
limit := 10
|
||||||
|
|
||||||
|
customers, total, err := models.CustomerGetPaginated(h.DB, search, page, limit)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
totalPages := (total + limit - 1) / limit
|
||||||
|
|
||||||
data := map[string]interface{}{
|
data := map[string]interface{}{
|
||||||
"Title": "Customers",
|
"Title": "Customers",
|
||||||
"Username": h.getUsername(r),
|
"Username": h.getUsername(r),
|
||||||
"ActivePage": "customers",
|
"ActivePage": "customers",
|
||||||
"Customers": customers,
|
"Customers": customers,
|
||||||
"Search": search,
|
"Search": search,
|
||||||
|
"Page": page,
|
||||||
|
"TotalPages": totalPages,
|
||||||
|
"HasPrev": page > 1,
|
||||||
|
"HasNext": page < totalPages,
|
||||||
|
"PrevPage": page - 1,
|
||||||
|
"NextPage": page + 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
// HTMX partial for search
|
// HTMX partial for search
|
||||||
|
|||||||
@ -10,18 +10,32 @@ import (
|
|||||||
|
|
||||||
func (h *Handler) InvoiceList(w http.ResponseWriter, r *http.Request) {
|
func (h *Handler) InvoiceList(w http.ResponseWriter, r *http.Request) {
|
||||||
status := r.URL.Query().Get("status")
|
status := r.URL.Query().Get("status")
|
||||||
invoices, err := models.InvoiceGetAll(h.DB, status)
|
page, _ := strconv.Atoi(r.URL.Query().Get("page"))
|
||||||
|
if page < 1 {
|
||||||
|
page = 1
|
||||||
|
}
|
||||||
|
limit := 10
|
||||||
|
|
||||||
|
invoices, total, err := models.InvoiceGetPaginated(h.DB, status, page, limit)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
totalPages := (total + limit - 1) / limit
|
||||||
|
|
||||||
data := map[string]interface{}{
|
data := map[string]interface{}{
|
||||||
"Title": "Invoices",
|
"Title": "Invoices",
|
||||||
"Username": h.getUsername(r),
|
"Username": h.getUsername(r),
|
||||||
"ActivePage": "invoices",
|
"ActivePage": "invoices",
|
||||||
"Invoices": invoices,
|
"Invoices": invoices,
|
||||||
"FilterStatus": status,
|
"FilterStatus": status,
|
||||||
|
"Page": page,
|
||||||
|
"TotalPages": totalPages,
|
||||||
|
"HasPrev": page > 1,
|
||||||
|
"HasNext": page < totalPages,
|
||||||
|
"PrevPage": page - 1,
|
||||||
|
"NextPage": page + 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.Header.Get("HX-Request") == "true" && r.URL.Query().Get("partial") == "true" {
|
if r.Header.Get("HX-Request") == "true" && r.URL.Query().Get("partial") == "true" {
|
||||||
|
|||||||
@ -25,17 +25,31 @@ func (h *Handler) ChartOfAccounts(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) JournalEntries(w http.ResponseWriter, r *http.Request) {
|
func (h *Handler) JournalEntries(w http.ResponseWriter, r *http.Request) {
|
||||||
entries, err := models.JournalEntryGetAll(h.DB)
|
page, _ := strconv.Atoi(r.URL.Query().Get("page"))
|
||||||
|
if page < 1 {
|
||||||
|
page = 1
|
||||||
|
}
|
||||||
|
limit := 20
|
||||||
|
|
||||||
|
entries, total, err := models.JournalEntryGetPaginated(h.DB, page, limit)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
totalPages := (total + limit - 1) / limit
|
||||||
|
|
||||||
data := map[string]interface{}{
|
data := map[string]interface{}{
|
||||||
"Title": "Journal Entries",
|
"Title": "Journal Entries",
|
||||||
"Username": h.getUsername(r),
|
"Username": h.getUsername(r),
|
||||||
"ActivePage": "ledger",
|
"ActivePage": "ledger",
|
||||||
"Entries": entries,
|
"Entries": entries,
|
||||||
|
"Page": page,
|
||||||
|
"TotalPages": totalPages,
|
||||||
|
"HasPrev": page > 1,
|
||||||
|
"HasNext": page < totalPages,
|
||||||
|
"PrevPage": page - 1,
|
||||||
|
"NextPage": page + 1,
|
||||||
}
|
}
|
||||||
h.render(w, []string{"layout.html", "ledger/journal_entries.html"}, data)
|
h.render(w, []string{"layout.html", "ledger/journal_entries.html"}, data)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,18 +11,32 @@ import (
|
|||||||
|
|
||||||
func (h *Handler) OrderList(w http.ResponseWriter, r *http.Request) {
|
func (h *Handler) OrderList(w http.ResponseWriter, r *http.Request) {
|
||||||
status := r.URL.Query().Get("status")
|
status := r.URL.Query().Get("status")
|
||||||
orders, err := models.OrderGetAll(h.DB, status)
|
page, _ := strconv.Atoi(r.URL.Query().Get("page"))
|
||||||
|
if page < 1 {
|
||||||
|
page = 1
|
||||||
|
}
|
||||||
|
limit := 10
|
||||||
|
|
||||||
|
orders, total, err := models.OrderGetPaginated(h.DB, status, page, limit)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
totalPages := (total + limit - 1) / limit
|
||||||
|
|
||||||
data := map[string]interface{}{
|
data := map[string]interface{}{
|
||||||
"Title": "Orders",
|
"Title": "Orders",
|
||||||
"Username": h.getUsername(r),
|
"Username": h.getUsername(r),
|
||||||
"ActivePage": "orders",
|
"ActivePage": "orders",
|
||||||
"Orders": orders,
|
"Orders": orders,
|
||||||
"FilterStatus": status,
|
"FilterStatus": status,
|
||||||
|
"Page": page,
|
||||||
|
"TotalPages": totalPages,
|
||||||
|
"HasPrev": page > 1,
|
||||||
|
"HasNext": page < totalPages,
|
||||||
|
"PrevPage": page - 1,
|
||||||
|
"NextPage": page + 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.Header.Get("HX-Request") == "true" && r.URL.Query().Get("partial") == "true" {
|
if r.Header.Get("HX-Request") == "true" && r.URL.Query().Get("partial") == "true" {
|
||||||
|
|||||||
@ -84,3 +84,46 @@ func CustomerCount(db *sql.DB) int {
|
|||||||
db.QueryRow("SELECT COUNT(*) FROM customers").Scan(&count)
|
db.QueryRow("SELECT COUNT(*) FROM customers").Scan(&count)
|
||||||
return count
|
return count
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func CustomerGetPaginated(db *sql.DB, search string, page, limit int) ([]Customer, int, error) {
|
||||||
|
offset := (page - 1) * limit
|
||||||
|
|
||||||
|
// Base queries
|
||||||
|
query := "SELECT id, name, email, phone, address, created_at, updated_at FROM customers"
|
||||||
|
countQuery := "SELECT COUNT(*) FROM customers"
|
||||||
|
|
||||||
|
args := []interface{}{}
|
||||||
|
if search != "" {
|
||||||
|
where := " WHERE name LIKE ? OR email LIKE ?"
|
||||||
|
query += where
|
||||||
|
countQuery += where
|
||||||
|
s := "%" + search + "%"
|
||||||
|
args = append(args, s, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get total count first
|
||||||
|
var total int
|
||||||
|
if err := db.QueryRow(countQuery, args...).Scan(&total); err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add limit and offset to query
|
||||||
|
query += " ORDER BY name LIMIT ? OFFSET ?"
|
||||||
|
args = append(args, limit, offset)
|
||||||
|
|
||||||
|
rows, err := db.Query(query, args...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
var customers []Customer
|
||||||
|
for rows.Next() {
|
||||||
|
var c Customer
|
||||||
|
if err := rows.Scan(&c.ID, &c.Name, &c.Email, &c.Phone, &c.Address, &c.CreatedAt, &c.UpdatedAt); err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
customers = append(customers, c)
|
||||||
|
}
|
||||||
|
return customers, total, nil
|
||||||
|
}
|
||||||
|
|||||||
@ -46,6 +46,48 @@ func InvoiceGetAll(db *sql.DB, status string) ([]Invoice, error) {
|
|||||||
return invoices, nil
|
return invoices, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func InvoiceGetPaginated(db *sql.DB, status string, page, limit int) ([]Invoice, int, error) {
|
||||||
|
offset := (page - 1) * limit
|
||||||
|
|
||||||
|
// Base queries
|
||||||
|
query := `SELECT i.id, i.order_id, i.customer_id, c.name, i.invoice_number, i.status, i.amount, i.due_date, i.paid_date, i.created_at
|
||||||
|
FROM invoices i JOIN customers c ON i.customer_id = c.id`
|
||||||
|
countQuery := "SELECT COUNT(*) FROM invoices i"
|
||||||
|
|
||||||
|
args := []interface{}{}
|
||||||
|
if status != "" {
|
||||||
|
where := " WHERE i.status = ?"
|
||||||
|
query += where
|
||||||
|
countQuery += where
|
||||||
|
args = append(args, status)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get total count
|
||||||
|
var total int
|
||||||
|
if err := db.QueryRow(countQuery, args...).Scan(&total); err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
query += " ORDER BY i.created_at DESC LIMIT ? OFFSET ?"
|
||||||
|
args = append(args, limit, offset)
|
||||||
|
|
||||||
|
rows, err := db.Query(query, args...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
var invoices []Invoice
|
||||||
|
for rows.Next() {
|
||||||
|
var inv Invoice
|
||||||
|
if err := rows.Scan(&inv.ID, &inv.OrderID, &inv.CustomerID, &inv.CustomerName, &inv.InvoiceNumber, &inv.Status, &inv.Amount, &inv.DueDate, &inv.PaidDate, &inv.CreatedAt); err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
invoices = append(invoices, inv)
|
||||||
|
}
|
||||||
|
return invoices, total, nil
|
||||||
|
}
|
||||||
|
|
||||||
func InvoiceGetByID(db *sql.DB, id int) (*Invoice, error) {
|
func InvoiceGetByID(db *sql.DB, id int) (*Invoice, error) {
|
||||||
inv := &Invoice{}
|
inv := &Invoice{}
|
||||||
err := db.QueryRow(
|
err := db.QueryRow(
|
||||||
|
|||||||
@ -103,6 +103,47 @@ func JournalEntryGetAll(db *sql.DB) ([]JournalEntry, error) {
|
|||||||
return entries, nil
|
return entries, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func JournalEntryGetPaginated(db *sql.DB, page, limit int) ([]JournalEntry, int, error) {
|
||||||
|
offset := (page - 1) * limit
|
||||||
|
|
||||||
|
var total int
|
||||||
|
if err := db.QueryRow("SELECT COUNT(*) FROM journal_entries").Scan(&total); err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
query := `
|
||||||
|
SELECT
|
||||||
|
je.id,
|
||||||
|
je.entry_date,
|
||||||
|
je.description,
|
||||||
|
je.reference,
|
||||||
|
je.created_at,
|
||||||
|
COALESCE(SUM(jl.debit), 0),
|
||||||
|
COALESCE(SUM(jl.credit), 0)
|
||||||
|
FROM journal_entries je
|
||||||
|
LEFT JOIN journal_lines jl ON je.id = jl.journal_entry_id
|
||||||
|
GROUP BY je.id
|
||||||
|
ORDER BY je.created_at DESC
|
||||||
|
LIMIT ? OFFSET ?
|
||||||
|
`
|
||||||
|
|
||||||
|
rows, err := db.Query(query, limit, offset)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
var entries []JournalEntry
|
||||||
|
for rows.Next() {
|
||||||
|
var je JournalEntry
|
||||||
|
if err := rows.Scan(&je.ID, &je.EntryDate, &je.Description, &je.Reference, &je.CreatedAt, &je.TotalDebit, &je.TotalCredit); err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
entries = append(entries, je)
|
||||||
|
}
|
||||||
|
return entries, total, nil
|
||||||
|
}
|
||||||
|
|
||||||
func JournalEntryGetByID(db *sql.DB, id int) (*JournalEntry, error) {
|
func JournalEntryGetByID(db *sql.DB, id int) (*JournalEntry, error) {
|
||||||
je := &JournalEntry{}
|
je := &JournalEntry{}
|
||||||
err := db.QueryRow("SELECT id, entry_date, description, reference, created_at FROM journal_entries WHERE id = ?", id).
|
err := db.QueryRow("SELECT id, entry_date, description, reference, created_at FROM journal_entries WHERE id = ?", id).
|
||||||
|
|||||||
@ -55,6 +55,48 @@ func OrderGetAll(db *sql.DB, status string) ([]Order, error) {
|
|||||||
return orders, nil
|
return orders, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func OrderGetPaginated(db *sql.DB, status string, page, limit int) ([]Order, int, error) {
|
||||||
|
offset := (page - 1) * limit
|
||||||
|
|
||||||
|
// Base queries
|
||||||
|
query := `SELECT o.id, o.customer_id, c.name, o.status, o.order_date, o.total_amount, o.notes, o.created_at, o.updated_at
|
||||||
|
FROM orders o JOIN customers c ON o.customer_id = c.id`
|
||||||
|
countQuery := "SELECT COUNT(*) FROM orders o"
|
||||||
|
|
||||||
|
args := []interface{}{}
|
||||||
|
if status != "" {
|
||||||
|
where := " WHERE o.status = ?"
|
||||||
|
query += where
|
||||||
|
countQuery += where
|
||||||
|
args = append(args, status)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get total count
|
||||||
|
var total int
|
||||||
|
if err := db.QueryRow(countQuery, args...).Scan(&total); err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
query += " ORDER BY o.created_at DESC LIMIT ? OFFSET ?"
|
||||||
|
args = append(args, limit, offset)
|
||||||
|
|
||||||
|
rows, err := db.Query(query, args...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
var orders []Order
|
||||||
|
for rows.Next() {
|
||||||
|
var o Order
|
||||||
|
if err := rows.Scan(&o.ID, &o.CustomerID, &o.CustomerName, &o.Status, &o.OrderDate, &o.TotalAmount, &o.Notes, &o.CreatedAt, &o.UpdatedAt); err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
orders = append(orders, o)
|
||||||
|
}
|
||||||
|
return orders, total, nil
|
||||||
|
}
|
||||||
|
|
||||||
func OrderGetByID(db *sql.DB, id int) (*Order, error) {
|
func OrderGetByID(db *sql.DB, id int) (*Order, error) {
|
||||||
o := &Order{}
|
o := &Order{}
|
||||||
err := db.QueryRow(
|
err := db.QueryRow(
|
||||||
|
|||||||
@ -60,4 +60,40 @@
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-4 flex items-center justify-between border-t border-gray-200 bg-white px-4 py-3 sm:px-6">
|
||||||
|
<div class="hidden sm:flex sm:flex-1 sm:items-center sm:justify-between">
|
||||||
|
<div>
|
||||||
|
<p class="text-sm text-gray-700">
|
||||||
|
Page <span class="font-medium">{{.Page}}</span> of <span class="font-medium">{{.TotalPages}}</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<nav class="isolate inline-flex -space-x-px rounded-md shadow-sm" aria-label="Pagination">
|
||||||
|
{{if .HasPrev}}
|
||||||
|
<button
|
||||||
|
hx-get="/customers?page={{.PrevPage}}&search={{.Search}}&partial=true"
|
||||||
|
hx-target="#customer-table"
|
||||||
|
class="relative inline-flex items-center rounded-l-md px-2 py-2 text-gray-400 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus:z-20 focus:outline-offset-0">
|
||||||
|
<span class="sr-only">Previous</span>
|
||||||
|
<svg class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
||||||
|
<path fill-rule="evenodd" d="M12.79 5.23a.75.75 0 01-.02 1.06L8.832 10l3.938 3.71a.75.75 0 11-1.04 1.08l-4.5-4.25a.75.75 0 010-1.08l4.5-4.25a.75.75 0 011.06.02z" clip-rule="evenodd" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
{{end}}
|
||||||
|
{{if .HasNext}}
|
||||||
|
<button
|
||||||
|
hx-get="/customers?page={{.NextPage}}&search={{.Search}}&partial=true"
|
||||||
|
hx-target="#customer-table"
|
||||||
|
class="relative inline-flex items-center rounded-r-md px-2 py-2 text-gray-400 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus:z-20 focus:outline-offset-0">
|
||||||
|
<span class="sr-only">Next</span>
|
||||||
|
<svg class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
||||||
|
<path fill-rule="evenodd" d="M7.21 14.77a.75.75 0 01.02-1.06L11.168 10 7.23 6.29a.75.75 0 111.04-1.08l4.5 4.25a.75.75 0 010 1.08l-4.5 4.25a.75.75 0 01-1.06-.02z" clip-rule="evenodd" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
{{end}}
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|||||||
@ -64,4 +64,40 @@
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-4 flex items-center justify-between border-t border-gray-200 bg-white px-4 py-3 sm:px-6">
|
||||||
|
<div class="hidden sm:flex sm:flex-1 sm:items-center sm:justify-between">
|
||||||
|
<div>
|
||||||
|
<p class="text-sm text-gray-700">
|
||||||
|
Page <span class="font-medium">{{.Page}}</span> of <span class="font-medium">{{.TotalPages}}</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<nav class="isolate inline-flex -space-x-px rounded-md shadow-sm" aria-label="Pagination">
|
||||||
|
{{if .HasPrev}}
|
||||||
|
<button
|
||||||
|
hx-get="/invoices?page={{.PrevPage}}&status={{.FilterStatus}}&partial=true"
|
||||||
|
hx-target="#invoice-table"
|
||||||
|
class="relative inline-flex items-center rounded-l-md px-2 py-2 text-gray-400 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus:z-20 focus:outline-offset-0">
|
||||||
|
<span class="sr-only">Previous</span>
|
||||||
|
<svg class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
||||||
|
<path fill-rule="evenodd" d="M12.79 5.23a.75.75 0 01-.02 1.06L8.832 10l3.938 3.71a.75.75 0 11-1.04 1.08l-4.5-4.25a.75.75 0 010-1.08l4.5-4.25a.75.75 0 011.06.02z" clip-rule="evenodd" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
{{end}}
|
||||||
|
{{if .HasNext}}
|
||||||
|
<button
|
||||||
|
hx-get="/invoices?page={{.NextPage}}&status={{.FilterStatus}}&partial=true"
|
||||||
|
hx-target="#invoice-table"
|
||||||
|
class="relative inline-flex items-center rounded-r-md px-2 py-2 text-gray-400 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus:z-20 focus:outline-offset-0">
|
||||||
|
<span class="sr-only">Next</span>
|
||||||
|
<svg class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
||||||
|
<path fill-rule="evenodd" d="M7.21 14.77a.75.75 0 01.02-1.06L11.168 10 7.23 6.29a.75.75 0 111.04-1.08l4.5 4.25a.75.75 0 010 1.08l-4.5 4.25a.75.75 0 01-1.06-.02z" clip-rule="evenodd" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
{{end}}
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|||||||
@ -45,5 +45,37 @@
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-4 flex items-center justify-between border-t border-gray-200 bg-white px-4 py-3 sm:px-6">
|
||||||
|
<div class="hidden sm:flex sm:flex-1 sm:items-center sm:justify-between">
|
||||||
|
<div>
|
||||||
|
<p class="text-sm text-gray-700">
|
||||||
|
Page <span class="font-medium">{{.Page}}</span> of <span class="font-medium">{{.TotalPages}}</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<nav class="isolate inline-flex -space-x-px rounded-md shadow-sm" aria-label="Pagination">
|
||||||
|
{{if .HasPrev}}
|
||||||
|
<a href="/ledger/journal?page={{.PrevPage}}"
|
||||||
|
class="relative inline-flex items-center rounded-l-md px-2 py-2 text-gray-400 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus:z-20 focus:outline-offset-0">
|
||||||
|
<span class="sr-only">Previous</span>
|
||||||
|
<svg class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
||||||
|
<path fill-rule="evenodd" d="M12.79 5.23a.75.75 0 01-.02 1.06L8.832 10l3.938 3.71a.75.75 0 11-1.04 1.08l-4.5-4.25a.75.75 0 010-1.08l4.5-4.25a.75.75 0 011.06.02z" clip-rule="evenodd" />
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
{{end}}
|
||||||
|
{{if .HasNext}}
|
||||||
|
<a href="/ledger/journal?page={{.NextPage}}"
|
||||||
|
class="relative inline-flex items-center rounded-r-md px-2 py-2 text-gray-400 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus:z-20 focus:outline-offset-0">
|
||||||
|
<span class="sr-only">Next</span>
|
||||||
|
<svg class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
||||||
|
<path fill-rule="evenodd" d="M7.21 14.77a.75.75 0 01.02-1.06L11.168 10 7.23 6.29a.75.75 0 111.04-1.08l4.5 4.25a.75.75 0 010 1.08l-4.5 4.25a.75.75 0 01-1.06-.02z" clip-rule="evenodd" />
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
{{end}}
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|||||||
@ -66,4 +66,40 @@
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-4 flex items-center justify-between border-t border-gray-200 bg-white px-4 py-3 sm:px-6">
|
||||||
|
<div class="hidden sm:flex sm:flex-1 sm:items-center sm:justify-between">
|
||||||
|
<div>
|
||||||
|
<p class="text-sm text-gray-700">
|
||||||
|
Page <span class="font-medium">{{.Page}}</span> of <span class="font-medium">{{.TotalPages}}</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<nav class="isolate inline-flex -space-x-px rounded-md shadow-sm" aria-label="Pagination">
|
||||||
|
{{if .HasPrev}}
|
||||||
|
<button
|
||||||
|
hx-get="/orders?page={{.PrevPage}}&status={{.FilterStatus}}&partial=true"
|
||||||
|
hx-target="#order-table"
|
||||||
|
class="relative inline-flex items-center rounded-l-md px-2 py-2 text-gray-400 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus:z-20 focus:outline-offset-0">
|
||||||
|
<span class="sr-only">Previous</span>
|
||||||
|
<svg class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
||||||
|
<path fill-rule="evenodd" d="M12.79 5.23a.75.75 0 01-.02 1.06L8.832 10l3.938 3.71a.75.75 0 11-1.04 1.08l-4.5-4.25a.75.75 0 010-1.08l4.5-4.25a.75.75 0 011.06.02z" clip-rule="evenodd" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
{{end}}
|
||||||
|
{{if .HasNext}}
|
||||||
|
<button
|
||||||
|
hx-get="/orders?page={{.NextPage}}&status={{.FilterStatus}}&partial=true"
|
||||||
|
hx-target="#order-table"
|
||||||
|
class="relative inline-flex items-center rounded-r-md px-2 py-2 text-gray-400 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus:z-20 focus:outline-offset-0">
|
||||||
|
<span class="sr-only">Next</span>
|
||||||
|
<svg class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
||||||
|
<path fill-rule="evenodd" d="M7.21 14.77a.75.75 0 01.02-1.06L11.168 10 7.23 6.29a.75.75 0 111.04-1.08l4.5 4.25a.75.75 0 010 1.08l-4.5 4.25a.75.75 0 01-1.06-.02z" clip-rule="evenodd" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
{{end}}
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user