diff --git a/.sqlx/query-34f56cde503100c09bbb378ce656af95abd81949be0c369a5d7225272e6c9c58.json b/.sqlx/query-34f56cde503100c09bbb378ce656af95abd81949be0c369a5d7225272e6c9c58.json new file mode 100644 index 0000000..bb8c5dd --- /dev/null +++ b/.sqlx/query-34f56cde503100c09bbb378ce656af95abd81949be0c369a5d7225272e6c9c58.json @@ -0,0 +1,20 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT\n count(id) AS \"count!\"\nFROM\n receipts\n", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "count!", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + null + ] + }, + "hash": "34f56cde503100c09bbb378ce656af95abd81949be0c369a5d7225272e6c9c58" +} diff --git a/.sqlx/query-71dcdc6a24d99eff2dd7af673a0ebb6fda45b0ebd5244309472921a934e1b829.json b/.sqlx/query-ed7bf495d2eefe7b479a79cc2fc77de3b5a3db4415cd55ecbd21c28c108274a6.json similarity index 79% rename from .sqlx/query-71dcdc6a24d99eff2dd7af673a0ebb6fda45b0ebd5244309472921a934e1b829.json rename to .sqlx/query-ed7bf495d2eefe7b479a79cc2fc77de3b5a3db4415cd55ecbd21c28c108274a6.json index f6bfb68..aba2cf8 100644 --- a/.sqlx/query-71dcdc6a24d99eff2dd7af673a0ebb6fda45b0ebd5244309472921a934e1b829.json +++ b/.sqlx/query-ed7bf495d2eefe7b479a79cc2fc77de3b5a3db4415cd55ecbd21c28c108274a6.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "SELECT\n id, vendor, date, amount, notes, filename\nFROM\n receipts\nORDER BY date\n", + "query": "SELECT\n id, vendor, date, amount, notes, filename\nFROM\n receipts\nORDER BY\n date DESC,\n id DESC\nLIMIT $1\nOFFSET $2\n", "describe": { "columns": [ { @@ -35,7 +35,10 @@ } ], "parameters": { - "Left": [] + "Left": [ + "Int8", + "Int8" + ] }, "nullable": [ false, @@ -46,5 +49,5 @@ false ] }, - "hash": "71dcdc6a24d99eff2dd7af673a0ebb6fda45b0ebd5244309472921a934e1b829" + "hash": "ed7bf495d2eefe7b479a79cc2fc77de3b5a3db4415cd55ecbd21c28c108274a6" } diff --git a/sql/receipts/count-receipts.sql b/sql/receipts/count-receipts.sql new file mode 100644 index 0000000..58d0c1e --- /dev/null +++ b/sql/receipts/count-receipts.sql @@ -0,0 +1,4 @@ +SELECT + count(id) AS "count!" +FROM + receipts diff --git a/sql/receipts/list-receipts.sql b/sql/receipts/list-receipts.sql index e148802..6d9fa5d 100644 --- a/sql/receipts/list-receipts.sql +++ b/sql/receipts/list-receipts.sql @@ -2,4 +2,8 @@ SELECT id, vendor, date, amount, notes, filename FROM receipts -ORDER BY date +ORDER BY + date DESC, + id DESC +LIMIT $1 +OFFSET $2 diff --git a/src/receipts.rs b/src/receipts.rs index 24b5d3d..5e19dad 100644 --- a/src/receipts.rs +++ b/src/receipts.rs @@ -138,12 +138,21 @@ impl ReceiptsRepository { pub async fn list_receipts( &mut self, + limit: i64, + offset: i64, ) -> Result, sqlx::Error> { - sqlx::query_file_as!(ReceiptJson, "sql/receipts/list-receipts.sql") + sqlx::query_file_as!(ReceiptJson, "sql/receipts/list-receipts.sql", limit, offset) .fetch_all(&mut **self.conn) .await } + pub async fn count_receipts(&mut self) -> Result { + Ok(sqlx::query_file!("sql/receipts/count-receipts.sql") + .fetch_one(&mut **self.conn) + .await? + .count) + } + pub async fn add_receipt( &mut self, data: &ReceiptPostData, diff --git a/src/routes/receipts.rs b/src/routes/receipts.rs index 7923d6d..776f40f 100644 --- a/src/routes/receipts.rs +++ b/src/routes/receipts.rs @@ -1,3 +1,5 @@ +use std::ops::RangeInclusive; + use rocket::form::Form; use rocket::http::{ContentType, Header, MediaType, Status}; use rocket::serde::json::Json; @@ -12,18 +14,62 @@ use crate::imaging; use crate::receipts::*; use crate::{Context, Database}; -#[rocket::get("/")] +fn paginate(total: i64, count: i64, current: i64) -> Vec { + let start = 1; + let end = (total / count).max(1); + let pages = RangeInclusive::new(start, end); + if end < 10 { + pages.map(|p| format!("{}", p)).collect() + } else { + pages + .filter_map(|p| { + if p == start + || (current - 2 <= p && p <= current + 2) + || p == end + { + Some(format!("{}", p)) + } else if p == current - 3 || p == current + 3 { + Some("...".into()) + } else { + None + } + }) + .collect() + } +} + +#[rocket::get("/?&")] pub async fn list_receipts( db: DatabaseConnection, + page: Option, + count: Option, ) -> (Status, Template) { let mut repo = ReceiptsRepository::new(db); - match repo.list_receipts().await { + let count = count.unwrap_or(25); + let page = page.unwrap_or(1); + let total = match repo.count_receipts().await { + Ok(r) => r, + Err(e) => { + return ( + Status::InternalServerError, + Template::render( + "error", + context! { + error: e.to_string(), + }, + ), + ) + }, + }; + match repo.list_receipts(count, (page - 1) * count).await { Ok(r) => ( Status::Ok, Template::render( "receipt-list", context! { receipts: r, + pages: paginate(total, count, page), + count: count, }, ), ), diff --git a/templates/receipt-list.html.tera b/templates/receipt-list.html.tera index 1f61e7f..e4221ca 100644 --- a/templates/receipt-list.html.tera +++ b/templates/receipt-list.html.tera @@ -80,6 +80,18 @@ #confirm-delete dl dd { margin-left: 0; } + + ul.pagination { + margin: 0; + padding: 0; + list-style-type: none; + text-align: center; + } + + ul.pagination li { + display: inline-block; + margin: 1em; + } {% endblock %} {% block main %}

Receipts

@@ -114,6 +126,13 @@ {% endfor %} +
    +{%- for page in pages %} +
  • {% if page == "..." %}...{% else + %}{{ page }}{% + endif %}
  • +{%- endfor %} +

Are you sure you want to delete receipt ?