use dioxus::prelude::*;
use matrix_sdk::ruma::{OwnedRoomId, OwnedUserId};
use crate::state::app_state::AppState;
#[component]
pub fn InviteDialog(room_id: String, on_close: EventHandler<()>) -> Element {
let state = use_context::<Signal<AppState>>();
let mut user_id_input = use_signal(|| String::new());
let mut is_inviting = use_signal(|| false);
let mut invite_error = use_signal(|| Option::<String>::None);
let mut invite_success = use_signal(|| Option::<String>::None);
let rid = room_id.clone();
let on_invite = move |_| {
let user_str = user_id_input.read().trim().to_string();
if user_str.is_empty() {
invite_error.set(Some("Please enter a user ID".to_string()));
return;
}
is_inviting.set(true);
invite_error.set(None);
invite_success.set(None);
let rid = rid.clone();
spawn(async move {
match invite_user(state, &rid, &user_str).await {
Ok(()) => {
tracing::info!("Invited {user_str} to {rid}");
invite_success.set(Some(format!("Invited {user_str}")));
user_id_input.set(String::new());
}
Err(e) => {
tracing::error!("Failed to invite: {e}");
invite_error.set(Some(e));
}
}
is_inviting.set(false);
});
};
rsx! {
div {
class: "modal-overlay",
onclick: move |_| on_close.call(()),
div {
class: "modal-dialog invite-dialog",
onclick: move |evt| evt.stop_propagation(),
div {
class: "modal-dialog__header",
h2 { "Invite User" }
button {
class: "modal-dialog__close",
onclick: move |_| on_close.call(()),
"✕"
}
}
div {
class: "modal-dialog__body",
if let Some(err) = invite_error.read().as_ref() {
div {
class: "invite-dialog__error",
"{err}"
}
}
if let Some(msg) = invite_success.read().as_ref() {
div {
class: "invite-dialog__success",
"{msg}"
}
}
div {
class: "invite-dialog__field",
label { "User ID" }
input {
r#type: "text",
placeholder: "@user:server.org",
value: "{user_id_input}",
oninput: move |evt| user_id_input.set(evt.value()),
disabled: *is_inviting.read(),
autofocus: true,
}
}
}
div {
class: "modal-dialog__footer",
button {
class: "btn btn--secondary",
onclick: move |_| on_close.call(()),
"Close"
}
button {
class: "btn btn--primary",
onclick: on_invite,
disabled: user_id_input.read().trim().is_empty() || *is_inviting.read(),
if *is_inviting.read() {
"Inviting..."
} else {
"Invite"
}
}
}
}
}
}
}
async fn invite_user(
state: Signal<AppState>,
room_id_str: &str,
user_id_str: &str,
) -> Result<(), String> {
let client = { state.read().client.clone() };
let client = client.ok_or_else(|| "Not logged in".to_string())?;
let room_id: OwnedRoomId = room_id_str
.try_into()
.map_err(|e| format!("Invalid room ID: {e}"))?;
let user_id: OwnedUserId = user_id_str
.try_into()
.map_err(|e| format!("Invalid user ID: {e}"))?;
let room = client
.get_room(&room_id)
.ok_or_else(|| format!("Room not found: {room_id}"))?;
room.invite_user_by_id(&user_id)
.await
.map_err(|e| format!("Failed to invite: {e}"))?;
Ok(())
}