use crate::core::types::{FieldValue, FieldError, FieldType, ValidatorConfig, FormError};
use crate::validation::ValidationErrors;
use std::collections::HashMap;
pub trait Form: Clone + serde::Serialize + for<'de> serde::Deserialize<'de> + Send + Sync + 'static {
fn field_metadata() -> Vec<FieldMetadata> where Self: Sized;
fn validate(&self) -> Result<(), ValidationErrors>;
fn get_field(&self, _name: &str) -> Option<FieldValue> {
None }
fn set_field(&mut self, _name: &str, _value: FieldValue) -> Result<(), FieldError> {
Err(FieldError::new(
_name.to_string(),
"Field not found or not settable".to_string(),
))
}
fn default_values() -> Self where Self: Sized;
fn schema() -> FormSchema where Self: Sized;
}
#[derive(Debug, Clone)]
pub struct FormState<T: Form> {
pub values: T,
pub errors: ValidationErrors,
pub is_dirty: bool,
pub is_submitting: bool,
pub is_valid: bool,
pub touched_fields: std::collections::HashSet<String>,
}
impl<T: Form> FormState<T> {
pub fn new(values: T) -> Self {
Self {
values,
errors: ValidationErrors::new(),
is_dirty: false,
is_submitting: false,
is_valid: true,
touched_fields: std::collections::HashSet::new(),
}
}
pub fn with_errors(mut self, errors: ValidationErrors) -> Self {
let is_empty = errors.is_empty();
self.errors = errors;
self.is_valid = is_empty;
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_touched(mut self, field_name: String) -> Self {
self.touched_fields.insert(field_name);
self
}
}
#[derive(Debug, Clone)]
pub struct FieldMetadata {
pub name: String,
pub field_type: FieldType,
pub validators: Vec<ValidatorConfig>,
pub is_required: bool,
pub default_value: Option<FieldValue>,
pub dependencies: Vec<String>,
pub attributes: HashMap<String, String>,
}
#[derive(Debug, Clone)]
pub struct FormSchema {
pub fields: Vec<FieldMetadata>,
pub form_validators: Vec<ValidatorConfig>,
pub attributes: HashMap<String, String>,
}
impl FormSchema {
pub fn new() -> Self {
Self {
fields: Vec::new(),
form_validators: Vec::new(),
attributes: HashMap::new(),
}
}
pub fn add_field(&mut self, field: FieldMetadata) {
self.fields.push(field);
}
pub fn get_field(&self, name: &str) -> Option<&FieldMetadata> {
self.fields.iter().find(|f| f.name == name)
}
pub fn required_fields(&self) -> Vec<&FieldMetadata> {
self.fields.iter().filter(|f| f.is_required).collect()
}
}
pub trait FormFieldComponent {
fn field_name(&self) -> &str;
fn field_value(&self) -> Option<FieldValue>;
fn set_field_value(&self, value: FieldValue);
fn field_errors(&self) -> Vec<String>;
fn is_valid(&self) -> bool;
fn is_dirty(&self) -> bool;
fn reset(&self);
}
pub trait FormSubmitHandler<T: Form> {
fn handle_submit(&self, form: &T) -> Result<(), FormError>;
}
pub trait FormValidator<T: Form> {
fn validate_field(&self, form: &T, field_name: &str) -> Result<(), FieldError>;
fn validate_form(&self, form: &T) -> Result<(), ValidationErrors>;
fn get_field_validators(&self, field_name: &str) -> Vec<ValidatorConfig>;
}
pub trait FormStateManager<T: Form> {
fn get_state(&self) -> FormState<T>;
fn update_state(&self, state: FormState<T>);
fn subscribe(&self, callback: Box<dyn Fn(FormState<T>) + Send + Sync + 'static>);
fn unsubscribe(&self, id: SubscriptionId);
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct SubscriptionId(usize);
impl SubscriptionId {
pub fn new(id: usize) -> Self {
Self(id)
}
}
pub trait FormPersistence<T: Form> {
fn save(&self, form: &T) -> Result<(), FormError>;
fn load(&self) -> Result<Option<T>, FormError>;
fn clear(&self) -> Result<(), FormError>;
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: &ValidationErrors);
}