PR with too many features #58

Merged
BobdaFett merged 56 commits from feat/admin-page into main 2026-02-10 14:31:49 +00:00
3 changed files with 53 additions and 40 deletions
Showing only changes of commit b11ad5ffff - Show all commits

No files matched your search

+51 -39
View File
@@ -3,7 +3,7 @@ use leptos::ev::{Event, Targeted};
use leptos::prelude::*; use leptos::prelude::*;
use leptos::web_sys::HtmlSelectElement; use leptos::web_sys::HtmlSelectElement;
use std::collections::HashMap; use std::collections::HashMap;
use leptos::logging::{log, warn}; use leptos::logging::log;
use crate::components::{use_validation_context, InputState, ValidationState}; use crate::components::{use_validation_context, InputState, ValidationState};
fn validate(required: bool, value: String) -> ValidationState { fn validate(required: bool, value: String) -> ValidationState {
@@ -29,27 +29,28 @@ pub fn Select(
) -> impl IntoView { ) -> impl IntoView {
//#region Value Logic //#region Value Logic
let default_raw_value = data_map.get_untracked() let value = Memo::new(move |_| {
.get(&data_member.get_untracked()) data_map.with(|map| {
.cloned() map.get(&data_member.get_untracked())
.unwrap_or_default() .and_then(|v| v.as_string().ok().flatten())
.as_string().unwrap_or_default().unwrap_or_default(); .unwrap_or_default()
})
let raw_value = RwSignal::new(default_raw_value); });
Effect::new(move || { Effect::new(move || {
data_map.update(|map| { log!("Current select value: {}", value.get());
map.insert(data_member.get(), ValueType::String(Some(raw_value.get())));
});
}); });
// Effect::new(move || {
// data_map.update(|map| {
// map.insert(data_member.get(), ValueType::String(Some(raw_value.get())));
// });
// });
//#endregion //#endregion
//#region Validation Logic //#region Validation Logic
let error = RwSignal::new( let error = Memo::new(move |_| validate(required.get(), value.get()));
validate(required.get_untracked(), raw_value.get_untracked())
);
warn!("Current error state: {:?}", error.get_untracked());
let dirty = RwSignal::new(false); let dirty = RwSignal::new(false);
let show_errors = Signal::derive(move || dirty.get() && matches!(error.get(), ValidationState::Invalid(_))); let show_errors = Signal::derive(move || dirty.get() && matches!(error.get(), ValidationState::Invalid(_)));
@@ -71,19 +72,27 @@ pub fn Select(
let on_change = move |e: Targeted<Event, HtmlSelectElement>| { let on_change = move |e: Targeted<Event, HtmlSelectElement>| {
let value = e.target().value(); let value = e.target().value();
log!("Found value {}", value);
raw_value.set(value.clone());
error.set(validate(required.get(), raw_value.get()));
dirty.set(true); dirty.set(true);
data_map.update(|map| { data_map.update(|map| {
if let Some(val) = map.get_mut(&data_member.get()) { map.insert(data_member.get(), ValueType::String(Some(value)));
*val = ValueType::String(Some(value.clone()));
} else {
map.insert(data_member.get(), ValueType::String(Some(value)));
}
}); });
}; };
// let on_change = move |e: Targeted<Event, HtmlSelectElement>| {
// let value = e.target().value();
// log!("Found value {}", value);
// raw_value.set(value.clone());
// error.set(validate(required.get(), raw_value.get()));
// dirty.set(true);
// data_map.update(|map| {
// if let Some(val) = map.get_mut(&data_member.get()) {
// *val = ValueType::String(Some(value.clone()));
// } else {
// map.insert(data_member.get(), ValueType::String(Some(value)));
// }
// });
// };
//#endregion //#endregion
view! { view! {
@@ -96,28 +105,31 @@ pub fn Select(
transition-border duration-150 transition-border duration-150
border-red-700 bg-transparent border-red-700 bg-transparent
disabled:border-gray-600 disabled:pointer-events-none disabled:bg-gray-600/33" disabled:border-gray-600 disabled:pointer-events-none disabled:bg-gray-600/33"
prop:value=move || value.get()
on:change:target=on_change on:change:target=on_change
disabled=disabled disabled=disabled
> >
// This closure handles the display of the options. // This closure handles the display of the options.
<option <option value="" disabled hidden selected=move || value.get().is_empty()>
value=""
disabled
hidden
selected=move || raw_value.get().is_empty()
>
"Select one..." "Select one..."
</option> </option>
{move || {
value_list // We can reasonably assume that the options in the list will be distinct.
.get() <For
.iter() each=move || value_list.get()
.map(move |value| { key=|value| value.clone()
let display = value.to_owned(); children=move |val| view! { <option value=val>{val.clone()}</option> }
view! { <option value=display>{display.clone()}</option> } />
}) // {move || {
.collect::<Vec<_>>() // value_list
}} // .get()
// .iter()
// .map(move |value| {
// let display = value.to_owned();
// view! { <option value=display>{display.clone()}</option> }
// })
// .collect::<Vec<_>>()
// }}
</select> </select>
</label> </label>
</div> </div>
+1 -1
View File
@@ -194,7 +194,7 @@ fn Entry(
) -> impl IntoView { ) -> impl IntoView {
view! { view! {
<div class="flex flex-col flex-1 p-2 rounded-sm transition-shadow shadow-sm hover:shadow-lg/30"> <div class="flex flex-col flex-1 p-2 rounded-sm transition-shadow shadow-sm hover:shadow-lg/30">
{schema {move || schema
.get() .get()
.iter() .iter()
.map(|input_type| .map(|input_type|
+1
View File
@@ -5,6 +5,7 @@ use crate::components::{ActionButton, Header};
/// Indicates the current state of an input. /// Indicates the current state of an input.
#[derive(Default, Debug, Clone)] #[derive(Default, Debug, Clone)]
#[derive(PartialEq)]
pub enum ValidationState { pub enum ValidationState {
/// A valid input. /// A valid input.
#[default] #[default]