use crate::core::types::{FieldType, FieldValue};
use crate::validation::Validator;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FieldMetadata {
pub name: String,
pub field_type: FieldType,
pub is_required: bool,
pub default_value: Option<FieldValue>,
pub dependencies: Vec<String>,
pub attributes: HashMap<String, String>,
pub validators: Vec<Validator>,
}
impl Default for FieldMetadata {
fn default() -> Self {
Self {
name: String::new(),
field_type: FieldType::Text,
is_required: false,
default_value: None,
dependencies: Vec::new(),
attributes: HashMap::new(),
validators: Vec::new(),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FormSchema {
pub name: String,
pub field_metadata: Vec<FieldMetadata>,
}
impl FormSchema {
pub fn new() -> Self {
Self {
name: String::new(),
field_metadata: Vec::new(),
}
}
pub fn get_field(&self, name: &str) -> Option<&FieldMetadata> {
self.field_metadata.iter().find(|f| f.name == name)
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct FormState<T: Form> {
pub values: T,
pub errors: crate::validation::ValidationErrors,
pub is_dirty: bool,
pub is_submitting: bool,
}
impl<T: Form> FormState<T> {
pub fn new(values: T) -> Self {
Self {
values,
errors: crate::validation::ValidationErrors::new(),
is_dirty: false,
is_submitting: false,
}
}
pub fn with_errors(mut self, errors: crate::validation::ValidationErrors) -> Self {
let is_empty = errors.is_empty();
self.errors = errors;
self.is_dirty = !is_empty;
self
}
pub fn with_values(mut self, values: T) -> Self {
self.values = values;
self
}
pub fn mark_dirty(mut self) -> Self {
self.is_dirty = true;
self
}
pub fn mark_submitting(mut self) -> Self {
self.is_submitting = true;
self
}
pub fn mark_not_submitting(mut self) -> Self {
self.is_submitting = false;
self
}
pub fn is_valid(&self) -> bool {
self.errors.is_empty()
}
pub fn reset(mut self) -> Self {
self.values = T::default_values();
self.errors = crate::validation::ValidationErrors::new();
self.is_dirty = false;
self.is_submitting = false;
self
}
}
pub trait Form: for<'de> Deserialize<'de> + Serialize + Clone + 'static {
fn field_metadata() -> Vec<FieldMetadata>;
fn validate(&self) -> Result<(), crate::validation::ValidationErrors>;
fn default_values() -> Self;
fn schema() -> FormSchema {
FormSchema {
name: std::any::type_name::<Self>()
.split("::")
.last()
.unwrap_or("unknown")
.to_string(),
field_metadata: Self::field_metadata(),
}
}
fn get_form_data(&self) -> HashMap<String, FieldValue> {
let mut data = HashMap::new();
let metadata = Self::field_metadata();
for field_meta in metadata {
let field_name = field_meta.name.clone();
let field_value = self.get_field_value(&field_name);
data.insert(field_name, field_value);
}
data
}
fn get_field_value(&self, _field_name: &str) -> FieldValue {
FieldValue::String(String::new())
}
fn set_field_value(&mut self, _field_name: &str, _value: FieldValue) {
}
}
pub trait FormFieldComponent {
fn field_name(&self) -> &str;
fn field_type(&self) -> FieldType;
fn is_required(&self) -> bool;
}
pub trait FormSubmitHandler<T: Form> {
fn handle_submit(&self, form: &T) -> Result<(), String>;
}
pub trait FormValidator<T: Form> {
fn validate_field(&self, form: &T, field_name: &str) -> Result<(), String>;
fn validate_form(&self, form: &T) -> Result<(), crate::validation::ValidationErrors>;
fn get_field_validators(&self, field_name: &str) -> Vec<Validator>;
}
pub trait FormPersistence<T: Form> {
fn save(&self, form: &T) -> Result<(), String>;
fn load(&self) -> Result<Option<T>, String>;
fn clear(&self) -> Result<(), String>;
fn exists(&self) -> bool;
}
pub trait FormAnalytics<T: Form> {
fn track_view(&self, form_name: &str);
fn track_field_interaction(&self, form_name: &str, field_name: &str, action: &str);
fn track_submission(&self, form_name: &str, success: bool);
fn track_validation_errors(
&self,
form_name: &str,
errors: &crate::validation::ValidationErrors,
);
}