add new link modal

This commit is contained in:
Romulus21
2025-10-08 14:31:55 +02:00
parent 3bf77add88
commit 64e0168443

View File

@@ -26,58 +26,25 @@ pub async fn add_value(name: String, link: String, icon: String) -> Result<(), S
#[component] #[component]
pub fn Links() -> impl IntoView { pub fn Links() -> impl IntoView {
let (show, set_show) = create_signal(false); let (show_form, set_show_form) = create_signal(false);
let (edit_link, set_edit_link) = create_signal::<Option<crate::models::Link>>(None);
let (edit, set_edit) = create_signal(false); let (edit, set_edit) = create_signal(false);
let link_action = create_server_action::<LinkAction>(); let link_action = create_server_action::<LinkAction>();
let update_action = create_server_action::<UpdateLinkAction>();
let result = link_action.version(); let result = link_action.version();
let reset_form = create_rw_signal(""); let update_result = update_action.version();
let links = create_resource( let links = create_resource(
move || (result.get()), move || (result.get(), update_result.get()),
move |_| async move { move |_| async move {
reset_form.set(""); set_show_form.set(false);
set_show.set(false); set_edit_link.set(None);
get_links().await get_links().await
}, },
); );
let form = move || {
show.get().then(|| {
view! { <div class="my-0 mx-auto w-72 p-6 bg-prim-light rounded-lg">
<h2 class="pb-6 text-2xl text-center">"Ajout d'un lien"</h2>
<ActionForm action=link_action>
<div>
<label class="block mt-3 mb-1">"Nom"</label>
<input type="text"
name="name"
prop:value=move || reset_form.get()
class="text-center bg-prim border border-transparent rounded-lg focus:border-third px-2 py-2 w-60" />
</div>
<div>
<label class="block mt-3 mb-1">"Lien"</label>
<input type="url"
name="link"
prop:value=move || reset_form.get()
class="text-center bg-prim border border-transparent rounded-lg focus:border-third px-2 py-2 w-60" />
</div>
<div>
<label class="block mt-3 mb-1">"Icône"</label>
<input type="url"
name="icon"
placeholder="http..."
prop:value=move || reset_form.get()
class="text-center bg-prim border border-transparent rounded-lg focus:border-third px-2 py-2 w-60" />
</div>
<div>
<button type="submit" class="bg-third hover:bg-third-light rounded-lg transition-colors px-2 py-1 w-60 my-5">"Valider"</button>
</div>
</ActionForm>
</div> }
})
};
view! { view! {
<Title text="Liens"/> <Title text="Liens"/>
<ul class="flex gap-5 m-5 flex-wrap justify-center"> <ul class="flex gap-5 m-5 flex-wrap justify-center">
@@ -92,7 +59,7 @@ pub fn Links() -> impl IntoView {
children=move |(_, link)| { children=move |(_, link)| {
let link = create_rw_signal(link); let link = create_rw_signal(link);
view!{ view!{
<Link link edit links /> <Link link edit set_edit_link set_show_form links />
} }
}/> }/>
} }
@@ -103,12 +70,22 @@ pub fn Links() -> impl IntoView {
<div class="flex justify-end gap-5 mx-5"> <div class="flex justify-end gap-5 mx-5">
<button on:click=move |_| {set_edit.set(!edit.get())} class="bg-prim-light hover:bg-prim-lightest rounded-full px-5 py-3 text-second-dark hover:text-third transition-colors">"Modifier"</button> <button on:click=move |_| {set_edit.set(!edit.get())} class="bg-prim-light hover:bg-prim-lightest rounded-full px-5 py-3 text-second-dark hover:text-third transition-colors">"Modifier"</button>
<button on:click=move |_| {set_show.set(true)} class="bg-prim-light hover:bg-prim-lightest rounded-full px-5 py-3 text-second-dark hover:text-third transition-colors">"Ajouter un lien +"</button> <button on:click=move |_| {
set_edit_link.set(None);
set_show_form.set(true);
} class="bg-prim-light hover:bg-prim-lightest rounded-full px-5 py-3 text-second-dark hover:text-third transition-colors">"Ajouter un lien +"</button>
</div> </div>
<div class="flex justify-center m-5"> {move || {
{form} show_form.get().then(|| {
</div> view! { <LinkFormModal
link=edit_link.get()
set_show=set_show_form
add_action=link_action
update_action=update_action
/> }
})
}}
} }
} }
@@ -128,10 +105,10 @@ pub async fn change_position(link_id: String, direction: String) -> Result<(), S
fn Link<T: 'static + Clone, S: 'static>( fn Link<T: 'static + Clone, S: 'static>(
link: RwSignal<crate::models::Link>, link: RwSignal<crate::models::Link>,
edit: ReadSignal<bool>, edit: ReadSignal<bool>,
set_edit_link: WriteSignal<Option<crate::models::Link>>,
set_show_form: WriteSignal<bool>,
links: Resource<T, S>, links: Resource<T, S>,
) -> impl IntoView { ) -> impl IntoView {
let (show_edit, set_show_edit) = create_signal(false);
view! { view! {
<li class="mx-auto w-44 lg:w-60"> <li class="mx-auto w-44 lg:w-60">
<a class="bg-prim-light w-full hover:bg-prim-lightest border-b hover:border-third border-transparent text-xl rounded-lg text-center hover:text-third transition-colors px-5 py-4 inline-block" <a class="bg-prim-light w-full hover:bg-prim-lightest border-b hover:border-third border-transparent text-xl rounded-lg text-center hover:text-third transition-colors px-5 py-4 inline-block"
@@ -150,18 +127,16 @@ fn Link<T: 'static + Clone, S: 'static>(
view! { <div class="bg-third border border-transparent rounded-b-lg flex justify-between"> view! { <div class="bg-third border border-transparent rounded-b-lg flex justify-between">
<MoveButton id=link.with(|x| x.id.to_string()) value="prev".to_string() label="<".to_string() links=links /> <MoveButton id=link.with(|x| x.id.to_string()) value="prev".to_string() label="<".to_string() links=links />
<button class="block px-2 py-1 flex-1 hover:bg-third-light" <button class="block px-2 py-1 flex-1 hover:bg-third-light"
on:click=move |_| {set_show_edit.set(true)} on:click=move |_| {
set_edit_link.set(Some(link.get()));
set_show_form.set(true);
}
>"Editer"</button> >"Editer"</button>
<DeleteButton id=link.with(|x| x.id.to_string()) links=links /> <DeleteButton id=link.with(|x| x.id.to_string()) links=links />
<MoveButton id=link.with(|x| x.id.to_string()) value="next".to_string() label=">".to_string() links=links /> <MoveButton id=link.with(|x| x.id.to_string()) value="next".to_string() label=">".to_string() links=links />
</div> } </div> }
}) })
}} }}
{move || {
show_edit.get().then(|| {
view! { <EditLinkForm link=link set_show=set_show_edit links=links /> }
})
}}
</li> </li>
} }
} }
@@ -235,67 +210,109 @@ pub async fn update_link(id: String, name: String, link: String, icon: String) -
} }
#[component] #[component]
fn EditLinkForm<T: 'static + Clone, S: 'static>( fn LinkFormModal(
link: RwSignal<crate::models::Link>, link: Option<crate::models::Link>,
set_show: WriteSignal<bool>, set_show: WriteSignal<bool>,
links: Resource<T, S>, add_action: Action<LinkAction, Result<(), ServerFnError>>,
update_action: Action<UpdateLinkAction, Result<(), ServerFnError>>,
) -> impl IntoView { ) -> impl IntoView {
let update_action = create_server_action::<UpdateLinkAction>(); let is_edit = link.is_some();
let (name, set_name) = create_signal(link.as_ref().map(|x| x.name.clone()).unwrap_or_default());
let (name, set_name) = create_signal(link.with(|x| x.name.clone())); let (link_url, set_link_url) = create_signal(link.as_ref().map(|x| x.link.clone()).unwrap_or_default());
let (link_url, set_link_url) = create_signal(link.with(|x| x.link.clone())); let (icon, set_icon) = create_signal(link.as_ref().map(|x| x.icon.clone()).unwrap_or_default());
let (icon, set_icon) = create_signal(link.with(|x| x.icon.clone())); let link_id = link.as_ref().map(|x| x.id.to_string());
create_effect(move |_| {
if update_action.value().get().is_some() {
links.refetch();
set_show.set(false);
}
});
view! { view! {
<div class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50"> <div class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
<div class="bg-prim-light p-6 rounded-lg w-96"> <div class="bg-prim-light p-6 rounded-lg w-96">
<h2 class="pb-6 text-2xl text-center">"Édition du lien"</h2> <h2 class="pb-6 text-2xl text-center">
<ActionForm action=update_action> {if is_edit { "Édition du lien" } else { "Ajout d'un lien" }}
<input name="id" type="hidden" value={move || link.with(|x| x.id.to_string())} /> </h2>
<div> {if is_edit {
<label class="block mt-3 mb-1">"Nom"</label> view! {
<input type="text" <ActionForm action=update_action>
name="name" <input name="id" type="hidden" value={link_id.unwrap_or_default()} />
prop:value=move || name.get() <LinkFormFields
on:input=move |ev| set_name.set(event_target_value(&ev)) name=name
class="text-center bg-prim border border-transparent rounded-lg focus:border-third px-2 py-2 w-full" /> set_name=set_name
</div> link_url=link_url
set_link_url=set_link_url
<div> icon=icon
<label class="block mt-3 mb-1">"Lien"</label> set_icon=set_icon
<input type="url" />
name="link" <FormButtons set_show=set_show />
prop:value=move || link_url.get() </ActionForm>
on:input=move |ev| set_link_url.set(event_target_value(&ev)) }.into_view()
class="text-center bg-prim border border-transparent rounded-lg focus:border-third px-2 py-2 w-full" /> } else {
</div> view! {
<ActionForm action=add_action>
<div> <LinkFormFields
<label class="block mt-3 mb-1">"Icône"</label> name=name
<input type="url" set_name=set_name
name="icon" link_url=link_url
prop:value=move || icon.get() set_link_url=set_link_url
on:input=move |ev| set_icon.set(event_target_value(&ev)) icon=icon
class="text-center bg-prim border border-transparent rounded-lg focus:border-third px-2 py-2 w-full" /> set_icon=set_icon
</div> />
<FormButtons set_show=set_show />
<div class="flex gap-2 mt-5"> </ActionForm>
<button type="button" }.into_view()
on:click=move |_| set_show.set(false) }}
class="bg-prim hover:bg-prim-light rounded-lg transition-colors px-2 py-1 flex-1">"Annuler"</button>
<button type="submit"
class="bg-third hover:bg-third-light rounded-lg transition-colors px-2 py-1 flex-1">"Valider"</button>
</div>
</ActionForm>
</div> </div>
</div> </div>
} }
}
#[component]
fn LinkFormFields(
name: ReadSignal<String>,
set_name: WriteSignal<String>,
link_url: ReadSignal<String>,
set_link_url: WriteSignal<String>,
icon: ReadSignal<String>,
set_icon: WriteSignal<String>,
) -> impl IntoView {
view! {
<div>
<label class="block mt-3 mb-1">"Nom"</label>
<input type="text"
name="name"
prop:value=move || name.get()
on:input=move |ev| set_name.set(event_target_value(&ev))
class="text-center bg-prim border border-transparent rounded-lg focus:border-third px-2 py-2 w-full" />
</div>
<div>
<label class="block mt-3 mb-1">"Lien"</label>
<input type="url"
name="link"
prop:value=move || link_url.get()
on:input=move |ev| set_link_url.set(event_target_value(&ev))
class="text-center bg-prim border border-transparent rounded-lg focus:border-third px-2 py-2 w-full" />
</div>
<div>
<label class="block mt-3 mb-1">"Icône"</label>
<input type="url"
name="icon"
placeholder="http..."
prop:value=move || icon.get()
on:input=move |ev| set_icon.set(event_target_value(&ev))
class="text-center bg-prim border border-transparent rounded-lg focus:border-third px-2 py-2 w-full" />
</div>
}
}
#[component]
fn FormButtons(set_show: WriteSignal<bool>) -> impl IntoView {
view! {
<div class="flex gap-2 mt-5">
<button type="button"
on:click=move |_| set_show.set(false)
class="bg-prim hover:bg-prim-light rounded-lg transition-colors px-2 py-1 flex-1">"Annuler"</button>
<button type="submit"
class="bg-third hover:bg-third-light rounded-lg transition-colors px-2 py-1 flex-1">"Valider"</button>
</div>
}
} }