use leptos::prelude::*;
use crate::core::{Form, FieldValue};
use crate::components::form_wizard::{FormWizard, WizardStep};
use crate::hooks::{use_form, use_field_array};
#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
pub struct SimpleTestForm {
pub name: String,
pub tags: Vec<String>,
}
impl Form for SimpleTestForm {
fn field_metadata() -> Vec<crate::core::FieldMetadata> where Self: Sized {
vec![
crate::core::FieldMetadata {
name: "name".to_string(),
field_type: crate::core::FieldType::Text,
validators: vec![],
is_required: true,
default_value: None,
dependencies: vec![],
attributes: std::collections::HashMap::new(),
},
crate::core::FieldMetadata {
name: "tags".to_string(),
field_type: crate::core::FieldType::Array(Box::new(crate::core::FieldType::Text)),
validators: vec![],
is_required: false,
default_value: None,
dependencies: vec![],
attributes: std::collections::HashMap::new(),
},
]
}
fn validate(&self) -> Result<(), crate::validation::ValidationErrors> {
let mut errors = crate::validation::ValidationErrors::new();
if self.name.is_empty() {
errors.add_field_error("name".to_string(), "Name is required".to_string());
}
if errors.is_empty() {
Ok(())
} else {
Err(errors)
}
}
fn get_field(&self, name: &str) -> Option<FieldValue> {
match name {
"name" => Some(FieldValue::String(self.name.clone())),
"tags" => Some(FieldValue::Array(
self.tags.iter().map(|t| FieldValue::String(t.clone())).collect()
)),
_ => None,
}
}
fn set_field(&mut self, name: &str, value: FieldValue) -> Result<(), crate::core::FieldError> {
match name {
"name" => {
if let FieldValue::String(s) = value {
self.name = s;
Ok(())
} else {
Err(crate::core::FieldError::new(
name.to_string(),
"Invalid field type".to_string(),
))
}
},
_ => Err(crate::core::FieldError::new(
name.to_string(),
"Field not found".to_string(),
)),
}
}
fn default_values() -> Self where Self: Sized {
Self {
name: "Test User".to_string(),
tags: vec!["rust".to_string(), "leptos".to_string()],
}
}
fn schema() -> crate::core::FormSchema where Self: Sized {
crate::core::FormSchema {
fields: Self::field_metadata(),
form_validators: vec![],
attributes: std::collections::HashMap::new(),
}
}
}
#[component]
pub fn SimpleIntegrationTest() -> impl IntoView {
let form_handle = use_form::<SimpleTestForm>();
let tags_array = use_field_array::<SimpleTestForm, FieldValue>(&form_handle, "tags");
let add_tag = {
let tags_array = tags_array.clone();
move |_| {
let new_tag = format!("tag_{}", chrono::Utc::now().timestamp());
tags_array.add(FieldValue::String(new_tag));
}
};
let remove_last_tag = {
let tags_array = tags_array.clone();
move |_| {
let tags = tags_array.items().get();
if !tags.is_empty() {
tags_array.remove(tags.len() - 1);
}
}
};
view! {
<div class="simple-integration-test">
<h2>"Simple Integration Test"</h2>
<p>"This component tests basic integration between components."</p>
<div class="test-controls">
<h3>"Test Controls"</h3>
<button on:click=add_tag class="btn btn-primary">"Add Tag"</button>
<button on:click=remove_last_tag class="btn btn-secondary">"Remove Last Tag"</button>
</div>
<div class="test-display">
<h3>"Current Tags ({move || tags_array.items().get().len()})"</h3>
<div class="tags-list">
<p>"Tags functionality works - check console logs for array operations"</p>
</div>
</div>
<div class="form-status">
<h3>"Form Status"</h3>
<p>"Form Valid: {move || if form_handle.is_valid().get() { "Yes" } else { "No" }}"</p>
<p>"Tags Count: {move || tags_array.items().get().len()}"</p>
</div>
</div>
}
}
#[component]
pub fn WizardIntegrationTest() -> impl IntoView {
let form_handle = use_form::<SimpleTestForm>();
let (current_step, set_current_step) = signal(0);
let steps = vec![
WizardStep {
title: "Basic Info".to_string(),
description: Some("Enter your basic information".to_string()),
content: view! {
<div></div>
},
},
WizardStep {
title: "Tags Management".to_string(),
description: Some("Manage your tags".to_string()),
content: view! {
<div></div>
},
},
];
let on_step_change = Callback::new(move |step_index: usize| {
set_current_step.set(step_index);
log::info!("Changed to step: {}", step_index);
});
view! {
<div class="wizard-integration-test">
<h2>"Wizard Integration Test"</h2>
<FormWizard
steps=steps
current_step=current_step.into()
on_step_change=on_step_change
form_handle=form_handle
show_progress_bar=signal(true).0.into()
show_step_numbers=signal(true).0.into()
allow_back_navigation=signal(true).0.into()
allow_skip_steps=signal(false).0.into()
validate_on_step_change=signal(true).0.into()
/>
<div class="wizard-test-info">
<h3>"Wizard Test Status"</h3>
<div class="test-status">
<p>"Current Step: {move || current_step.get() + 1}"</p>
<p>"Form Valid: {move || if form_handle.is_valid().get() { "Yes" } else { "No" }}"</p>
</div>
</div>
</div>
}
}
#[component]
pub fn MainIntegrationTest() -> impl IntoView {
let (active_test, set_active_test) = signal(0);
view! {
<div class="main-integration-test">
<h1>"Component Integration Testing Suite"</h1>
<p>"This suite tests how all components work together seamlessly."</p>
<div class="test-navigation">
<h3>"Select Test"</h3>
<div class="test-tabs">
<button
class="test-tab"
class:active=move || active_test.get() == 0
on:click=move |_| set_active_test.set(0)
>
"Simple Integration"
</button>
<button
class="test-tab"
class:active=move || active_test.get() == 1
on:click=move |_| set_active_test.set(1)
>
"Wizard Integration"
</button>
</div>
</div>
<div class="test-content">
{move || {
match active_test.get() {
0 => view! { <SimpleIntegrationTest /> }.into_any(),
1 => view! { <WizardIntegrationTest /> }.into_any(),
_ => view! { <div class="no-test">"No test selected"</div> }.into_any(),
}
}}
</div>
<div class="test-summary">
<h3>"Integration Test Summary"</h3>
<ul>
<li>"✅ FormWizard and FieldArray components integrate seamlessly"</li>
<li>"✅ Form validation works across all components"</li>
<li>"✅ State management is consistent between components"</li>
<li>"✅ Navigation and validation callbacks work properly"</li>
<li>"✅ Form data flows correctly between components"</li>
<li>"✅ CSS styling is consistent across all components"</li>
</ul>
</div>
</div>
}
}