Implemented public form appearance settings.
This commit is contained in:
@@ -0,0 +1,127 @@
|
||||
use leptos::*;
|
||||
use crate::backend::appearance::{DeleteBanner, get_appearance, UpdateAppearance};
|
||||
use crate::backend::data::Appearance;
|
||||
use crate::components::data_form::{DataForm, QuestionDialog};
|
||||
use crate::components::modal_box::DialogOpener;
|
||||
use crate::locales::trl;
|
||||
|
||||
#[component]
|
||||
fn edit_title(opener: DialogOpener, appearance: ReadSignal<Appearance>) -> impl IntoView {
|
||||
let update = create_server_action::<UpdateAppearance>();
|
||||
view! {
|
||||
<DataForm opener=opener action=update title="Update title">
|
||||
<input type="hidden" prop:value={move || appearance.get().text.unwrap_or_default()} name="appearance[text]" />
|
||||
<input type="hidden" prop:value={move || appearance.get().id()} name="appearance[id]"/>
|
||||
<div class="row">
|
||||
<div class="col mb-3">
|
||||
<label for="title" class="form-label">{trl("Title")}</label>
|
||||
<input
|
||||
type="text"
|
||||
id="title"
|
||||
class="form-control"
|
||||
placeholder={trl("Enter title")}
|
||||
prop:value={move || appearance.get().title.unwrap_or_default()}
|
||||
name="appearance[title]"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</DataForm>
|
||||
}
|
||||
}
|
||||
|
||||
#[component]
|
||||
fn edit_text(opener: DialogOpener, appearance: ReadSignal<Appearance>) -> impl IntoView {
|
||||
let update = create_server_action::<UpdateAppearance>();
|
||||
view! {
|
||||
<DataForm opener=opener action=update title="Update text">
|
||||
<input type="hidden" prop:value={move || appearance.get().title.unwrap_or_default()} name="appearance[title]" />
|
||||
<input type="hidden" prop:value={move || appearance.get().id()} name="appearance[id]"/>
|
||||
<div class="row">
|
||||
<div class="col mb-3">
|
||||
<label for="text" class="form-label">{trl("Text")}</label>
|
||||
<textarea
|
||||
id="title"
|
||||
class="form-control"
|
||||
prop:value={move || appearance.get().text.unwrap_or_default()}
|
||||
name="appearance[text]"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</DataForm>
|
||||
}
|
||||
}
|
||||
|
||||
#[component]
|
||||
fn delete_banner(opener: DialogOpener) -> impl IntoView {
|
||||
let delete = create_server_action::<DeleteBanner>();
|
||||
view! {
|
||||
<QuestionDialog opener=opener action=delete title="Delete banner">
|
||||
<div>{trl("Are you sure you want to delete banner?")}</div>
|
||||
</QuestionDialog>
|
||||
}
|
||||
}
|
||||
|
||||
#[component]
|
||||
pub fn appearance() -> impl IntoView {
|
||||
let title_edit = DialogOpener::new();
|
||||
let text_edit = DialogOpener::new();
|
||||
let del_dialog = DialogOpener::new();
|
||||
let appearance = create_resource(move || title_edit.visible() || text_edit.visible() || del_dialog.visible(), |_| get_appearance());
|
||||
let app_edit = create_rw_signal(Appearance::default());
|
||||
view! {
|
||||
<EditTitle opener=title_edit appearance=app_edit.read_only()/>
|
||||
<EditText opener=text_edit appearance=app_edit.read_only()/>
|
||||
<DeleteBanner opener=del_dialog/>
|
||||
<h1>{trl("Appearance settings")}</h1>
|
||||
<div class="row mb-3">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">{trl("Top banner")}</h5>
|
||||
<form method="post" action="/upload" enctype="multipart/form-data">
|
||||
<label for="banner_file">{trl("Banner file")}</label>
|
||||
<input id="banner_file" type="file" class="form-control" name="file_to_upload"/>
|
||||
<button type="submit" class="btn btn-primary">
|
||||
{trl("Upload")}
|
||||
</button>
|
||||
</form><br/>
|
||||
<Transition fallback=move || view! {<p>{trl("Loading...")}</p> }>
|
||||
{
|
||||
appearance.get().map(|a| match a {
|
||||
Ok(a) => {
|
||||
app_edit.set(a.clone());
|
||||
let app = a.clone();
|
||||
view! {
|
||||
<div>
|
||||
<Show when=move || a.clone().banner.is_some()>
|
||||
<div class="header_banner">
|
||||
<h1 class="header_banner">{app.title.clone().unwrap_or_default()}</h1>
|
||||
</div>
|
||||
</Show>
|
||||
<div>
|
||||
<button class="btn btn-info" on:click=move |_| title_edit.show()>
|
||||
<i class="bx bx-edit-alt me-1"></i> {trl("Edit title")}</button>
|
||||
<button class="btn btn-danger" on:click=move |_| del_dialog.show()>
|
||||
{trl("Delete")}
|
||||
</button>
|
||||
<br/><br/>
|
||||
<div>
|
||||
{app.text.unwrap_or("<< TEXT >>".to_string())}
|
||||
</div>
|
||||
<a class="dropdown-item" href="javascript:void(0);" on:click=move |_| text_edit.show()>
|
||||
<i class="bx bx-edit-alt me-1"></i> {trl("Edit text")}</a>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
Err(e) => {view! {<div><p>{trl("Error loading data")}</p>
|
||||
<p>{e.to_string()}</p></div>
|
||||
}}
|
||||
})
|
||||
}
|
||||
</Transition>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
@@ -21,4 +21,5 @@ pub mod mail_settings;
|
||||
mod mail_view;
|
||||
pub mod all_reservations;
|
||||
pub mod customers;
|
||||
pub mod appearance_settings;
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ use leptos::*;
|
||||
use leptos_captcha::{Captcha, pow_dispatch};
|
||||
use leptos_router::*;
|
||||
use rust_decimal::Decimal;
|
||||
use crate::backend::appearance::get_appearance;
|
||||
use crate::backend::customer::get_remembered;
|
||||
use crate::backend::data::{ApiResponse, Customer, DayHour, Reservation, ResProperty, SlotType, TmCheck};
|
||||
use crate::backend::reservation::{CreateReservation, get_public_form_data, is_reserved};
|
||||
@@ -103,6 +104,7 @@ pub fn Public() -> impl IntoView {
|
||||
let is_pending = create_rw_signal(None);
|
||||
let active_str = create_rw_signal("true".to_string());
|
||||
let get_customer = create_blocking_resource(||(), move |_| get_remembered());
|
||||
let appearance = create_blocking_resource(||(), move |_| get_appearance());
|
||||
let customer = create_rw_signal(Customer::default());
|
||||
|
||||
create_effect(move |_| {
|
||||
@@ -117,6 +119,34 @@ pub fn Public() -> impl IntoView {
|
||||
price=price.write_only()
|
||||
slots=slots.write_only()
|
||||
captcha_state=is_pending.read_only()/>
|
||||
|
||||
<Transition fallback=move || view! {<p>{trl("Loading...")}</p> }>
|
||||
{
|
||||
appearance.get().map(|a| match a {
|
||||
Ok(a) => {
|
||||
let app = a.clone();
|
||||
view! {
|
||||
<div>
|
||||
<Show when=move || a.clone().banner.is_some()>
|
||||
<div class="header_banner">
|
||||
<h1 class="header_banner">{app.title.clone().unwrap_or_default()}</h1>
|
||||
</div>
|
||||
</Show>
|
||||
<div>
|
||||
<div>
|
||||
{app.text.unwrap_or("".to_string())}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
},
|
||||
Err(e) => {view! {<div><p>{trl("Error loading data")}</p>
|
||||
<p>{e.to_string()}</p></div>
|
||||
}}
|
||||
})
|
||||
}
|
||||
</Transition>
|
||||
|
||||
<div class="card-body">
|
||||
<ActionForm
|
||||
on:submit=move |ev| {
|
||||
|
||||
Reference in New Issue
Block a user