use http::Method;
use web_sys::{window, FormData};
use yew::html::onsubmit::Event;
use yew::{function_component, AttrValue, Callback, Children, NodeRef, Properties};
use yew::{Classes, TargetCast};
use crate::actions::{Action, AnyForm, RequestOptions, UseActionHandle};
#[derive(Properties)]
pub struct FormProps<A>
where
A: Action,
{
#[prop_or_default]
pub id: Option<AttrValue>,
#[prop_or_default]
pub node_ref: Option<NodeRef>,
#[prop_or_default]
pub children: Children,
#[prop_or_default]
pub class: Classes,
#[prop_or_default]
pub style: Option<AttrValue>,
#[prop_or(AttrValue::from("application/x-www-form-urlencoded"))]
pub enc_type: AttrValue,
#[prop_or_default]
pub onsubmit: Option<Callback<Event>>,
#[prop_or_default]
pub multipart: bool,
pub action: UseActionHandle<A, AnyForm>,
#[prop_or(Method::POST)]
pub method: Method,
#[prop_or(false)]
pub reload: bool,
}
impl<A> PartialEq for FormProps<A>
where
A: Action,
{
fn eq(&self, other: &Self) -> bool {
self.id == other.id
&& self.children == other.children
&& self.class == other.class
&& self.style == other.style
&& self.enc_type == other.enc_type
&& self.multipart == other.multipart
&& self.action == other.action
&& self.method == other.method
&& self.node_ref == other.node_ref
}
}
#[function_component]
pub fn ActionForm<A>(props: &FormProps<A>) -> yew::Html
where
A: Action + 'static,
{
let action = props.action.clone();
let loading = action.is_loading();
let method = props.method.clone();
let reload = props.reload;
let onsubmit = props.onsubmit.clone();
let node_ref = props.node_ref.clone();
let enc_type = if props.multipart {
AttrValue::from("multipart/form-data")
} else {
props.enc_type.clone()
};
let form_enctype = enc_type.clone();
let on_submit = move |event: yew::html::onsubmit::Event| {
event.prevent_default();
if let Some(onsubmit) = onsubmit.clone() {
onsubmit.emit(event.clone());
}
if loading {
return;
}
let form = event.target_dyn_into().unwrap();
let form_data = FormData::new_with_form(&form).unwrap();
let opts = RequestOptions::new().method(method.clone());
let form = match enc_type.as_str() {
"application/x-www-form-urlencoded" => AnyForm::UrlEncoded(form_data),
"multipart/form-data" => AnyForm::Multipart(form_data),
s => {
log::warn!("unsupported form enctype: {s}, only `application/x-www-form-urlencoded` and `multipart/form-data` are supported");
AnyForm::Multipart(form_data)
}
};
action
.send_with_options(form, opts)
.expect("failed to send form");
if reload {
let window = window().unwrap();
window.location().reload().unwrap();
}
};
yew::html! {
<form method={props.method.clone().to_string()}
onsubmit={on_submit}
id={props.id.clone()}
ref={node_ref.unwrap_or_default()}
class={props.class.clone()}
style={props.style.clone()}
action={A::route()}
enctype={form_enctype}
>
{for props.children.iter()}
</form>
}
}