Skip to main content

max / makenotwork

4.6 KB · 153 lines History Blame Raw
1 //! Shared formatting utilities used across TUI screens and commands.
2
3 use crate::currency::Currency;
4
5 /// Format a revenue amount in cents. Returns the bare symbol and "0" for zero.
6 ///
7 /// Takes the currency the amount is denominated in, because there is no such
8 /// thing as a bare amount: the same integer is different money to a US and a
9 /// British creator. Pass the currency the *number* came with — per-project
10 /// revenue carries its own — falling back to the viewer's settlement currency
11 /// only where the server sends no currency alongside the figure.
12 pub(crate) fn format_cents(cents: i64, currency: Currency) -> String {
13 if cents == 0 {
14 return format!("{}0", currency.symbol());
15 }
16 let sign = if cents < 0 { "-" } else { "" };
17 let abs = cents.unsigned_abs();
18 format!("{sign}{}{}.{:02}", currency.symbol(), abs / 100, abs % 100)
19 }
20
21 /// Format an item price in cents. Returns "Free" for zero.
22 ///
23 /// See [`format_cents`] on why the currency is not optional. A creator's prices
24 /// are always in their own settlement currency.
25 pub(crate) fn format_price(cents: i32, currency: Currency) -> String {
26 if cents == 0 {
27 return "Free".to_string();
28 }
29 format_cents(i64::from(cents), currency)
30 }
31
32 /// Human-readable creator tier label.
33 pub(crate) fn format_tier(tier: &str) -> &str {
34 match tier {
35 "basic" => "Basic",
36 "small_files" => "Small Files",
37 "big_files" => "Big Files",
38 "everything" => "Everything",
39 _ => tier,
40 }
41 }
42
43 /// Human-readable project type label.
44 pub(crate) fn format_project_type(pt: &str) -> &str {
45 match pt {
46 "software" => "Software",
47 "music" => "Music",
48 "blog" => "Blog",
49 "video" => "Video",
50 "audio" => "Audio",
51 "art" => "Art",
52 "writing" => "Writing",
53 "education" => "Education",
54 other => other,
55 }
56 }
57
58 /// Human-readable item type label.
59 pub(crate) fn format_item_type(it: &str) -> &str {
60 match it {
61 "audio" => "Audio",
62 "text" => "Text",
63 "video" => "Video",
64 "image" => "Image",
65 "plugin" => "Plugin",
66 "preset" => "Preset",
67 "sample" => "Sample",
68 "course" => "Course",
69 "template" => "Template",
70 "digital" => "Digital",
71 "bundle" => "Bundle",
72 other => other,
73 }
74 }
75
76 #[cfg(test)]
77 mod tests {
78 use super::*;
79
80 use crate::currency::Currency;
81
82 #[test]
83 fn format_cents_zero() {
84 assert_eq!(format_cents(0, Currency::Usd), "$0");
85 }
86
87 #[test]
88 fn format_cents_positive() {
89 assert_eq!(format_cents(999, Currency::Usd), "$9.99");
90 assert_eq!(format_cents(100, Currency::Usd), "$1.00");
91 assert_eq!(format_cents(1050, Currency::Usd), "$10.50");
92 }
93
94 #[test]
95 fn format_cents_carries_the_sign() {
96 // A refunded period is negative revenue, and dropping the minus turns a
97 // loss into a gain on screen.
98 assert_eq!(format_cents(-1050, Currency::Usd), "-$10.50");
99 assert_eq!(format_cents(-5, Currency::Gbp), "-\u{a3}0.05");
100 }
101
102 #[test]
103 fn format_cents_uses_the_currencys_own_symbol() {
104 assert_eq!(format_cents(1050, Currency::Gbp), "\u{a3}10.50");
105 assert_eq!(format_cents(1050, Currency::Cad), "CA$10.50");
106 assert_eq!(format_cents(1050, Currency::Eur), "\u{20ac}10.50");
107 assert_eq!(format_cents(0, Currency::Nzd), "NZ$0");
108 }
109
110 #[test]
111 fn format_price_free() {
112 // Free is free in every currency; no symbol belongs on it.
113 assert_eq!(format_price(0, Currency::Usd), "Free");
114 assert_eq!(format_price(0, Currency::Gbp), "Free");
115 }
116
117 #[test]
118 fn format_price_nonzero() {
119 assert_eq!(format_price(550, Currency::Usd), "$5.50");
120 assert_eq!(format_price(1299, Currency::Usd), "$12.99");
121 assert_eq!(format_price(1299, Currency::Aud), "A$12.99");
122 }
123
124 #[test]
125 fn format_tier_known() {
126 assert_eq!(format_tier("basic"), "Basic");
127 assert_eq!(format_tier("small_files"), "Small Files");
128 assert_eq!(format_tier("everything"), "Everything");
129 }
130
131 #[test]
132 fn format_tier_unknown() {
133 assert_eq!(format_tier("custom"), "custom");
134 }
135
136 #[test]
137 fn format_project_type_known() {
138 assert_eq!(format_project_type("software"), "Software");
139 assert_eq!(format_project_type("music"), "Music");
140 }
141
142 #[test]
143 fn format_item_type_known() {
144 assert_eq!(format_item_type("audio"), "Audio");
145 assert_eq!(format_item_type("plugin"), "Plugin");
146 }
147
148 #[test]
149 fn format_item_type_unknown() {
150 assert_eq!(format_item_type("other_thing"), "other_thing");
151 }
152 }
153