use yew::prelude::*; use yew_router::prelude::*; use crate::api; use crate::pages::Route; use crate::types::ArtistListItem; #[function_component(LibraryPage)] pub fn library_page() -> Html { let artists = use_state(|| None::>); let error = use_state(|| None::); let fetch_artists = { let artists = artists.clone(); let error = error.clone(); Callback::from(move |_: ()| { let artists = artists.clone(); let error = error.clone(); wasm_bindgen_futures::spawn_local(async move { match api::list_artists(200, 0).await { Ok(a) => artists.set(Some(a)), Err(e) => error.set(Some(e.0)), } }); }) }; { let fetch = fetch_artists.clone(); use_effect_with((), move |_| { fetch.emit(()); }); } if let Some(ref err) = *error { return html! {
{ format!("Error: {err}") }
}; } let Some(ref artists) = *artists else { return html! {

{ "Loading..." }

}; }; html! {
if artists.is_empty() {

{ "No artists in library. Use Search to add some!" }

} else { { for artists.iter().map(|a| { let artist_id = a.id; let artist_name = a.name.clone(); let artist_mbid = a.musicbrainz_id.clone(); let is_watched = a.total_watched > 0; let is_fully_watched = a.enriched && a.total_watched >= a.total_items && a.total_items > 0; let is_monitored = a.monitored; let on_remove = { let error = error.clone(); let fetch = fetch_artists.clone(); Callback::from(move |_: MouseEvent| { let error = error.clone(); let fetch = fetch.clone(); wasm_bindgen_futures::spawn_local(async move { match api::delete_artist(artist_id).await { Ok(_) => fetch.emit(()), Err(e) => error.set(Some(e.0)), } }); }) }; let on_watch = { let error = error.clone(); let fetch = fetch_artists.clone(); let name = artist_name.clone(); let mbid = artist_mbid.clone(); Callback::from(move |_: MouseEvent| { let error = error.clone(); let fetch = fetch.clone(); let name = name.clone(); let mbid = mbid.clone(); wasm_bindgen_futures::spawn_local(async move { match api::add_artist(&name, mbid.as_deref()).await { Ok(_) => fetch.emit(()), Err(e) => error.set(Some(e.0)), } }); }) }; let on_unwatch = { let error = error.clone(); let fetch = fetch_artists.clone(); Callback::from(move |_: MouseEvent| { let error = error.clone(); let fetch = fetch.clone(); wasm_bindgen_futures::spawn_local(async move { match api::unwatch_artist(artist_id).await { Ok(_) => fetch.emit(()), Err(e) => error.set(Some(e.0)), } }); }) }; let on_monitor_toggle = { let error = error.clone(); let fetch = fetch_artists.clone(); Callback::from(move |_: MouseEvent| { let error = error.clone(); let fetch = fetch.clone(); wasm_bindgen_futures::spawn_local(async move { match api::set_artist_monitored(artist_id, !is_monitored).await { Ok(_) => fetch.emit(()), Err(e) => error.set(Some(e.0)), } }); }) }; // Pre-compute progress bar styles let owned_pct = if a.total_watched > 0 { (a.total_owned as f64 / a.total_watched as f64 * 100.0) as u32 } else { 0 }; let owned_color = if a.total_owned >= a.total_watched && a.total_watched > 0 { "var(--success)" } else if a.total_owned > 0 { "var(--warning)" } else { "var(--text-muted)" }; let owned_bar_style = format!("width:{owned_pct}%;background:{owned_color};"); let watched_pct = if a.total_items > 0 { (a.total_watched as f64 / a.total_items as f64 * 100.0) as u32 } else { 0 }; let watched_color = if a.total_watched > 0 { "var(--accent)" } else { "var(--text-muted)" }; let watched_bar_style = format!("width:{watched_pct}%;background:{watched_color};"); html! { if a.enriched { } else { } } })}
{ "Name" } { "Monitored" } { "Owned" } { "Watched" }
to={Route::Artist { id: a.id.to_string() }}> { &a.name } > if a.monitored { { "\u{2713}" } }
{ format!("{}/{}", a.total_owned, a.total_watched) }
{ format!("{}/{}", a.total_watched, a.total_items) }
{ "Awaiting artist enrichment..." }
}
} }