freezone/platform/src/components/accounting/financial_reports_tab.rs
2025-06-30 17:01:40 +02:00

261 lines
14 KiB
Rust

use yew::prelude::*;
use web_sys::HtmlInputElement;
use wasm_bindgen::JsCast;
use crate::components::accounting::models::*;
#[derive(Properties, PartialEq)]
pub struct FinancialReportsTabProps {
pub state: UseStateHandle<AccountingState>,
}
#[function_component(FinancialReportsTab)]
pub fn financial_reports_tab(props: &FinancialReportsTabProps) -> Html {
let state = &props.state;
let show_report_modal = use_state(|| false);
let report_type = use_state(|| ReportType::ProfitLoss);
let start_date = use_state(|| "".to_string());
let end_date = use_state(|| "".to_string());
let on_generate_report = {
let state = state.clone();
let show_report_modal = show_report_modal.clone();
let report_type = report_type.clone();
let start_date = start_date.clone();
let end_date = end_date.clone();
Callback::from(move |_| {
if start_date.is_empty() || end_date.is_empty() {
web_sys::window()
.unwrap()
.alert_with_message("Please select both start and end dates")
.unwrap();
return;
}
let new_report = FinancialReport {
id: state.financial_reports.len() + 1,
report_type: (*report_type).clone(),
period_start: (*start_date).clone(),
period_end: (*end_date).clone(),
generated_date: js_sys::Date::new_0().to_iso_string().as_string().unwrap()[..10].to_string(),
status: "Generated".to_string(),
};
let mut new_state = (*state).clone();
new_state.financial_reports.push(new_report);
state.set(new_state);
show_report_modal.set(false);
})
};
let on_export_report = {
Callback::from(move |report_id: usize| {
// Create CSV content for the report
let csv_content = format!(
"Financial Report Export\nReport ID: {}\nGenerated: {}\n\nThis is a placeholder for the actual report data.",
report_id,
js_sys::Date::new_0().to_iso_string().as_string().unwrap()
);
// Create and download the file
let blob = web_sys::Blob::new_with_str_sequence(&js_sys::Array::of1(&csv_content.into())).unwrap();
let url = web_sys::Url::create_object_url_with_blob(&blob).unwrap();
let document = web_sys::window().unwrap().document().unwrap();
let a = document.create_element("a").unwrap();
a.set_attribute("href", &url).unwrap();
a.set_attribute("download", &format!("financial_report_{}.csv", report_id)).unwrap();
a.dyn_ref::<web_sys::HtmlElement>().unwrap().click();
web_sys::Url::revoke_object_url(&url).unwrap();
})
};
html! {
<div class="animate-fade-in-up">
<div class="d-flex justify-content-between align-items-center mb-4">
<h4 class="mb-0">{"Financial Reports"}</h4>
<button
class="btn btn-primary"
onclick={
let show_report_modal = show_report_modal.clone();
Callback::from(move |_| show_report_modal.set(true))
}
>
<i class="bi bi-plus-lg me-2"></i>
{"Generate Report"}
</button>
</div>
<div class="card shadow-soft" style="border: none;">
<div class="card-body">
if state.financial_reports.is_empty() {
<div class="text-center py-5">
<i class="bi bi-file-earmark-text display-1 text-muted mb-3"></i>
<h5 class="text-muted">{"No reports generated yet"}</h5>
<p class="text-muted">{"Generate your first financial report to get started"}</p>
</div>
} else {
<div class="table-responsive">
<table class="table table-hover">
<thead class="table-light">
<tr>
<th>{"Report Type"}</th>
<th>{"Period"}</th>
<th>{"Generated"}</th>
<th>{"Status"}</th>
<th>{"Actions"}</th>
</tr>
</thead>
<tbody>
{for state.financial_reports.iter().map(|report| {
let report_id = report.id;
let on_export = on_export_report.clone();
html! {
<tr>
<td>
<span class="badge bg-primary">{format!("{:?}", report.report_type)}</span>
</td>
<td>{format!("{} to {}", report.period_start, report.period_end)}</td>
<td>{&report.generated_date}</td>
<td>
<span class="badge bg-success">{&report.status}</span>
</td>
<td>
<div class="btn-group btn-group-sm">
<button
class="btn btn-outline-primary"
onclick={
Callback::from(move |_| {
web_sys::window()
.unwrap()
.alert_with_message("Report preview feature coming soon!")
.unwrap();
})
}
>
<i class="bi bi-eye"></i>
</button>
<button
class="btn btn-outline-success"
onclick={move |_| on_export.emit(report_id)}
>
<i class="bi bi-download"></i>
</button>
</div>
</td>
</tr>
}
})}
</tbody>
</table>
</div>
}
</div>
</div>
// Report Generation Modal
if *show_report_modal {
<div class="modal show d-block" tabindex="-1" style="background-color: rgba(0,0,0,0.5);">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">{"Generate Financial Report"}</h5>
<button
type="button"
class="btn-close"
onclick={
let show_report_modal = show_report_modal.clone();
Callback::from(move |_| show_report_modal.set(false))
}
></button>
</div>
<div class="modal-body">
<div class="mb-3">
<label class="form-label">{"Report Type"}</label>
<select
class="form-select"
onchange={
let report_type = report_type.clone();
Callback::from(move |e: Event| {
let target = e.target_dyn_into::<HtmlInputElement>().unwrap();
let value = match target.value().as_str() {
"ProfitLoss" => ReportType::ProfitLoss,
"BalanceSheet" => ReportType::BalanceSheet,
"CashFlow" => ReportType::CashFlow,
"TaxSummary" => ReportType::TaxSummary,
_ => ReportType::ProfitLoss,
};
report_type.set(value);
})
}
>
<option value="ProfitLoss">{"Profit & Loss"}</option>
<option value="BalanceSheet">{"Balance Sheet"}</option>
<option value="CashFlow">{"Cash Flow"}</option>
<option value="TaxSummary">{"Tax Summary"}</option>
</select>
</div>
<div class="row">
<div class="col-md-6">
<div class="mb-3">
<label class="form-label">{"Start Date"}</label>
<input
type="date"
class="form-control"
value={(*start_date).clone()}
onchange={
let start_date = start_date.clone();
Callback::from(move |e: Event| {
let target = e.target_dyn_into::<HtmlInputElement>().unwrap();
start_date.set(target.value());
})
}
/>
</div>
</div>
<div class="col-md-6">
<div class="mb-3">
<label class="form-label">{"End Date"}</label>
<input
type="date"
class="form-control"
value={(*end_date).clone()}
onchange={
let end_date = end_date.clone();
Callback::from(move |e: Event| {
let target = e.target_dyn_into::<HtmlInputElement>().unwrap();
end_date.set(target.value());
})
}
/>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button
type="button"
class="btn btn-secondary"
onclick={
let show_report_modal = show_report_modal.clone();
Callback::from(move |_| show_report_modal.set(false))
}
>
{"Cancel"}
</button>
<button
type="button"
class="btn btn-primary"
onclick={on_generate_report}
>
{"Generate Report"}
</button>
</div>
</div>
</div>
</div>
}
</div>
}
}