use dioxus::prelude::*;
use matrix_sdk::ruma::OwnedRoomId;
use crate::components::avatar::Avatar;
use crate::state::app_state::{AppState, RightPanelView};
use crate::state::room_state::{MemberMembership, RoomMember};
#[component]
pub fn MemberListPanel() -> Element {
let mut state = use_context::<Signal<AppState>>();
let mut search_query = use_signal(|| String::new());
let mut members = use_signal(Vec::<RoomMember>::new);
let mut members_loaded_for = use_signal(|| Option::<String>::None);
let state_read = state.read();
let active_room_id = state_read.active_room_id.clone();
let member_count = state_read
.active_room()
.map(|r| r.member_count)
.unwrap_or(0);
drop(state_read);
let room_id_str = active_room_id.as_ref().map(|id| id.to_string());
if room_id_str != *members_loaded_for.read() {
members_loaded_for.set(room_id_str.clone());
if let Some(rid) = room_id_str {
spawn(async move {
let client = { state.read().client.clone() };
if let Some(client) = client {
if let Ok(room_id) = OwnedRoomId::try_from(rid.as_str()) {
if let Some(room) = client.get_room(&room_id) {
match room.members(matrix_sdk::RoomMemberships::JOIN).await {
Ok(room_members) => {
let list: Vec<RoomMember> = room_members.iter().map(|m| {
RoomMember {
user_id: m.user_id().to_owned(),
display_name: m.display_name().map(|s| s.to_string()),
avatar_url: m.avatar_url().map(|u| u.to_string()),
power_level: match m.power_level() {
matrix_sdk::ruma::events::room::power_levels::UserPowerLevel::Int(i) => i64::from(i),
_ => 100,
},
is_ignored: false,
membership: MemberMembership::Join,
}
}).collect();
members.set(list);
}
Err(e) => tracing::error!("Failed to load members: {e}"),
}
}
}
}
});
}
}
let query = search_query.read().to_lowercase();
let members_read = members.read();
let filtered_members: Vec<&RoomMember> = members_read
.iter()
.filter(|m| {
if query.is_empty() {
return true;
}
let name_match = m
.display_name
.as_deref()
.unwrap_or("")
.to_lowercase()
.contains(&query);
let id_match = m.user_id.to_string().to_lowercase().contains(&query);
name_match || id_match
})
.collect();
let close_panel = move |_| {
state.write().right_panel = RightPanelView::Closed;
};
let back_to_info = move |_| {
state.write().right_panel = RightPanelView::RoomInfo;
};
rsx! {
div {
class: "member-list-panel",
header {
class: "member-list-panel__header",
button {
class: "member-list-panel__back-btn",
title: "Back to room info",
onclick: back_to_info,
"←"
}
h3 {
class: "member-list-panel__title",
"Members"
}
span {
class: "member-list-panel__count",
"{member_count}"
}
button {
class: "member-list-panel__close-btn",
title: "Close panel",
onclick: close_panel,
"✕"
}
}
div {
class: "member-list-panel__search",
input {
class: "member-list-panel__search-input",
r#type: "text",
placeholder: "Search members...",
value: "{search_query}",
oninput: move |evt| {
search_query.set(evt.value());
},
}
}
div {
class: "member-list-panel__invite",
button {
class: "member-list-panel__invite-btn",
"Invite to this room"
}
}
div {
class: "member-list-panel__list",
if filtered_members.is_empty() {
p {
class: "member-list-panel__empty",
if query.is_empty() {
"Loading members..."
} else {
"No members found."
}
}
}
for member in filtered_members.iter() {
MemberListItem {
key: "{member.user_id}",
user_id: member.user_id.to_string(),
display_name: member.display_name.clone().unwrap_or_else(|| member.user_id.to_string()),
avatar_url: member.avatar_url.clone(),
power_level: member.power_level,
membership: member.membership.clone(),
}
}
}
}
}
}
#[component]
fn MemberListItem(
user_id: String,
display_name: String,
avatar_url: Option<String>,
power_level: i64,
membership: MemberMembership,
) -> Element {
let mut state = use_context::<Signal<AppState>>();
let user_id_clone = user_id.clone();
let on_click = move |_| {
state.write().right_panel = RightPanelView::MemberDetail(user_id_clone.clone());
};
let role_label = match power_level {
100.. => "Admin",
50..=99 => "Moderator",
_ => "",
};
rsx! {
div {
class: "member-list-item",
onclick: on_click,
Avatar {
name: display_name.clone(),
url: avatar_url,
size: 32,
}
div {
class: "member-list-item__info",
span {
class: "member-list-item__name",
"{display_name}"
}
span {
class: "member-list-item__user-id",
"{user_id}"
}
}
if !role_label.is_empty() {
span {
class: "member-list-item__role",
"{role_label}"
}
}
}
}
}