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::{get_name, MacawUser}, user_presences::UserPresences, views::{macaw::settings::SettingsPage, AppState}};
#[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=user.get().into() />
<div class="dock-pill"></div>
</div>
{move || {
let open = open.get();
debug!("open = {:?}", open);
if open {
view! {
<Overlay set_open>
<PersonalStatusMenu user=user.get().into() set_open/>
</Overlay>
}.into_any()
} else {
view! {}.into_any()
}}}
}.into_any()
} else {
view! {}.into_any()
}
}
#[component]
pub fn PersonalStatusMenu(user: Store<User>, 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.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, false)}</div>
<div class="jid">{move || user.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 |_| {
// TODO: check if client is actually dropped/shutdown eventually
disconnect.dispatch(());
set_app.set(AppState::LoggedOut)
}>
Log out
</div>
</div>
}
}