Merge branch 'main' into styles-nino
This commit is contained in:
@@ -25,6 +25,9 @@ enum Route {
|
||||
/// Route for viewing all tickets.
|
||||
#[at("/tickets")]
|
||||
AllTickets,
|
||||
/// Route for viewing archived tickets.
|
||||
#[at("/tickets/archive")]
|
||||
ArchivedTickets,
|
||||
/// Route for user registration.
|
||||
#[at("/register")]
|
||||
Register,
|
||||
@@ -206,6 +209,13 @@ fn switch(route: Route) -> Html {
|
||||
</SidebarShell>
|
||||
</ProtectedRoute>
|
||||
},
|
||||
Route::ArchivedTickets => html! {
|
||||
<ProtectedRoute admin_page={true}>
|
||||
<SidebarShell>
|
||||
<ticket::ArchivedTickets/>
|
||||
</SidebarShell>
|
||||
</ProtectedRoute>
|
||||
},
|
||||
Route::Register => html! {
|
||||
<ProtectedRoute admin_page={true}>
|
||||
<SidebarShell>
|
||||
|
||||
@@ -11,4 +11,3 @@ pub mod sidebar;
|
||||
pub mod ticket;
|
||||
pub mod user;
|
||||
pub mod utilities;
|
||||
|
||||
|
||||
@@ -405,6 +405,7 @@ pub fn sidebar() -> Html {
|
||||
<TicketMenu/>
|
||||
<UsersMenu/>
|
||||
<Link<crate::Route> to={crate::Route::Diagnostics}>{ "Statistiken" }</Link<crate::Route>>
|
||||
<Link<crate::Route> to={crate::Route::ArchivedTickets}>{ "Archiv" }</Link<crate::Route>>
|
||||
<li class="logout-item">
|
||||
<button
|
||||
class="logout-button"
|
||||
|
||||
@@ -667,7 +667,7 @@ pub fn all_tickets_component() -> Html {
|
||||
html! {
|
||||
<div>
|
||||
<ul class="ticket-list">
|
||||
{ for tickets.iter().filter(|t| if user.is_admin { true } else if let Some(uid) = user.id { t.user_id == uid } else { false }).map(|t| {
|
||||
{ for tickets.iter().filter(|t| t.status != "Archived" (if user.is_admin { true } else if let Some(uid) = user.id { t.user_id == uid } else { false })).map(|t| {
|
||||
let status_class = match t.status.as_str() {
|
||||
"ToDo" => "To-Do",
|
||||
"InProgress" => "InProgress",
|
||||
@@ -690,3 +690,136 @@ pub fn all_tickets_component() -> Html {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A component for fetching and displaying a list of archived tickets.
|
||||
///
|
||||
/// This component retrieves all tickets from the backend and presents them as a list,
|
||||
/// filtered to only show those with "Archived" status.
|
||||
///
|
||||
/// # State
|
||||
/// Uses `use_state` hooks to manage:
|
||||
/// - `tickets`: A vector of `Ticket` structs to store the fetched tickets.
|
||||
/// - `error`: Any error message encountered during API calls.
|
||||
/// - `loading`: A boolean indicating if data is currently being fetched.
|
||||
/// - `user`: An `ActiveUser` struct holding the current user's ID and admin status.
|
||||
///
|
||||
/// # Functionality
|
||||
/// - **Fetch Tickets**: On component mount, fetches all tickets from `/api/tickets`.
|
||||
/// - **Fetch Current User**: Concurrently fetches the current user's details from
|
||||
/// `/api/users/current` to determine their `user_id` and `is_admin` status.
|
||||
/// - **Conditional Display**:
|
||||
/// - If `loading` is true, displays "Loading...".
|
||||
/// - If an `error` occurs, displays the error message.
|
||||
/// - Otherwise, renders a list of tickets.
|
||||
/// - **Filtering**:
|
||||
/// - Only tickets with `t.status == "Archived"` are displayed.
|
||||
/// - If the user is an admin, all archived tickets are shown.
|
||||
/// - If the user is not an admin, only their own archived tickets are shown.
|
||||
/// - **Navigation**: Each ticket in the list is a link to [`crate::Route::TicketById`]
|
||||
/// for viewing individual ticket details.
|
||||
///
|
||||
/// # Example
|
||||
/// ```rust
|
||||
/// html! {
|
||||
/// <ArchivedTickets />
|
||||
/// }
|
||||
/// ```
|
||||
#[component(ArchivedTickets)]
|
||||
pub fn archived_tickets_component() -> Html {
|
||||
let tickets = use_state(|| Vec::<Ticket>::new());
|
||||
let error = use_state(|| None::<String>);
|
||||
let loading = use_state(|| false);
|
||||
let user = use_state(|| ActiveUser {
|
||||
id: None,
|
||||
is_admin: false,
|
||||
});
|
||||
|
||||
{
|
||||
let tickets = tickets.clone();
|
||||
let error = error.clone();
|
||||
let loading = loading.clone();
|
||||
|
||||
use_effect_with((), move |_| {
|
||||
loading.set(true);
|
||||
spawn_local(async move {
|
||||
let url = format!("/api/tickets");
|
||||
match Request::get(&url).send().await {
|
||||
Ok(response) if response.status() == 200 => {
|
||||
match response.json::<Vec<Ticket>>().await {
|
||||
Ok(t) => tickets.set(t),
|
||||
Err(e) => error.set(Some(format!("parse error: {}", e))),
|
||||
}
|
||||
}
|
||||
Ok(response) => {
|
||||
if let Ok(text) = response.text().await {
|
||||
error.set(Some(text));
|
||||
} else {
|
||||
error.set(Some(format!("status {}", response.status())));
|
||||
}
|
||||
}
|
||||
Err(err) => error.set(Some(format!("Network error: {}", err))),
|
||||
}
|
||||
loading.set(false);
|
||||
});
|
||||
|| ()
|
||||
});
|
||||
}
|
||||
|
||||
{
|
||||
let user = user.clone();
|
||||
use_effect_with((), move |_| {
|
||||
let user = user.clone();
|
||||
spawn_local(async move {
|
||||
if let Ok(response) = Request::get("/api/users/current")
|
||||
.credentials(web_sys::RequestCredentials::Include)
|
||||
.send()
|
||||
.await
|
||||
{
|
||||
if response.status() == 200 {
|
||||
if let Ok(json) = response.json::<serde_json::Value>().await {
|
||||
let id = json
|
||||
.get("data")
|
||||
.and_then(|d| d.get("id"))
|
||||
.and_then(|v| v.as_i64())
|
||||
.and_then(|n| i16::try_from(n).ok());
|
||||
let is_admin = json
|
||||
.get("data")
|
||||
.and_then(|d| d.get("is_admin"))
|
||||
.and_then(|v| v.as_bool())
|
||||
.unwrap_or(false);
|
||||
user.set(ActiveUser { id, is_admin });
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|| ()
|
||||
});
|
||||
}
|
||||
|
||||
if *loading {
|
||||
html! {<p>{ "Loading" }</p>}
|
||||
} else if let Some(e) = &*error {
|
||||
html! { <p>{ format!("Error: {}", e) }</p> }
|
||||
} else {
|
||||
html! {
|
||||
<ul>
|
||||
{ for tickets.iter().filter(|t| t.status == "Archived" && (user.is_admin || if let Some(uid) = user.id { t.user_id == uid } else { false })).map(|t| html! {
|
||||
<div>
|
||||
<li key={t.id.to_string()}>
|
||||
<Link<crate::Route> to={crate::Route::TicketById{id: t.id}}><h3>{ format!("{} - #{}", t.betreff, t.id) }</h3></Link<crate::Route>>
|
||||
<p>{ &t.description }</p>
|
||||
<p>{ match t.status.as_str() {
|
||||
"ToDo" => "Zu tun",
|
||||
"InProgress" => "In Bearbeitung",
|
||||
"Completed" => "Erledigt",
|
||||
"Archived" => "Archiviert",
|
||||
_ => "Ungültiger Status"
|
||||
}}</p>
|
||||
</li>
|
||||
|
||||
</div>
|
||||
})}
|
||||
</ul>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user