summaryrefslogblamecommitdiffstats
path: root/src/components/personal_status.rs
blob: 59ffa47cb53ff3252bc3ccb42f6ab98731fe01eb (plain) (tree)
1
2
3
4
5
6
7
8



                                                    



                                       






                                                               





                                                                                          
































                                                                    



            
                                                                                          


                                                                                              
 


                                                                         














                                                                                  
              



                                                 










                                                                
                                               






                                                           






                                                   



                                                           






                                                



                                                           






                                                           



                                                           






                                                   



                                                           






                                                           




                                                                                
                           


                                                          
                           


                                              
                       









                                                

                                                                                                 










                                                                              

















                                                                                       


                         






                                                                   

                       






                                                                   


                        






                                                    




                       
use filamento::{
    presence::{Offline, Online, PresenceType, Show},
    user::{User, UserStoreFields},
};
use leptos::{html, prelude::*};
use reactive_stores::{ArcStore, Store};
use tracing::{debug, error};

use crate::{
    client::Client,
    components::{avatar::AvatarWithPresence, overlay::Overlay},
    user::{MacawUser, get_name},
    user_presences::UserPresences,
    views::{AppState, macaw::settings::SettingsPage},
};

#[component]
pub fn PersonalStatus() -> impl IntoView {
    let user: LocalResource<MacawUser> = use_context().expect("no local user in context");

    let (open, set_open) = signal(false);
    move || {
        if let Some(user) = user.get() {
            view! {
                <div
                    class="dock-item"
                    class:focused=move || *open.read()
                    on:click=move |_| {
                        debug!("set open to true");
                        set_open.update(|state| *state = !*state)
                    }
                >
                    <AvatarWithPresence user />
                    <div class="dock-pill"></div>
                </div>
                {move || {
                    let open = open.get();
                    debug!("open = {:?}", open);
                    if open {
                        view! {
                            <Overlay set_open>
                                <PersonalStatusMenu user set_open />
                            </Overlay>
                        }
                            .into_any()
                    } else {
                        view! {}.into_any()
                    }
                }}
            }
            .into_any()
        } else {
            view! {}.into_any()
        }
    }
}

#[component]
pub fn PersonalStatusMenu(user: MacawUser, set_open: WriteSignal<bool>) -> impl IntoView {
    let set_app: WriteSignal<AppState> = use_context().unwrap();
    let show_settings: RwSignal<Option<SettingsPage>> = use_context().unwrap();
    let user_presences: Store<UserPresences> = use_context().expect("no user presence store");

    let client = use_context::<Client>().expect("client not in context");
    let client1 = client.clone();
    let (show_value, set_show_value) = signal({
        let show = match user_presences
            .write()
            .get_user_presences(&user.get().jid().read())
            .write()
            .resource_presence(client.resource.read().clone().unwrap_or_default())
            .presence
        {
            PresenceType::Online(online) => match online.show {
                Some(s) => match s {
                    Show::Away => 3,
                    Show::Chat => 0,
                    Show::DoNotDisturb => 2,
                    Show::ExtendedAway => 4,
                },
                None => 1,
            },
            PresenceType::Offline(_offline) => 5,
        };
        debug!("initial show = {show}");
        show
    });

    let show_select: NodeRef<html::Select> = NodeRef::new();

    let disconnect = Action::new_local(move |()| {
        let client = client.clone();
        async move {
            client.disconnect(Offline::default()).await;
        }
    });
    let set_status = Action::new_local(move |show_value: &i32| {
        let show_value = show_value.to_owned();
        let client = client1.clone();
        async move {
            if let Err(e) = match show_value {
                0 => {
                    if let Ok(r) = client.connect().await {
                        client.resource.set(Some(r))
                    };
                    client
                        .set_status(Online {
                            show: Some(Show::Chat),
                            ..Default::default()
                        })
                        .await
                }
                1 => {
                    if let Ok(r) = client.connect().await {
                        client.resource.set(Some(r))
                    };
                    client
                        .set_status(Online {
                            show: None,
                            ..Default::default()
                        })
                        .await
                }
                2 => {
                    if let Ok(r) = client.connect().await {
                        client.resource.set(Some(r))
                    };
                    client
                        .set_status(Online {
                            show: Some(Show::DoNotDisturb),
                            ..Default::default()
                        })
                        .await
                }
                3 => {
                    if let Ok(r) = client.connect().await {
                        client.resource.set(Some(r))
                    };
                    client
                        .set_status(Online {
                            show: Some(Show::Away),
                            ..Default::default()
                        })
                        .await
                }
                4 => {
                    if let Ok(r) = client.connect().await {
                        client.resource.set(Some(r))
                    };
                    client
                        .set_status(Online {
                            show: Some(Show::ExtendedAway),
                            ..Default::default()
                        })
                        .await
                }
                5 => {
                    if let Ok(_) = client.disconnect(Offline::default()).await {
                        client.resource.set(None)
                    }
                    set_show_value.set(5);
                    return;
                }
                _ => {
                    error!("invalid availability select");
                    return;
                }
            } {
                error!("show set error: {e}");
                return;
            }
            set_show_value.set(show_value);
        }
    });

    view! {
        <div class="personal-status-menu menu">
            <div class="user">
                <AvatarWithPresence user=user />
                <div class="user-info">
                    <div class="nick">{move || get_name(user.get().into(), false)}</div>
                    <div class="jid">{move || user.get().jid().with(|jid| jid.to_string())}</div>
                </div>
            </div>
            <div class="status-edit">
                <select
                    node_ref=show_select
                    on:change:target=move |ev| {
                        let show_value = ev.target().value().parse().unwrap();
                        set_status.dispatch(show_value);
                    }
                    prop:show_value=move || show_value.get().to_string()
                >
                    <option value="0" selected=move || show_value.get_untracked() == 0>
                        Available to Chat
                    </option>
                    <option value="1" selected=move || show_value.get_untracked() == 1>
                        Online
                    </option>
                    <option value="2" selected=move || show_value.get_untracked() == 2>
                        Do not disturb
                    </option>
                    <option value="3" selected=move || show_value.get_untracked() == 3>
                        Away
                    </option>
                    <option value="4" selected=move || show_value.get_untracked() == 4>
                        Extended Away
                    </option>
                    <option value="5" selected=move || show_value.get_untracked() == 5>
                        Offline
                    </option>
                </select>
            </div>
            <hr />
            <div
                class="menu-item"
                on:click=move |_| {
                    show_settings.set(Some(SettingsPage::Profile));
                    set_open.set(false);
                }
            >
                Profile
            </div>
            <div
                class="menu-item"
                on:click=move |_| {
                    show_settings.set(Some(SettingsPage::Account));
                    set_open.set(false);
                }
            >
                Settings
            </div>
            <hr />
            <div
                class="menu-item"
                on:click=move |_| {
                    disconnect.dispatch(());
                    set_app.set(AppState::LoggedOut)
                }
            >
                Log out
            </div>
        </div>
    }
}