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) {
|
||||
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 {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
totalPages := (total + limit - 1) / limit
|
||||
|
||||
data := map[string]interface{}{
|
||||
"Title": "Customers",
|
||||
"Username": h.getUsername(r),
|
||||
"ActivePage": "customers",
|
||||
"Customers": customers,
|
||||
"Search": search,
|
||||
"Page": page,
|
||||
"TotalPages": totalPages,
|
||||
"HasPrev": page > 1,
|
||||
"HasNext": page < totalPages,
|
||||
"PrevPage": page - 1,
|
||||
"NextPage": page + 1,
|
||||
}
|
||||
|
||||
// HTMX partial for search
|
||||
|
||||
@ -10,18 +10,32 @@ import (
|
||||
|
||||
func (h *Handler) InvoiceList(w http.ResponseWriter, r *http.Request) {
|
||||
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 {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
totalPages := (total + limit - 1) / limit
|
||||
|
||||
data := map[string]interface{}{
|
||||
"Title": "Invoices",
|
||||
"Username": h.getUsername(r),
|
||||
"ActivePage": "invoices",
|
||||
"Invoices": invoices,
|
||||
"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" {
|
||||
|
||||
@ -25,17 +25,31 @@ func (h *Handler) ChartOfAccounts(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 {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
totalPages := (total + limit - 1) / limit
|
||||
|
||||
data := map[string]interface{}{
|
||||
"Title": "Journal Entries",
|
||||
"Username": h.getUsername(r),
|
||||
"ActivePage": "ledger",
|
||||
"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)
|
||||
}
|
||||
|
||||
@ -11,18 +11,32 @@ import (
|
||||
|
||||
func (h *Handler) OrderList(w http.ResponseWriter, r *http.Request) {
|
||||
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 {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
totalPages := (total + limit - 1) / limit
|
||||
|
||||
data := map[string]interface{}{
|
||||
"Title": "Orders",
|
||||
"Username": h.getUsername(r),
|
||||
"ActivePage": "orders",
|
||||
"Orders": orders,
|
||||
"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" {
|
||||
|
||||
@ -84,3 +84,46 @@ func CustomerCount(db *sql.DB) int {
|
||||
db.QueryRow("SELECT COUNT(*) FROM customers").Scan(&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
|
||||
}
|
||||
|
||||
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) {
|
||||
inv := &Invoice{}
|
||||
err := db.QueryRow(
|
||||
|
||||
@ -103,6 +103,47 @@ func JournalEntryGetAll(db *sql.DB) ([]JournalEntry, error) {
|
||||
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) {
|
||||
je := &JournalEntry{}
|
||||
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
|
||||
}
|
||||
|
||||
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) {
|
||||
o := &Order{}
|
||||
err := db.QueryRow(
|
||||
|
||||
@ -60,4 +60,40 @@
|
||||
</tbody>
|
||||
</table>
|
||||
</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}}
|
||||
|
||||
@ -64,4 +64,40 @@
|
||||
</tbody>
|
||||
</table>
|
||||
</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}}
|
||||
|
||||
@ -45,5 +45,37 @@
|
||||
</tbody>
|
||||
</table>
|
||||
</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>
|
||||
{{end}}
|
||||
|
||||
@ -66,4 +66,40 @@
|
||||
</tbody>
|
||||
</table>
|
||||
</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}}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user