229 lines
11 KiB
Rust
229 lines
11 KiB
Rust
use yew::prelude::*;
|
|
use crate::routing::{AppView, ViewContext};
|
|
|
|
#[derive(Properties, PartialEq)]
|
|
pub struct SidebarProps {
|
|
pub current_view: AppView,
|
|
pub current_context: ViewContext,
|
|
pub is_visible: bool,
|
|
pub on_view_change: Callback<AppView>,
|
|
}
|
|
|
|
#[function_component(Sidebar)]
|
|
pub fn sidebar(props: &SidebarProps) -> Html {
|
|
let current_view = props.current_view.clone();
|
|
let current_context = props.current_context.clone();
|
|
let on_view_change = props.on_view_change.clone();
|
|
|
|
let sidebar_class = if props.is_visible {
|
|
"sidebar shadow-sm border-end d-flex show"
|
|
} else {
|
|
"sidebar shadow-sm border-end d-flex"
|
|
};
|
|
|
|
// All possible navigation items
|
|
let all_nav_items = vec![
|
|
AppView::Home,
|
|
AppView::Administration,
|
|
AppView::PersonAdministration,
|
|
AppView::Accounting,
|
|
AppView::Contracts,
|
|
AppView::Governance,
|
|
AppView::Treasury,
|
|
AppView::Entities,
|
|
];
|
|
|
|
// Filter items based on current context
|
|
let nav_items: Vec<AppView> = all_nav_items
|
|
.into_iter()
|
|
.filter(|view| view.is_available_for_context(¤t_context))
|
|
.collect();
|
|
|
|
html! {
|
|
<div class={sidebar_class} id="sidebar">
|
|
<div class="py-2">
|
|
|
|
// Identity Card - Business/Residence
|
|
<div class="px-3 mb-3">
|
|
{match current_context {
|
|
ViewContext::Business => {
|
|
let business_view = AppView::Business;
|
|
let is_active = business_view == current_view;
|
|
let on_click = {
|
|
let on_view_change = on_view_change.clone();
|
|
Callback::from(move |_: MouseEvent| {
|
|
on_view_change.emit(AppView::Business);
|
|
})
|
|
};
|
|
|
|
html! {
|
|
<div
|
|
class={classes!(
|
|
"card",
|
|
"shadow-sm",
|
|
if is_active { "bg-dark text-white border-0" } else { "bg-white border-dark" },
|
|
"cursor-pointer"
|
|
)}
|
|
onclick={on_click}
|
|
style="cursor: pointer;"
|
|
>
|
|
<div class="card-body p-3">
|
|
<div class="d-flex align-items-center">
|
|
<div class={classes!(
|
|
"rounded-circle",
|
|
"d-flex",
|
|
"align-items-center",
|
|
"justify-content-center",
|
|
"me-3",
|
|
if is_active { "bg-white text-dark" } else { "bg-dark text-white" }
|
|
)} style="width: 40px; height: 40px;">
|
|
<i class="bi bi-building fs-5"></i>
|
|
</div>
|
|
<div class="flex-grow-1">
|
|
<h6 class="mb-0">{"TechCorp Solutions"}</h6>
|
|
<small class={classes!(
|
|
"font-monospace",
|
|
if is_active { "text-white-50" } else { "text-muted" }
|
|
)}>
|
|
{"BIZ-2024-001"}
|
|
</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
}
|
|
},
|
|
ViewContext::Person => {
|
|
let residence_view = AppView::Residence;
|
|
let is_active = residence_view == current_view;
|
|
let on_click = {
|
|
let on_view_change = on_view_change.clone();
|
|
Callback::from(move |_: MouseEvent| {
|
|
on_view_change.emit(AppView::Residence);
|
|
})
|
|
};
|
|
|
|
html! {
|
|
<div
|
|
class={classes!(
|
|
"card",
|
|
"shadow-sm",
|
|
if is_active { "bg-dark text-white border-0" } else { "bg-white border-dark" },
|
|
"cursor-pointer"
|
|
)}
|
|
onclick={on_click}
|
|
style="cursor: pointer;"
|
|
>
|
|
<div class="card-body p-3">
|
|
<div class="d-flex align-items-center">
|
|
<div class={classes!(
|
|
"rounded-circle",
|
|
"d-flex",
|
|
"align-items-center",
|
|
"justify-content-center",
|
|
"me-3",
|
|
if is_active { "bg-white text-dark" } else { "bg-dark text-white" }
|
|
)} style="width: 40px; height: 40px;">
|
|
<i class="bi bi-person fs-5"></i>
|
|
</div>
|
|
<div class="flex-grow-1">
|
|
<h6 class="mb-0">{"Timur Gordon"}</h6>
|
|
<small class={classes!(
|
|
"font-monospace",
|
|
if is_active { "text-white-50" } else { "text-muted" }
|
|
)}>
|
|
{"RES-ZNZ-2024-042"}
|
|
</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
}
|
|
}
|
|
}}
|
|
</div>
|
|
|
|
// Horizontal divider
|
|
<div class="px-3 mb-3">
|
|
<hr class="text-muted" />
|
|
</div>
|
|
|
|
// Navigation items
|
|
<ul class="nav flex-column">
|
|
{for nav_items.iter().map(|view| {
|
|
let is_active = *view == current_view;
|
|
let view_to_emit = view.clone();
|
|
let on_click = {
|
|
let on_view_change = on_view_change.clone();
|
|
Callback::from(move |_: MouseEvent| {
|
|
on_view_change.emit(view_to_emit.clone());
|
|
})
|
|
};
|
|
|
|
html! {
|
|
<li class="nav-item">
|
|
<a
|
|
class={classes!(
|
|
"nav-link",
|
|
"d-flex",
|
|
"align-items-center",
|
|
"ps-3",
|
|
"py-2",
|
|
is_active.then_some("active"),
|
|
is_active.then_some("fw-bold"),
|
|
is_active.then_some("border-start"),
|
|
is_active.then_some("border-4"),
|
|
is_active.then_some("border-primary"),
|
|
)}
|
|
href="#"
|
|
onclick={on_click}
|
|
>
|
|
<i class={classes!("bi", view.get_icon(), "me-2")}></i>
|
|
{view.get_title(¤t_context)}
|
|
</a>
|
|
</li>
|
|
}
|
|
})}
|
|
</ul>
|
|
|
|
// Divider for external applications
|
|
<div class="px-3 my-3">
|
|
<hr class="text-muted" />
|
|
</div>
|
|
|
|
// External Applications
|
|
<div class="px-3">
|
|
// Marketplace Button
|
|
<div class="card border-primary mb-3" style="cursor: pointer;">
|
|
<div class="card-body p-3">
|
|
<div class="d-flex align-items-center">
|
|
<div class="rounded-circle bg-primary text-white d-flex align-items-center justify-content-center me-3" style="width: 35px; height: 35px;">
|
|
<i class="bi bi-shop fs-6"></i>
|
|
</div>
|
|
<div class="flex-grow-1">
|
|
<h6 class="mb-1 text-primary">{"Marketplace"}</h6>
|
|
<small class="text-muted">{"Browse contract templates"}</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
// DeFi Button
|
|
<div class="card border-success" style="cursor: pointer;">
|
|
<div class="card-body p-3">
|
|
<div class="d-flex align-items-center">
|
|
<div class="rounded-circle bg-success text-white d-flex align-items-center justify-content-center me-3" style="width: 35px; height: 35px;">
|
|
<i class="bi bi-currency-exchange fs-6"></i>
|
|
</div>
|
|
<div class="flex-grow-1">
|
|
<h6 class="mb-1 text-success">{"DeFi"}</h6>
|
|
<small class="text-muted">{"Financial tools & escrow"}</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
}
|
|
} |