From 64e016844321431f08dde680d3d941764656a2ce Mon Sep 17 00:00:00 2001 From: Romulus21 Date: Wed, 8 Oct 2025 14:31:55 +0200 Subject: [PATCH] add new link modal --- src/routes/link.rs | 233 ++++++++++++++++++++++++--------------------- 1 file changed, 125 insertions(+), 108 deletions(-) diff --git a/src/routes/link.rs b/src/routes/link.rs index 5d0f125..8892e8e 100644 --- a/src/routes/link.rs +++ b/src/routes/link.rs @@ -26,58 +26,25 @@ pub async fn add_value(name: String, link: String, icon: String) -> Result<(), S #[component] 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::>(None); let (edit, set_edit) = create_signal(false); let link_action = create_server_action::(); + let update_action = create_server_action::(); + let result = link_action.version(); - let reset_form = create_rw_signal(""); + let update_result = update_action.version(); + let links = create_resource( - move || (result.get()), + move || (result.get(), update_result.get()), move |_| async move { - reset_form.set(""); - set_show.set(false); + set_show_form.set(false); + set_edit_link.set(None); get_links().await }, ); - let form = move || { - show.get().then(|| { - view! {
-

"Ajout d'un lien"

- -
- - -
- -
- - -
- -
- - -
-
- -
-
-
} - }) - }; - view! { <ul class="flex gap-5 m-5 flex-wrap justify-center"> @@ -92,7 +59,7 @@ pub fn Links() -> impl IntoView { children=move |(_, link)| { let link = create_rw_signal(link); 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"> <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 class="flex justify-center m-5"> - {form} - </div> + {move || { + show_form.get().then(|| { + 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>( link: RwSignal<crate::models::Link>, edit: ReadSignal<bool>, + set_edit_link: WriteSignal<Option<crate::models::Link>>, + set_show_form: WriteSignal<bool>, links: Resource<T, S>, ) -> impl IntoView { - let (show_edit, set_show_edit) = create_signal(false); - view! { <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" @@ -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"> <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" - 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> <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 /> </div> } }) }} - {move || { - show_edit.get().then(|| { - view! { <EditLinkForm link=link set_show=set_show_edit links=links /> } - }) - }} </li> } } @@ -235,67 +210,109 @@ pub async fn update_link(id: String, name: String, link: String, icon: String) - } #[component] -fn EditLinkForm<T: 'static + Clone, S: 'static>( - link: RwSignal<crate::models::Link>, +fn LinkFormModal( + link: Option<crate::models::Link>, set_show: WriteSignal<bool>, - links: Resource<T, S>, + add_action: Action<LinkAction, Result<(), ServerFnError>>, + update_action: Action<UpdateLinkAction, Result<(), ServerFnError>>, ) -> impl IntoView { - let update_action = create_server_action::<UpdateLinkAction>(); - - let (name, set_name) = create_signal(link.with(|x| x.name.clone())); - let (link_url, set_link_url) = create_signal(link.with(|x| x.link.clone())); - let (icon, set_icon) = create_signal(link.with(|x| x.icon.clone())); - - create_effect(move |_| { - if update_action.value().get().is_some() { - links.refetch(); - set_show.set(false); - } - }); + let is_edit = link.is_some(); + let (name, set_name) = create_signal(link.as_ref().map(|x| x.name.clone()).unwrap_or_default()); + let (link_url, set_link_url) = create_signal(link.as_ref().map(|x| x.link.clone()).unwrap_or_default()); + let (icon, set_icon) = create_signal(link.as_ref().map(|x| x.icon.clone()).unwrap_or_default()); + let link_id = link.as_ref().map(|x| x.id.to_string()); view! { <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"> - <h2 class="pb-6 text-2xl text-center">"Édition du lien"</h2> - <ActionForm action=update_action> - <input name="id" type="hidden" value={move || link.with(|x| x.id.to_string())} /> + <h2 class="pb-6 text-2xl text-center"> + {if is_edit { "Édition du lien" } else { "Ajout d'un lien" }} + </h2> - <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" - 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> - - <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> - </ActionForm> + {if is_edit { + view! { + <ActionForm action=update_action> + <input name="id" type="hidden" value={link_id.unwrap_or_default()} /> + <LinkFormFields + name=name + set_name=set_name + link_url=link_url + set_link_url=set_link_url + icon=icon + set_icon=set_icon + /> + <FormButtons set_show=set_show /> + </ActionForm> + }.into_view() + } else { + view! { + <ActionForm action=add_action> + <LinkFormFields + name=name + set_name=set_name + link_url=link_url + set_link_url=set_link_url + icon=icon + set_icon=set_icon + /> + <FormButtons set_show=set_show /> + </ActionForm> + }.into_view() + }} </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> + } } \ No newline at end of file