chattyness/crates/chattyness-admin-ui/src/pages/users.rs

94 lines
4.2 KiB
Rust

//! Users list page component.
use leptos::prelude::*;
use crate::components::{Card, EmptyState, PageHeader, Pagination, SearchForm, StatusBadge};
use crate::hooks::{use_fetch, use_pagination};
use crate::models::UserSummary;
use crate::utils::build_paginated_url;
/// Users page component.
#[component]
pub fn UsersPage() -> impl IntoView {
let pagination = use_pagination();
// Fetch users using the new hook
let users = use_fetch::<Vec<UserSummary>>(move || {
build_paginated_url(
"/api/admin/users",
pagination.page.get(),
&pagination.search_query.get(),
25,
)
});
view! {
<PageHeader title="All Users" subtitle="Manage user accounts">
<a href="/admin/users/new" class="btn btn-primary">"Create User"</a>
</PageHeader>
<Card>
<SearchForm
action="/admin/users"
placeholder="Search by username or email..."
search_input=pagination.search_input
/>
<Suspense fallback=|| view! { <p>"Loading users..."</p> }>
{move || {
users.get().map(|maybe_users: Option<Vec<UserSummary>>| {
match maybe_users {
Some(user_list) if !user_list.is_empty() => {
view! {
<div class="table-container">
<table class="data-table">
<thead>
<tr>
<th>"Username"</th>
<th>"Display Name"</th>
<th>"Email"</th>
<th>"Status"</th>
<th>"Created"</th>
</tr>
</thead>
<tbody>
{user_list.into_iter().map(|user| {
view! {
<tr>
<td>
<a href=format!("/admin/users/{}", user.id) class="table-link">
{user.username}
</a>
</td>
<td>{user.display_name}</td>
<td>{user.email.unwrap_or_else(|| "-".to_string())}</td>
<td><StatusBadge status=user.status /></td>
<td>{user.created_at}</td>
</tr>
}
}).collect_view()}
</tbody>
</table>
</div>
<Pagination
current_page=pagination.page.get()
base_url="/admin/users".to_string()
query=pagination.search_query.get()
/>
}.into_any()
}
_ => view! {
<EmptyState
message="No users found."
action_href="/admin/users/new"
action_text="Create User"
/>
}.into_any()
}
})
}}
</Suspense>
</Card>
}
}