use chats_list_item::ChatsListItem;
use indexmap::IndexMap;
use jid::BareJID;
use js_sys::{wasm_bindgen::UnwrapThrowExt, Object, Reflect, JSON};
use leptos::{html::Div, prelude::*};
use overlay_scrollbars::OverlayScrollbars;
use tracing::debug;
use crate::{
chat::{ArcMacawChat, MacawChat},
client::Client,
components::{icon::IconComponent, new_chat::NewChatWidget, overlay::Overlay},
icon::Icon,
message::{ArcMacawMessage, MacawMessage},
message_subscriptions::MessageSubscriptions,
};
mod chats_list_item;
#[component]
pub fn ChatsList() -> impl IntoView {
let (chats, set_chats) = signal(IndexMap::new());
let load_chats = LocalResource::new(move || async move {
let client = use_context::<Client>().expect("client not in context");
let chats = client
.get_chats_ordered_with_latest_messages_and_users()
.await
.map_err(|e| e.to_string());
match chats {
Ok(c) => {
let mut chats = IndexMap::new();
for ((chat, chat_user), (message, message_user)) in c {
chats.insert(
chat.correspondent.clone(),
(
ArcMacawChat::got_chat_and_user(chat, chat_user).await,
ArcMacawMessage::got_message_and_user(message, message_user).await,
),
);
}
set_chats.set(chats);
}
Err(_) => {
// TODO: show error message at top of chats list
}
}
});
let (open_new_chat, set_open_new_chat) = signal(false);
// TODO: filter new messages signal
let new_messages_signal: RwSignal<MessageSubscriptions> = use_context().unwrap();
let (sub_id, set_sub_id) = signal(None);
let _load_new_messages = LocalResource::new(move || async move {
load_chats.await;
let (sub_id, mut new_messages) = new_messages_signal.write().subscribe_all();
set_sub_id.set(Some(sub_id));
while let Some((to, new_message)) = new_messages.recv().await {
debug!("got new message in let");
let mut chats = set_chats.write();
if let Some((chat, _latest_message)) = chats.shift_remove(&to) {
// TODO: check if new message is actually latest message
debug!("chat existed");
debug!(
"new message: {}",
new_message.message.get().read().body.body
);
chats.insert_before(0, to, (chat.clone(), new_message));
debug!("done setting");
} else {
debug!("the chat didn't exist");
let client = use_context::<Client>().expect("client not in context");
let chat = client.get_chat(to.clone()).await.unwrap();
let user = client.get_user(to.clone()).await.unwrap();
debug!("before got chat");
let chat = ArcMacawChat::got_chat_and_user(chat, user).await;
debug!("after got chat");
chats.insert_before(0, to, (chat, new_message));
debug!("done setting");
}
}
debug!("set the new message");
});
on_cleanup(move || {
if let Some(sub_id) = sub_id.get_untracked() {
new_messages_signal.write().unsubscribe_all(sub_id);
}
});
let chats_list: NodeRef<Div> = NodeRef::new();
let chats_list_viewport: NodeRef<Div> = NodeRef::new();
let _scrollbars = Effect::new(move |_| {
if let Some(buffer) = chats_list.get() {
if let Some(viewport) = chats_list_viewport.get() {
let scrollbars_obj = Object::new();
// Reflect::set(&scrollbars_obj, &"theme".into(), &"os-macaw".into()).unwrap_throw();
// Reflect::set(&scrollbars_obj, &"autoHide".into(), &"leave".into()).unwrap_throw();
let options_obj = Object::new();
// Reflect::set(&options_obj, &"scrollbars".into(), &scrollbars_obj).unwrap_throw();
let elements_obj = Object::new();
Reflect::set(&elements_obj, &"viewport".into(), &viewport.into()).unwrap_throw();
let element_obj = Object::new();
Reflect::set(&elements_obj, &"elements".into(), &elements_obj).unwrap_throw();
Reflect::set(&element_obj, &"target".into(), &buffer.into()).unwrap_throw();
// let element = Object::define_property(&Object::define_property(&Object::new(), &"target".into(), &buffer.into()), &"elements".into(), &Object::define_property(&Object::new(), &"viewport".into(), &viewport.into()));
debug!("scrollable element: {}", JSON::stringify(&element_obj.clone().into()).unwrap_throw());
OverlayScrollbars(element_obj, options_obj);
}
}
});
view! {
<div class="chats-list panel">
// TODO: update icon, tooltip on hover.
<div class="header">
<h2>Chats</h2>
<div class="new-chat header-icon" class:open=open_new_chat>
<IconComponent
icon=Icon::NewBubble24
on:click=move |_| set_open_new_chat.update(|state| *state = !*state)
/>
{move || {
if *open_new_chat.read() {
view! {
<Overlay set_open=set_open_new_chat>
<NewChatWidget set_open_new_chat />
</Overlay>
}
.into_any()
} else {
view! {}.into_any()
}
}}
</div>
</div>
<div class="overlay-scroll" node_ref=chats_list>
<div class="chats-list-chats" node_ref=chats_list_viewport>
<For
each=move || chats.get()
key=|chat| chat.1.1.message.get().read().id
let(chat)
>
<ChatsListItem chat=chat.1.0.into() message=chat.1.1.into() />
</For>
</div>
</div>
</div>
}
}