init projectmycelium

This commit is contained in:
mik-tf
2025-09-01 21:37:01 -04:00
commit b41efb0e99
319 changed files with 128160 additions and 0 deletions

229
src/services/navbar.rs Normal file
View File

@@ -0,0 +1,229 @@
use actix_session::Session;
use serde::{Serialize, Deserialize};
use rust_decimal::Decimal;
use crate::services::{currency::CurrencyService, user_persistence::UserPersistence};
/// Service for handling navbar dropdown data
#[derive(Clone)]
pub struct NavbarService {
currency_service: CurrencyService,
}
/// Data structure for navbar dropdown menu
#[derive(Debug, Serialize, Deserialize)]
pub struct NavbarDropdownData {
pub user_name: Option<String>,
pub user_email: String,
pub wallet_balance: Decimal,
pub wallet_balance_formatted: String,
pub display_currency: String,
pub currency_symbol: String,
pub quick_actions: Vec<QuickAction>,
pub show_topup_button: bool,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct QuickAction {
pub id: String,
pub label: String,
pub url: String,
pub icon: String,
pub badge: Option<String>,
}
/// Builder for NavbarService
#[derive(Default)]
pub struct NavbarServiceBuilder {
currency_service: Option<CurrencyService>,
}
impl NavbarServiceBuilder {
pub fn new() -> Self {
Self::default()
}
pub fn with_currency_service(mut self, service: CurrencyService) -> Self {
self.currency_service = Some(service);
self
}
pub fn build(self) -> Result<NavbarService, String> {
let currency_service = self.currency_service
.unwrap_or_else(|| CurrencyService::builder().build().unwrap());
Ok(NavbarService {
currency_service,
})
}
}
impl NavbarService {
pub fn builder() -> NavbarServiceBuilder {
NavbarServiceBuilder::new()
}
/// Get navbar dropdown data for authenticated user
pub fn get_dropdown_data(&self, session: &Session) -> Result<NavbarDropdownData, String> {
// Get user email from session
let user_email = session.get::<String>("user_email")
.map_err(|e| format!("Failed to get user email from session: {}", e))?
.ok_or("User not authenticated")?;
// Load user persistent data
let persistent_data = UserPersistence::load_user_data(&user_email)
.unwrap_or_else(|| crate::services::user_persistence::UserPersistentData {
user_email: user_email.clone(),
..Default::default()
});
// Get user's preferred display currency
let mut display_currency = self.currency_service.get_user_preferred_currency(session);
// Get currency info for formatting; fall back to USD if invalid
let (currency, effective_currency) = match self.currency_service.get_currency(&display_currency) {
Some(c) => (c, display_currency.clone()),
None => {
let usd = self
.currency_service
.get_currency("USD")
.expect("USD currency must be available");
display_currency = "USD".to_string();
(usd, "USD".to_string())
}
};
// Convert wallet balance to display currency
let wallet_balance_display = if effective_currency == "USD" {
persistent_data.wallet_balance_usd
} else {
self.currency_service.convert_amount(
persistent_data.wallet_balance_usd,
"USD",
&effective_currency,
).unwrap_or(Decimal::ZERO)
};
// Format the balance
let wallet_balance_formatted = currency.format_amount(wallet_balance_display);
// Create quick actions
let quick_actions = vec![
QuickAction {
id: "topup".to_string(),
label: "Top Up Wallet".to_string(),
url: "/wallet?action=topup".to_string(),
icon: "bi-plus-circle".to_string(),
badge: None,
},
QuickAction {
id: "wallet".to_string(),
label: "Wallet".to_string(),
url: "/wallet".to_string(),
icon: "bi-wallet2".to_string(),
badge: None,
},
QuickAction {
id: "settings".to_string(),
label: "Settings".to_string(),
url: "/dashboard/settings".to_string(),
icon: "bi-gear".to_string(),
badge: None,
},
];
Ok(NavbarDropdownData {
user_name: persistent_data.name,
user_email,
wallet_balance: wallet_balance_display,
wallet_balance_formatted,
display_currency: effective_currency.clone(),
currency_symbol: currency.symbol.clone(),
quick_actions,
show_topup_button: true,
})
}
/// Get simplified navbar data for guest users
pub fn get_guest_data() -> NavbarDropdownData {
NavbarDropdownData {
user_name: None,
user_email: String::new(),
wallet_balance: Decimal::ZERO,
wallet_balance_formatted: "Not logged in".to_string(),
display_currency: "USD".to_string(),
currency_symbol: "$".to_string(),
quick_actions: vec![
QuickAction {
id: "login".to_string(),
label: "Login".to_string(),
url: "/login".to_string(),
icon: "bi-box-arrow-in-right".to_string(),
badge: None,
},
QuickAction {
id: "register".to_string(),
label: "Register".to_string(),
url: "/register".to_string(),
icon: "bi-person-plus".to_string(),
badge: None,
},
],
show_topup_button: false,
}
}
/// Check if user has sufficient balance for a purchase
pub fn check_sufficient_balance(&self, session: &Session, required_amount_usd: Decimal) -> Result<bool, String> {
let user_email = session.get::<String>("user_email")
.map_err(|e| format!("Failed to get user email: {}", e))?
.ok_or("User not authenticated")?;
let persistent_data = UserPersistence::load_user_data(&user_email)
.unwrap_or_default();
Ok(persistent_data.wallet_balance_usd >= required_amount_usd)
}
/// Get quick top-up amounts for user's preferred currency
pub fn get_quick_topup_amounts(&self, session: &Session) -> Result<Vec<Decimal>, String> {
let user_email = session.get::<String>("user_email")
.map_err(|e| format!("Failed to get user email: {}", e))?
.ok_or("User not authenticated")?;
let persistent_data = UserPersistence::load_user_data(&user_email)
.unwrap_or_default();
// Use custom amounts if set, otherwise use defaults
if let Some(custom_amounts) = persistent_data.quick_topup_amounts {
Ok(custom_amounts)
} else {
// Default amounts in user's preferred currency
let display_currency = self.currency_service.get_user_preferred_currency(session);
let default_amounts = if display_currency == "USD" {
vec![
Decimal::from(10), // $10
Decimal::from(25), // $25
Decimal::from(50), // $50
Decimal::from(100), // $100
]
} else {
// Default fiat amounts (will be converted to USD internally)
vec![
Decimal::from(10), // $10, €10, etc.
Decimal::from(20), // $20, €20, etc.
Decimal::from(50), // $50, €50, etc.
Decimal::from(100), // $100, €100, etc.
]
};
Ok(default_amounts)
}
}
}
impl Default for NavbarService {
fn default() -> Self {
Self::builder().build().unwrap()
}
}