use yew::prelude::*; use std::collections::HashMap; use crate::routing::ViewContext; use crate::components::ViewComponent; #[derive(Clone, PartialEq)] pub enum ContractStatus { Draft, PendingSignatures, Signed, Active, Expired, Cancelled, } impl ContractStatus { fn to_string(&self) -> &'static str { match self { ContractStatus::Draft => "Draft", ContractStatus::PendingSignatures => "Pending Signatures", ContractStatus::Signed => "Signed", ContractStatus::Active => "Active", ContractStatus::Expired => "Expired", ContractStatus::Cancelled => "Cancelled", } } fn badge_class(&self) -> &'static str { match self { ContractStatus::Draft => "bg-secondary", ContractStatus::PendingSignatures => "bg-warning text-dark", ContractStatus::Signed => "bg-success", ContractStatus::Active => "bg-success", ContractStatus::Expired => "bg-danger", ContractStatus::Cancelled => "bg-dark", } } } #[derive(Clone, PartialEq)] pub struct ContractSigner { pub id: String, pub name: String, pub email: String, pub status: String, // "Pending", "Signed", "Rejected" pub signed_at: Option, pub comments: Option, } #[derive(Clone, PartialEq)] pub struct Contract { pub id: String, pub title: String, pub description: String, pub contract_type: String, pub status: ContractStatus, pub created_by: String, pub created_at: String, pub updated_at: String, pub signers: Vec, pub terms_and_conditions: Option, pub effective_date: Option, pub expiration_date: Option, } impl Contract { fn signed_signers(&self) -> usize { self.signers.iter().filter(|s| s.status == "Signed").count() } fn pending_signers(&self) -> usize { self.signers.iter().filter(|s| s.status == "Pending").count() } } #[derive(Properties, PartialEq)] pub struct ContractsViewProps { pub context: ViewContext, } pub enum ContractsMsg { CreateContract, EditContract(String), DeleteContract(String), ViewContract(String), FilterByStatus(String), FilterByType(String), SearchContracts(String), } pub struct ContractsViewComponent { contracts: Vec, filtered_contracts: Vec, status_filter: String, type_filter: String, search_filter: String, } impl Component for ContractsViewComponent { type Message = ContractsMsg; type Properties = ContractsViewProps; fn create(_ctx: &Context) -> Self { let contracts = Self::get_sample_contracts(); let filtered_contracts = contracts.clone(); Self { contracts, filtered_contracts, status_filter: String::new(), type_filter: String::new(), search_filter: String::new(), } } fn update(&mut self, _ctx: &Context, msg: Self::Message) -> bool { match msg { ContractsMsg::CreateContract => { // Handle create contract navigation true } ContractsMsg::EditContract(id) => { // Handle edit contract navigation true } ContractsMsg::DeleteContract(id) => { // Handle delete contract self.contracts.retain(|c| c.id != id); self.apply_filters(); true } ContractsMsg::ViewContract(id) => { // Handle view contract navigation true } ContractsMsg::FilterByStatus(status) => { self.status_filter = status; self.apply_filters(); true } ContractsMsg::FilterByType(contract_type) => { self.type_filter = contract_type; self.apply_filters(); true } ContractsMsg::SearchContracts(query) => { self.search_filter = query; self.apply_filters(); true } } } fn view(&self, ctx: &Context) -> Html { let context = &ctx.props().context; let (title, description) = match context { ViewContext::Business => ("Legal Contracts", "Manage business agreements and legal documents"), ViewContext::Person => ("Contracts", "Personal contracts and agreements"), }; // Create tabs content let mut tabs = HashMap::new(); // Contracts Tab tabs.insert("Contracts".to_string(), self.render_contracts_tab(ctx)); // Create Contract Tab tabs.insert("Create Contract".to_string(), self.render_create_contract_tab(ctx)); html! { } } } impl ContractsViewComponent { fn get_sample_contracts() -> Vec { vec![ Contract { id: "1".to_string(), title: "Service Agreement - Web Development".to_string(), description: "Development of company website and maintenance".to_string(), contract_type: "Service Agreement".to_string(), status: ContractStatus::PendingSignatures, created_by: "John Smith".to_string(), created_at: "2024-01-15".to_string(), updated_at: "2024-01-16".to_string(), signers: vec![ ContractSigner { id: "s1".to_string(), name: "Alice Johnson".to_string(), email: "alice@example.com".to_string(), status: "Signed".to_string(), signed_at: Some("2024-01-16 10:30".to_string()), comments: Some("Looks good!".to_string()), }, ContractSigner { id: "s2".to_string(), name: "Bob Wilson".to_string(), email: "bob@example.com".to_string(), status: "Pending".to_string(), signed_at: None, comments: None, }, ], terms_and_conditions: Some("# Service Agreement\n\nThis agreement outlines...".to_string()), effective_date: Some("2024-02-01".to_string()), expiration_date: Some("2024-12-31".to_string()), }, Contract { id: "2".to_string(), title: "Non-Disclosure Agreement".to_string(), description: "Confidentiality agreement for project collaboration".to_string(), contract_type: "Non-Disclosure Agreement".to_string(), status: ContractStatus::Signed, created_by: "Sarah Davis".to_string(), created_at: "2024-01-10".to_string(), updated_at: "2024-01-12".to_string(), signers: vec![ ContractSigner { id: "s3".to_string(), name: "Mike Brown".to_string(), email: "mike@example.com".to_string(), status: "Signed".to_string(), signed_at: Some("2024-01-12 14:20".to_string()), comments: None, }, ContractSigner { id: "s4".to_string(), name: "Lisa Green".to_string(), email: "lisa@example.com".to_string(), status: "Signed".to_string(), signed_at: Some("2024-01-12 16:45".to_string()), comments: Some("Agreed to all terms".to_string()), }, ], terms_and_conditions: Some("# Non-Disclosure Agreement\n\nThe parties agree...".to_string()), effective_date: Some("2024-01-12".to_string()), expiration_date: Some("2026-01-12".to_string()), }, Contract { id: "3".to_string(), title: "Employment Contract - Software Engineer".to_string(), description: "Full-time employment agreement".to_string(), contract_type: "Employment Contract".to_string(), status: ContractStatus::Draft, created_by: "HR Department".to_string(), created_at: "2024-01-20".to_string(), updated_at: "2024-01-20".to_string(), signers: vec![], terms_and_conditions: Some("# Employment Contract\n\nPosition: Software Engineer...".to_string()), effective_date: Some("2024-02-15".to_string()), expiration_date: None, }, ] } fn apply_filters(&mut self) { self.filtered_contracts = self.contracts .iter() .filter(|contract| { // Status filter if !self.status_filter.is_empty() && contract.status.to_string() != self.status_filter { return false; } // Type filter if !self.type_filter.is_empty() && contract.contract_type != self.type_filter { return false; } // Search filter if !self.search_filter.is_empty() { let query = self.search_filter.to_lowercase(); if !contract.title.to_lowercase().contains(&query) && !contract.description.to_lowercase().contains(&query) { return false; } } true }) .cloned() .collect(); } fn render_contracts_tab(&self, _ctx: &Context) -> Html { html! {
// Filters Section
{"Filters"}
// Contracts Table
{"Contracts"}
{self.render_contracts_table(_ctx)}
} } fn render_contracts_table(&self, ctx: &Context) -> Html { if self.filtered_contracts.is_empty() { return html! {

{"No contracts found"}

{"Create New Contract"}
}; } html! {
{for self.filtered_contracts.iter().map(|contract| self.render_contract_row(contract, ctx))}
{"Contract Title"} {"Type"} {"Status"} {"Created By"} {"Signers"} {"Created"} {"Updated"} {"Actions"}
} } fn render_contract_row(&self, contract: &Contract, _ctx: &Context) -> Html { html! { {&contract.title} {&contract.contract_type} {contract.status.to_string()} {&contract.created_by} {format!("{}/{}", contract.signed_signers(), contract.signers.len())} {&contract.created_at} {&contract.updated_at}
{if matches!(contract.status, ContractStatus::Draft) { html! { <> } } else { html! {} }}
} } fn render_create_contract_tab(&self, _ctx: &Context) -> Html { html! {
{"Contract Details"}
{"Markdown Support:"}{" You can use markdown formatting including headers (#), lists (-), tables (|), bold (**text**), italic (*text*), links, and more."}
{"Tips"}

{"Creating a new contract is just the first step. After creating the contract, you'll be able to:"}

  • {"Add signers who need to approve the contract"}
  • {"Edit the contract content"}
  • {"Send the contract for signatures"}
  • {"Track the signing progress"}

{"The contract will be in "}{"Draft"}{" status until you send it for signatures."}

{"Contract Templates"}

{"You can use one of our pre-defined templates to get started quickly:"}

} } } #[function_component(ContractsView)] pub fn contracts_view(props: &ContractsViewProps) -> Html { html! { } }