Skip to content

Commit 6b80148

Browse files
committed
feat: SI prefixed sats amounts
1 parent 0d08739 commit 6b80148

File tree

4 files changed

+69
-9
lines changed

4 files changed

+69
-9
lines changed

src/templates/donate.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use super::format_sats_si;
12
use crate::models::Donation;
23
use crate::templates::components::{
34
donation_invoice_markup, donation_invoice_script, DonationInvoiceConfig,
@@ -40,7 +41,7 @@ pub fn donate(
4041
div class="text-center mt-8" {
4142
div class="stat-brutal" {
4243
div class="stat-value orange" {
43-
(pool_balance_sats) " "
44+
(format_sats_si(pool_balance_sats)) " "
4445
i class="fa-solid fa-bolt" {}
4546
}
4647
div class="stat-label" { "sats split across " (num_locations) " locations" }
@@ -96,7 +97,7 @@ pub fn donate(
9697
}
9798
}
9899
td class="py-2 px-3 text-right font-bold text-highlight orange" {
99-
(donation.amount_sats()) " "
100+
(format_sats_si(donation.amount_sats())) " "
100101
i class="fa-solid fa-bolt" {}
101102
}
102103
}

src/templates/home.rs

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use super::format_sats_si;
12
use crate::models::Stats;
23
use maud::{html, Markup};
34

@@ -35,7 +36,7 @@ pub fn home(stats: &Stats) -> Markup {
3536
))
3637
(stat_card(
3738
"Sats Available",
38-
&format!("{}", stats.total_sats_available),
39+
&format_sats_si(stats.total_sats_available),
3940
true,
4041
"fa-bolt"
4142
))
@@ -128,3 +129,33 @@ fn step(number: &str, title: &str, description: &str) -> Markup {
128129
}
129130
}
130131
}
132+
133+
#[cfg(test)]
134+
mod tests {
135+
use super::*;
136+
137+
#[test]
138+
fn test_format_sats_si() {
139+
// Zero and negative
140+
assert_eq!(format_sats_si(0), "0");
141+
assert_eq!(format_sats_si(-100), "0");
142+
143+
// Small values (no suffix)
144+
assert_eq!(format_sats_si(1), "1");
145+
assert_eq!(format_sats_si(999), "999");
146+
147+
// Thousands (k suffix) - 3 significant figures
148+
assert_eq!(format_sats_si(1000), "1.00k");
149+
assert_eq!(format_sats_si(2310), "2.31k");
150+
assert_eq!(format_sats_si(21400), "21.4k");
151+
assert_eq!(format_sats_si(256000), "256k");
152+
assert_eq!(format_sats_si(999_499), "999k");
153+
assert_eq!(format_sats_si(999_500), "1.00M");
154+
155+
// Millions (M suffix) - 3 significant figures
156+
assert_eq!(format_sats_si(1_000_000), "1.00M");
157+
assert_eq!(format_sats_si(1_230_000), "1.23M");
158+
assert_eq!(format_sats_si(21_000_000), "21.0M");
159+
assert_eq!(format_sats_si(123_000_000), "123M");
160+
}
161+
}

src/templates/location_detail.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use super::format_sats_si;
12
use crate::models::{Donation, Location, NfcCard, Photo, ScanWithUser, UserRole};
23
use crate::templates::components::{
34
donation_invoice_markup, donation_invoice_script, DonationInvoiceConfig,
@@ -243,14 +244,14 @@ pub fn location_detail(
243244
div class="card-brutal-inset p-4" {
244245
div class="label-brutal text-xs mb-2" { "AVAILABLE SATS" }
245246
div class="text-2xl font-black text-highlight orange" {
246-
(available_sats) " "
247+
(format_sats_si(available_sats)) " "
247248
i class="fa-solid fa-bolt" {}
248249
}
249250
}
250251
div class="card-brutal-inset p-4" {
251252
div class="label-brutal text-xs mb-2" { "POOL BALANCE" }
252253
div class="text-2xl font-black text-secondary" {
253-
(pool_sats) " "
254+
(format_sats_si(pool_sats)) " "
254255
i class="fa-solid fa-bolt" {}
255256
}
256257
}
@@ -361,7 +362,7 @@ pub fn location_detail(
361362
div {
362363
div class="label-brutal text-xs mb-1" { "POOL BALANCE" }
363364
div class="text-3xl font-black text-highlight orange" {
364-
(pool_sats) " "
365+
(format_sats_si(pool_sats)) " "
365366
i class="fa-solid fa-bolt" {}
366367
}
367368
}
@@ -431,7 +432,7 @@ pub fn location_detail(
431432
}
432433
td class="py-3 px-4 text-right mono" {
433434
span class="text-highlight orange font-black" {
434-
(donation.amount_sats())
435+
(format_sats_si(donation.amount_sats()))
435436
}
436437
" "
437438
i class="fa-solid fa-bolt text-highlight orange" {}
@@ -475,7 +476,7 @@ pub fn location_detail(
475476
td class="py-3 px-4 text-right" {
476477
@if scan.is_claimed() {
477478
span class="text-highlight orange font-black" {
478-
(scan.sats_claimed())
479+
(format_sats_si(scan.sats_claimed()))
479480
" "
480481
i class="fa-solid fa-bolt" {}
481482
}
@@ -623,7 +624,7 @@ pub fn location_detail(
623624
"#,
624625
location.longitude, location.latitude,
625626
location.longitude, location.latitude,
626-
location.name, available_sats
627+
location.name, format_sats_si(available_sats)
627628
)))
628629

629630
// Photo upload script - auto-upload on file selection

src/templates/mod.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,33 @@ pub mod register;
1414
pub mod wallet;
1515
pub mod withdraw;
1616

17+
/// Format sats with SI prefixes (k, M) and 3 significant figures
18+
pub fn format_sats_si(sats: i64) -> String {
19+
if sats <= 0 {
20+
return "0".to_string();
21+
}
22+
let sats = sats as f64;
23+
24+
let (val, suffix) = if sats >= 1_000_000.0 {
25+
(sats / 1_000_000.0, "M")
26+
} else if sats >= 1_000.0 {
27+
(sats / 1_000.0, "k")
28+
} else {
29+
return (sats as u64).to_string();
30+
};
31+
32+
// Round to 3 significant figures
33+
let decimals = if val >= 100.0 { 0 } else if val >= 10.0 { 1 } else { 2 };
34+
let formatted = format!("{:.decimals$}{suffix}", val);
35+
36+
// Handle rounding up to next unit (e.g., 999.9k -> 1000k should be 1M)
37+
if formatted.starts_with("1000") && suffix == "k" {
38+
"1.00M".to_string()
39+
} else {
40+
formatted
41+
}
42+
}
43+
1744
pub use admin_locations::admin_locations;
1845
pub use admin_users::admin_users;
1946
pub use collect::{collect, CollectParams};

0 commit comments

Comments
 (0)