summaryrefslogblamecommitdiffstats
path: root/src/components/chats_list.rs
blob: 027de64c7d1c6958f19be7983195c993be24b5b8 (plain) (tree)
1
2
3
4
5
6
7
8


                                   


                                                                  

                   







                                                                                 














                                                                             

                                                                       


                                                   

                                                                                               

                          
                 






















                                                                                     



                                                              







                                                                                     
                                                                             







                                                                
                                                      



                                                                























                                                                                                                                                                                                                                         




                                                   




                                                                                            





                                                                       

                                           





                                               









                                                                                      



                  
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>
    }
}