diff --git a/src-tauri/src/commands/items.rs b/src-tauri/src/commands/items.rs index 04207c5..da572a7 100644 --- a/src-tauri/src/commands/items.rs +++ b/src-tauri/src/commands/items.rs @@ -9,12 +9,14 @@ use crate::fetchers; use crate::fetchers::auth::AuthClient; use crate::models::settings; +/// Creates an `AuthClient` for authenticated communication to the database fn create_auth_client(state: &DbConnection, url: String) -> Result { let (access, secret) = settings::upstream_credentials(state) .ok_or_else(|| "Upstream credentials not configured".to_string())?; Ok(AuthClient::new(url, access, secret)) } +/// Fetch all items with consideration for the `ItemReadOption` filters #[tauri::command] pub async fn read_all_items( state: State<'_, DbConnection>, @@ -32,6 +34,7 @@ pub async fn read_all_items( } } +/// Counts the total number of items with consideration for the `ItemReadOption` filters #[tauri::command] pub async fn count_all_items( state: State<'_, DbConnection>, @@ -49,6 +52,7 @@ pub async fn count_all_items( } } +/// Updates a single item in the database or upstream service #[tauri::command] pub async fn update_item( state: State<'_, DbConnection>, @@ -66,6 +70,7 @@ pub async fn update_item( } } +/// Performs bulk updates in multiple items #[tauri::command] pub async fn update_items( state: State<'_, DbConnection>, diff --git a/src/api/items.ts b/src/api/items.ts index 75b5a2b..5f89930 100644 --- a/src/api/items.ts +++ b/src/api/items.ts @@ -111,6 +111,7 @@ export async function unsave(id: number) { } } +// Mark items as a specific status: read or unread export async function markAs(ids: number[], status: ItemStatus) { try { if (ids.length === 1) { diff --git a/src/routes/Items.tsx b/src/routes/Items.tsx index 30a2686..cffc069 100644 --- a/src/routes/Items.tsx +++ b/src/routes/Items.tsx @@ -42,9 +42,16 @@ function Items(props: Props) { const loadPage = async (newOffset: number) => { setOffset(newOffset); - setOpt({ ...opt(), offset: offset() }); + + // Prevents offset from being set to a value that is out of range + setOpt({ ...opt(), offset: Math.max(0, offset() - 1) }); + window.scroll(0, 0); - await loadItems(); + if (count() <= (offset() * LIMIT)) { + setOpt({ ...opt(), offset: Math.max(0, offset() - 1) }); + await loadItems(); + } + await loadItems(); setItems(items); }; const toggleSave = async (item: api.Item) => { @@ -62,7 +69,11 @@ function Items(props: Props) { if (ids.length) { await api.markAs(ids, status); if (props.type === ItemType.UNREAD) { - setItems(items().map((x) => (ids.includes(x.id) ? { ...x, status: status } : x))); + + // Instead of greying out `READ` items, we remove them + // from the list automatically for better UX + // since this page only focuses on `UNREAD` items + setItems(items().filter((x) => !ids.includes(x.id))); setCount(await api.countItems(opt())); } else { await loadItems(); @@ -116,7 +127,7 @@ function Items(props: Props) { setOpt(initialOpt); break; case ItemType.UNREAD: - setOpt({ ...initialOpt, status: api.ItemStatus.UNREAD }); + setOpt({ ...initialOpt, status: api.ItemStatus.UNREAD, order_by: api.ItemOrder.UNREAD_FIRST }); break; case ItemType.SAVED: setOpt({ ...initialOpt, is_saved: true });