229 lines
7.9 KiB
Rust
229 lines
7.9 KiB
Rust
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()
|
|
}
|
|
} |