freezone/platform/src/components/entities/company_registration/step_one.rs
2025-06-27 04:13:31 +02:00

277 lines
14 KiB
Rust

use yew::prelude::*;
use web_sys::HtmlInputElement;
use crate::models::*;
#[derive(Properties, PartialEq)]
pub struct StepOneProps {
pub form_data: CompanyFormData,
pub on_form_update: Callback<CompanyFormData>,
}
pub enum StepOneMsg {
UpdateCompanyName(String),
UpdateDescription(String),
UpdateEmail(String),
UpdateIndustry(String),
SelectCompanyType(CompanyType),
}
pub struct StepOne {
form_data: CompanyFormData,
}
impl Component for StepOne {
type Message = StepOneMsg;
type Properties = StepOneProps;
fn create(ctx: &Context<Self>) -> Self {
Self {
form_data: ctx.props().form_data.clone(),
}
}
fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
match msg {
StepOneMsg::UpdateCompanyName(value) => {
self.form_data.company_name = value;
}
StepOneMsg::UpdateDescription(value) => {
self.form_data.company_purpose = Some(value);
}
StepOneMsg::UpdateEmail(value) => {
self.form_data.company_email = value;
}
StepOneMsg::UpdateIndustry(value) => {
self.form_data.company_industry = if value.is_empty() { None } else { Some(value) };
}
StepOneMsg::SelectCompanyType(company_type) => {
self.form_data.company_type = company_type;
}
}
// Notify parent of form data changes
ctx.props().on_form_update.emit(self.form_data.clone());
true
}
fn changed(&mut self, ctx: &Context<Self>, _old_props: &Self::Properties) -> bool {
self.form_data = ctx.props().form_data.clone();
true
}
fn view(&self, ctx: &Context<Self>) -> Html {
let link = ctx.link();
html! {
<div class="step-content">
<div class="row">
<div class="col-md-6">
<div class="row mb-3">
<label for="companyName" class="col-sm-4 col-form-label" data-bs-toggle="tooltip" data-bs-placement="top" title="The official name of your company or legal entity">
{"Company Name"} <span class="text-danger">{"*"}</span>
</label>
<div class="col-sm-8">
<input
type="text"
class="form-control"
id="companyName"
placeholder="Enter company name"
value={self.form_data.company_name.clone()}
oninput={link.callback(|e: InputEvent| {
let input: HtmlInputElement = e.target_unchecked_into();
StepOneMsg::UpdateCompanyName(input.value())
})}
required=true
data-bs-toggle="tooltip"
data-bs-placement="top"
title="The official name of your company or legal entity"
/>
</div>
</div>
<div class="row mb-3">
<label for="email" class="col-sm-4 col-form-label" data-bs-toggle="tooltip" data-bs-placement="top" title="Primary contact email for the company">
{"Email Address"} <span class="text-danger">{"*"}</span>
</label>
<div class="col-sm-8">
<input
type="email"
class="form-control"
id="email"
placeholder="company@example.com"
value={self.form_data.company_email.clone()}
oninput={link.callback(|e: InputEvent| {
let input: HtmlInputElement = e.target_unchecked_into();
StepOneMsg::UpdateEmail(input.value())
})}
required=true
data-bs-toggle="tooltip"
data-bs-placement="top"
title="Primary contact email for the company"
/>
</div>
</div>
<div class="row mb-3">
<label for="industry" class="col-sm-4 col-form-label" data-bs-toggle="tooltip" data-bs-placement="top" title="Primary industry sector (optional)">
{"Industry"}
</label>
<div class="col-sm-8">
<select
class="form-select"
id="industry"
value={self.form_data.company_industry.clone().unwrap_or_default()}
onchange={link.callback(|e: Event| {
let input: HtmlInputElement = e.target_unchecked_into();
StepOneMsg::UpdateIndustry(input.value())
})}
data-bs-toggle="tooltip"
data-bs-placement="top"
title="Primary industry sector (optional)"
>
<option value="">{"Select industry"}</option>
<option value="Technology">{"Technology"}</option>
<option value="Finance">{"Finance"}</option>
<option value="Healthcare">{"Healthcare"}</option>
<option value="Education">{"Education"}</option>
<option value="Retail">{"Retail"}</option>
<option value="Manufacturing">{"Manufacturing"}</option>
<option value="Real Estate">{"Real Estate"}</option>
<option value="Consulting">{"Consulting"}</option>
<option value="Media">{"Media"}</option>
<option value="Transportation">{"Transportation"}</option>
<option value="Energy">{"Energy"}</option>
<option value="Agriculture">{"Agriculture"}</option>
<option value="Other">{"Other"}</option>
</select>
</div>
</div>
</div>
<div class="col-md-6">
<div class="mb-3">
<textarea
class="form-control"
id="description"
rows="5"
placeholder="Describe your company's business activities and purpose..."
value={self.form_data.company_purpose.clone().unwrap_or_default()}
oninput={link.callback(|e: InputEvent| {
let input: HtmlInputElement = e.target_unchecked_into();
StepOneMsg::UpdateDescription(input.value())
})}
data-bs-toggle="tooltip"
data-bs-placement="top"
title="Brief description of your company's business activities and purpose"
></textarea>
</div>
</div>
</div>
// Company Type Selection
<div class="row mt-4">
<div class="col-12">
<div class="row">
{self.render_company_type_option(ctx, CompanyType::SingleFZC,
"Single FZC",
"Perfect for individual entrepreneurs and solo ventures. Simple structure with one shareholder.",
vec!["1 shareholder only", "Cannot issue digital assets", "Can hold external shares", "Connect to bank", "Participate in ecosystem"],
"$20 setup + $20/month")}
{self.render_company_type_option(ctx, CompanyType::StartupFZC,
"Startup FZC",
"Ideal for small teams and early-stage startups. Allows multiple shareholders and digital asset issuance.",
vec!["Up to 5 shareholders", "Can issue digital assets", "Hold external shares", "Connect to bank", "Full ecosystem access"],
"$50 setup + $50/month")}
{self.render_company_type_option(ctx, CompanyType::GrowthFZC,
"Growth FZC",
"Designed for growing businesses that need more flexibility and can hold physical assets.",
vec!["Up to 20 shareholders", "Can issue digital assets", "Hold external shares", "Connect to bank", "Hold physical assets"],
"$100 setup + $100/month")}
{self.render_company_type_option(ctx, CompanyType::GlobalFZC,
"Global FZC",
"Enterprise-level structure for large organizations with unlimited shareholders and full capabilities.",
vec!["Unlimited shareholders", "Can issue digital assets", "Hold external shares", "Connect to bank", "Hold physical assets"],
"$2000 setup + $200/month")}
{self.render_company_type_option(ctx, CompanyType::CooperativeFZC,
"Cooperative FZC",
"Democratic organization structure with collective decision-making and equitable distribution.",
vec!["Unlimited members", "Democratic governance", "Collective decision-making", "Equitable distribution", "Full capabilities"],
"$2000 setup + $200/month")}
</div>
</div>
</div>
</div>
}
}
}
impl StepOne {
fn render_company_type_option(
&self,
ctx: &Context<Self>,
company_type: CompanyType,
title: &str,
description: &str,
benefits: Vec<&str>,
price: &str,
) -> Html {
let link = ctx.link();
let is_selected = self.form_data.company_type == company_type;
let card_class = if is_selected {
"card border-success mb-3 shadow-sm"
} else {
"card border-light mb-3"
};
html! {
<div class="col-xl col-lg-4 col-md-6 mb-3" style="min-width: 220px; max-width: 280px;">
<div class={card_class} style="cursor: pointer;" onclick={link.callback(move |_| StepOneMsg::SelectCompanyType(company_type.clone()))}>
<div class="card-header">
<div class="d-flex align-items-center">
<input
type="radio"
class="form-check-input me-2"
checked={is_selected}
onchange={link.callback(move |_| StepOneMsg::SelectCompanyType(company_type.clone()))}
/>
<h6 class="mb-0">{title}</h6>
</div>
</div>
<div class="card-body">
<p class="card-text text-muted mb-2">{description}</p>
<div class="text-left mb-3">
<span class="badge bg-primary">{price}</span>
</div>
<div class="row">
<div class="col-12">
<h6 class="text-success mb-2">{"Key Features:"}</h6>
<ul class="list-unstyled mb-0">
{for benefits.iter().map(|benefit| {
html! {
<li class="mb-1">
<i class="bi bi-check-circle text-success me-2"></i>{benefit}
</li>
}
})}
</ul>
</div>
</div>
</div>
{if is_selected {
html! {
<div class="card-footer bg-success text-white">
<i class="bi bi-check-circle me-2"></i>{"Selected"}
</div>
}
} else {
html! {}
}}
</div>
</div>
}
}
}