summaryrefslogtreecommitdiffstats
path: root/src/components/chats_list.rs
blob: 027de64c7d1c6958f19be7983195c993be24b5b8 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
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>
    }
}