use dioxus::prelude::*;
use crate::state::app_state::AppState;
use crate::state::room_state::ReactionGroup;
async fn toggle_reaction(
state: Signal<AppState>,
room_id: &str,
event_id: &str,
emoji: &str,
) -> Result<(), String> {
let client = { state.read().client.clone() };
let client = client.ok_or_else(|| "Not logged in".to_string())?;
let room_id: matrix_sdk::ruma::OwnedRoomId = room_id
.try_into()
.map_err(|e| format!("Invalid room ID: {e}"))?;
let target_event_id: matrix_sdk::ruma::OwnedEventId = event_id
.try_into()
.map_err(|e| format!("Invalid event ID: {e}"))?;
let room = client
.get_room(&room_id)
.ok_or_else(|| format!("Room not found: {room_id}"))?;
use matrix_sdk::ruma::events::reaction::ReactionEventContent;
use matrix_sdk::ruma::events::relation::Annotation;
let annotation = Annotation::new(target_event_id, emoji.to_string());
let content = ReactionEventContent::new(annotation);
room.send(content)
.await
.map_err(|e| format!("Failed to send reaction: {e}"))?;
Ok(())
}
#[component]
pub fn ReactionList(room_id: String, event_id: String, reactions: Vec<ReactionGroup>) -> Element {
let state = use_context::<Signal<AppState>>();
rsx! {
div {
class: "reaction-list",
for reaction in reactions.iter() {
{
let emoji = reaction.key.clone();
let rid = room_id.clone();
let eid = event_id.clone();
let already_reacted = reaction.user_reacted;
rsx! {
button {
class: if already_reacted {
"reaction-list__item reaction-list__item--active"
} else {
"reaction-list__item"
},
title: "{reaction.senders.len()} reactions",
onclick: move |_| {
if !already_reacted {
let rid = rid.clone();
let eid = eid.clone();
let emoji = emoji.clone();
spawn(async move {
if let Err(e) = toggle_reaction(state, &rid, &eid, &emoji).await {
tracing::error!("Failed to toggle reaction: {e}");
}
});
}
},
span { class: "reaction-list__emoji", "{reaction.key}" }
span { class: "reaction-list__count", "{reaction.count}" }
}
}
}
}
button {
class: "reaction-list__add",
title: "Add reaction",
"+"
}
}
}
}