Skip to content

Commit dbe4e94

Browse files
authored
fix(menubar): keep cost budget in USD and flag empty custom budget (#508)
Two follow-ups from the budget review: - Currency consistency: the daily cost budget is defined in USD (the presets and the custom field are labeled "$"), but the "exceeded" banner ran the value through the display-currency rate, so a non-USD user saw the field and banner disagree (e.g. field "$100", banner "EUR 92"). Render the budget label in USD via a new asUSD() helper so the picker, field, and banner all agree. The over-budget comparison was already USD vs USD and is unchanged. - Empty custom cue: selecting "Custom..." and leaving the field blank stores 0, which silently disables the alert while the picker still shows "Custom...". The help text now says "Enter an amount above, or the alert stays off." in that state so it does not look armed when it isn't.
1 parent 8794dde commit dbe4e94

2 files changed

Lines changed: 22 additions & 3 deletions

File tree

mac/Sources/CodeBurnMenubar/AppStore.swift

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,9 +85,11 @@ final class AppStore {
8585
return total >= activeDailyBudget
8686
}
8787

88-
/// The active daily-budget threshold formatted for display (currency or tokens).
88+
/// The active daily-budget threshold formatted for display (tokens, or USD).
89+
/// The cost budget is defined in USD (matching the "$" presets and field), so
90+
/// it is not run through the display-currency conversion here.
8991
var dailyBudgetLabel: String {
90-
isTokenMetric ? "\(activeDailyBudget.asCompactTokens()) tokens" : activeDailyBudget.asCurrency()
92+
isTokenMetric ? "\(activeDailyBudget.asCompactTokens()) tokens" : activeDailyBudget.asUSD()
9193
}
9294

9395
var isLoading: Bool { loadingCountsByKey.values.contains { $0 > 0 } }
@@ -1268,6 +1270,12 @@ private let thousandsFormatter: NumberFormatter = {
12681270
if n >= 1_000 { return String(format: "%.0fK", n / 1_000) }
12691271
return String(format: "%.0f", n)
12701272
}
1273+
1274+
/// Formats a raw USD amount with a "$" and grouping, without applying the
1275+
/// display-currency rate. Used for the USD-denominated daily budget.
1276+
func asUSD() -> String {
1277+
"$" + (groupedDecimalFormatter.string(from: NSNumber(value: self)) ?? "\(Int(self))")
1278+
}
12711279
}
12721280

12731281
extension Int {

mac/Sources/CodeBurnMenubar/Views/SettingsView.swift

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,17 @@ private struct GeneralSettingsTab: View {
5757
v == v.rounded() ? String(Int(v)) : String(v)
5858
}
5959

60+
// Help text under the budget picker. When "Custom…" is selected but no amount
61+
// has been entered, the budget is effectively 0 (off); call that out so the
62+
// alert does not look armed when it isn't.
63+
private var alertHelpText: String {
64+
let customEmpty = store.isTokenMetric
65+
? (tokenCustom && store.dailyTokenBudget == 0)
66+
: (costCustom && store.dailyBudget == 0)
67+
if customEmpty { return "Enter an amount above, or the alert stays off." }
68+
return "Flame icon turns yellow when today's \(store.isTokenMetric ? "tokens" : "cost") pass the daily budget."
69+
}
70+
6071
var body: some View {
6172
Form {
6273
Section("Display") {
@@ -162,7 +173,7 @@ private struct GeneralSettingsTab: View {
162173
}
163174
}
164175
}
165-
Text("Flame icon turns yellow when today's \(store.isTokenMetric ? "tokens" : "cost") pass the daily budget.")
176+
Text(alertHelpText)
166177
.font(.system(size: 11))
167178
.foregroundStyle(.secondary)
168179
}

0 commit comments

Comments
 (0)