use crate::app_types::AppSiteConnection;
use crate::components::common::dt_button::*;
use crate::components::common::dt_input_password::*;
use crate::components::common::dt_input_text::*;
use crate::components::common::dt_status_const_text::*;
use crate::components::common::main_layout::*;
use crate::components::common::titled_panel::*;
use crate::components::pages::register::RegisterRoute;
use crate::utils::get_input_value::get_input_value;
use crate::utils::set_focus::set_focus;
use crate::MainRoute;
use bounce::use_atom;
use bounce::UseAtomHandle;
use dialtone_common::rest::users::user_exchanges::PostUser;
use dialtone_common::rest::users::user_exchanges::PostUserResponse;
use dialtone_common::rest::users::user_login::UserCredential;
use dialtone_common::utils::make_acct::make_acct;
use dialtone_reqwest::api_v1::names::check_name_available::check_name_available;
use dialtone_reqwest::api_v1::users::register_user::register_user;
use futures_util::stream::StreamExt;
use gloo::console::log;
use gloo_timers::future::IntervalStream;
use std::rc::Rc;
use yew::prelude::*;
use yew_router::prelude::*;
struct OpenRegistrationFormState {
pub history: AnyHistory,
pub disabled_register_button: UseStateHandle<bool>,
pub in_progress: UseStateHandle<bool>,
pub username: UseStateHandle<String>,
pub password: UseStateHandle<String>,
pub status: UseStateHandle<ConstText>,
pub sc_atom: UseAtomHandle<AppSiteConnection>,
}
#[function_component(RegisterOpen)]
pub fn register_open() -> Html {
const BLANK_STATUS: ConstText = ConstText::blank();
const REGISTRATION_FAILED: ConstText =
ConstText::new(ConstStatusType::WARNING, "Could not register account");
const REGISTRATION_ERROR: ConstText =
ConstText::new(ConstStatusType::ERROR, "Account registration unavailable");
const NAME_UNAVAILABLE: ConstText =
ConstText::new(ConstStatusType::WARNING, "User name is already in use.");
let form_state = Rc::new(OpenRegistrationFormState {
history: use_history().unwrap(),
disabled_register_button: use_state(|| true),
in_progress: use_state(|| false),
username: use_state(|| "".to_string()),
password: use_state(|| "".to_string()),
status: use_state(|| BLANK_STATUS),
sc_atom: use_atom::<AppSiteConnection>(),
});
let on_button_click = {
let form_state = Rc::clone(&form_state);
Callback::from(move |_| {
let form_state = Rc::clone(&form_state);
form_state.in_progress.set(true);
form_state.status.set(BLANK_STATUS);
wasm_bindgen_futures::spawn_local(async move {
let sc = &form_state.sc_atom.0;
let acct = make_acct(&form_state.username, &sc.host_name.as_ref().unwrap());
let post_user = PostUser::OpenRegistration(UserCredential {
user_acct: acct,
password: form_state.password.to_string(),
});
let registration_result = register_user(sc, &post_user).await;
match registration_result {
Ok(registration_response) => match registration_response {
PostUserResponse::AccountRegistered(_) => {
form_state.history.push(RegisterRoute::Success);
}
PostUserResponse::AccountNotRegistered(_) => {
form_state.status.set(REGISTRATION_FAILED);
form_state.in_progress.set(false);
set_focus("register_username");
}
PostUserResponse::AccountNeedsApproval(_) => {
form_state.history.push(RegisterRoute::ApprovalNeeded);
}
},
Err(_) => {
form_state.status.set(REGISTRATION_ERROR);
form_state.in_progress.set(false);
}
}
});
})
};
let on_username = {
let form_state = Rc::clone(&form_state);
Callback::from(move |s| {
form_state.username.set(s);
if !form_state.username.is_empty() && !form_state.password.is_empty() {
form_state.disabled_register_button.set(false);
}
})
};
let on_password = {
let form_state = Rc::clone(&form_state);
Callback::from(move |s| {
form_state.password.set(s);
if !form_state.username.is_empty() && !form_state.password.is_empty() {
form_state.disabled_register_button.set(false);
}
})
};
use_effect_with_deps(
move |_| {
set_focus("register_username");
|| ()
},
(),
);
use_effect_with_deps(
{
let form_state = Rc::clone(&form_state);
move |_| {
wasm_bindgen_futures::spawn_local(async move {
let form_state = Rc::clone(&form_state);
let status = form_state.status.clone();
let sc_atom = form_state.sc_atom.clone();
IntervalStream::new(750)
.take_while(|_| async { get_input_value("register_username").is_some() })
.fold(String::new(), |name_to_check, _| async {
let status = status.clone();
let sc_atom = sc_atom.clone();
let input_value = get_input_value("register_username");
if input_value.is_none() {
name_to_check
} else {
let input_value = input_value.unwrap();
if input_value.len() > 2 && input_value != name_to_check {
log!("checking name ", &input_value);
let name_available =
check_name_available(&sc_atom.0, &input_value).await;
if let Ok(name_available) = name_available {
if !name_available {
status.set(NAME_UNAVAILABLE);
} else {
status.set(BLANK_STATUS);
}
}
input_value
} else {
name_to_check
}
}
})
.await;
});
|| ()
}
},
(),
);
html! {
<MainLayout>
<div class="centered_form_page">
<TitledPanel title="Register Account">
<form class="basic_form"
onsubmit={Callback::from(|e: FocusEvent| e.prevent_default())}
autocomplete="off" >
<label for="register_username">{"Username:"}</label>
<DtInputText
id="register_username"
disabled=false
name="register_username"
on_update_value={on_username}/>
<label for="register_password">{"Password:"}</label>
<DtInputPassword
id="register_password"
disabled=false
name="register_password"
on_update_value={on_password}/>
<DtButton
text="Register"
disabled={*form_state.disabled_register_button}
on_click={on_button_click.clone()}
id="register_button"
in_progress={*form_state.in_progress}/>
<DtStatusConstText
status={(*form_state.status).clone()} />
<span>
<Link<MainRoute>
classes={classes!("in_page_action")}
to={MainRoute::Login}>{"Login to Existing Account"}
</Link<MainRoute>></span>
</form>
</TitledPanel>
</div>
</MainLayout>
}
}