use dioxus::prelude::*;
use matrix_sdk::ruma::api::client::room::create_room::v3::Request as CreateRoomRequest;
use matrix_sdk::ruma::api::client::room::Visibility;
use matrix_sdk::ruma::OwnedRoomId;
use crate::state::app_state::{AppState, AppView};
#[component]
pub fn CreateRoomDialog(on_close: EventHandler<()>) -> Element {
let mut state = use_context::<Signal<AppState>>();
let mut room_name = use_signal(|| String::new());
let mut room_topic = use_signal(|| String::new());
let mut is_public = use_signal(|| false);
let mut is_encrypted = use_signal(|| true);
let mut is_direct = use_signal(|| false);
let mut is_creating = use_signal(|| false);
let mut create_error = use_signal(|| Option::<String>::None);
let on_create = move |_| {
let name = room_name.read().clone();
if name.trim().is_empty() {
create_error.set(Some("Room name is required".to_string()));
return;
}
is_creating.set(true);
create_error.set(None);
let topic = room_topic.read().clone();
let public = *is_public.read();
let _encrypted = *is_encrypted.read();
let direct = *is_direct.read();
spawn(async move {
match create_room(state, &name, &topic, public, direct).await {
Ok(room_id) => {
tracing::info!("Room created: {room_id}");
let mut s = state.write();
s.active_room_id = Some(room_id.clone());
s.current_view = AppView::Room(room_id);
drop(s);
on_close.call(());
}
Err(e) => {
tracing::error!("Failed to create room: {e}");
create_error.set(Some(e));
}
}
is_creating.set(false);
});
};
rsx! {
div {
class: "modal-overlay",
onclick: move |_| on_close.call(()),
div {
class: "modal-dialog create-room-dialog",
onclick: move |evt| evt.stop_propagation(),
div {
class: "modal-dialog__header",
h2 { "Create Room" }
button {
class: "modal-dialog__close",
onclick: move |_| on_close.call(()),
"✕"
}
}
div {
class: "modal-dialog__body",
if let Some(err) = create_error.read().as_ref() {
div {
class: "create-room-dialog__error",
"{err}"
}
}
div {
class: "create-room-dialog__field",
label { "Room Name" }
input {
r#type: "text",
placeholder: "e.g. My Room",
value: "{room_name}",
oninput: move |evt| room_name.set(evt.value()),
disabled: *is_creating.read(),
autofocus: true,
}
}
div {
class: "create-room-dialog__field",
label { "Topic (optional)" }
input {
r#type: "text",
placeholder: "What is this room about?",
value: "{room_topic}",
oninput: move |evt| room_topic.set(evt.value()),
disabled: *is_creating.read(),
}
}
div {
class: "create-room-dialog__options",
label {
class: "create-room-dialog__checkbox",
input {
r#type: "checkbox",
checked: *is_public.read(),
oninput: move |evt| is_public.set(evt.value() == "true"),
}
span { "Public room (anyone can join)" }
}
label {
class: "create-room-dialog__checkbox",
input {
r#type: "checkbox",
checked: *is_encrypted.read(),
oninput: move |evt| is_encrypted.set(evt.value() == "true"),
}
span { "Enable encryption" }
}
label {
class: "create-room-dialog__checkbox",
input {
r#type: "checkbox",
checked: *is_direct.read(),
oninput: move |evt| is_direct.set(evt.value() == "true"),
}
span { "Direct message" }
}
}
}
div {
class: "modal-dialog__footer",
button {
class: "btn btn--secondary",
onclick: move |_| on_close.call(()),
disabled: *is_creating.read(),
"Cancel"
}
button {
class: "btn btn--primary",
onclick: on_create,
disabled: room_name.read().trim().is_empty() || *is_creating.read(),
if *is_creating.read() {
"Creating..."
} else {
"Create Room"
}
}
}
}
}
}
}
async fn create_room(
state: Signal<AppState>,
name: &str,
topic: &str,
is_public: bool,
is_direct: bool,
) -> Result<OwnedRoomId, String> {
let client = { state.read().client.clone() };
let client = client.ok_or_else(|| "Not logged in".to_string())?;
let mut request = CreateRoomRequest::new();
request.name = Some(name.to_string());
if !topic.is_empty() {
request.topic = Some(topic.to_string());
}
request.visibility = if is_public {
Visibility::Public
} else {
Visibility::Private
};
request.is_direct = is_direct;
let response = client
.create_room(request)
.await
.map_err(|e| format!("Failed to create room: {e}"))?;
Ok(response.room_id().to_owned())
}