Repository navigation
v0.6.0
An unknown balance is never shown as a zero. A wallet unlocked while NoirWire could not be reached showed "$0.00" for its total, its cash and every portfolio, beside a notice that the figures "may be out of date": a person reads that as a real zero balance. Until balances have loaded once, every figure worked out from them is now null, the types say so, and the screen carries one line with a retry. Also here: Costs states prices only, the chart hint follows the pointer and not the platform, Home says when Earn does not run, and a testing note for the header, Welcome and About.
Breaking
The types changed on purpose, so an app cannot print a zero by accident: a figure from balances is Figure (string | null), and a component draws nothing for null. Each app keeps one ReadFreshness for its balance read already (0.5.3, for homeView); pass that same value everywhere below.
For both apps:
- Home:
view.total.valueandview.cash.valuearestring | null, and so arevalueandlineon each row ofview.portfoliosandview.archived.rows. Draw nothing for null (the waiting placeholder whileview.loading), never "$0.00". Newview.unavailable: { text, retry } | null: when it is not null, showtextonce, with a button labelledretrythat runs the balance refresh, in place of the stale notice (view.staleis null then).view.emptyis false andview.waitingis null until balances load, so the empty wallet's "Add money" lead and the "has arrived" notice are not drawn over an unread wallet. - Home, Earn:
view.earningis renamedview.earn. It is null where Earn does not run (the app passesundefinedas the Earn total off the main network, as now). Whenview.earnis null, hide the Home Earn tile and the "could be earning" card (portfolioCopy.earnPromo); do not decide that from the network in the app. - Portfolio list:
portfolioRowView(reads, portfolio, updatedAt, balances)takes the balance read as a fourth argument.valueandlinearestring | null. - Portfolio and pie pages:
portfolioView(reads, wallet, id, updatedAt, balances, inEarn?):balancesis the fifth argument andinEarnmoves to sixth.valueandcashLinearestring | null; a pie'smix.slices[].trailingisstring | null. Newview.loadingandview.unavailable(draw as on Home). Until balances load,primary,rebalance,holdingsandemptyare null, and every button inquietbut Receive hasdisabled: trueand areason: show the reason where the screen showssendReason. - Tracker page:
TrackerState.freshnesstakesbalancesas well (a visitor passesNEVER_READ).holding.quantityand.valuewere already nullable; until balances load they are null,holding.rowsis empty andholding.noneis null, so draw neither a quantity nor "You do not own this tracker yet". Newview.unavailable. Buy is disabled and Sell is not offered until balances load. - Send:
SendFormStatetakesbalances.amountLineandavailable.valuearestring | null.balanceUnavailablenow also carries the reason while balances have never loaded: keep drawing it where it is drawn. - Buy and sell:
TradeFormStatetakesbalances;availableisstring | null, andbalanceUnavailablecarries the reason.portfolioChoices(reads, wallet, side, symbol, balances)andnoMoneyView(reads, wallet, portfolioId, balances)take it last; a choice'scaptionisstring | null, andnoMoneyViewanswers null until balances load. - Invest in a pie:
pieInvestViewtakesbalances;availableisstring | null, and newbalanceUnavailableis the reason to show under the amount. - Move to portfolio:
FundingAmountStatetakes a requiredreadFailed: boolean(whether the funding wallet's read on opening failed) besidefundingBalance. Newview.unavailable: show its line and retry when not null. The web'sleadno longer says "Available 0.00 USDC" before the read: it names no amount.choosePortfolioViewtakesbalances, and each row'scashisstring | null. - Earn:
earnScreenView,earnPortfolioViewandearnSheetViewtakebalances. A row'scash(andcash,cashAvailableonearnPortfolioView) isstring | null; the sheet'savailableisstring | nulland it has a newbalanceUnavailable. The screen has newloadingandunavailable; until balances load,depositandwithdraware disabled,deposit.reasonis the unavailable line and no rowopensanything. The Earn total was already "Unavailable", never a zero, until every position is read, and is unchanged.earnChoiceViewandearnAmountVieware unchanged: they are reached only through the actions the screen now holds back. - Chart hint:
marketsCopy.detail.chartHintis now{ touch, mouse }andmobileMarketsCopy.detail.chartHintis gone. DrawchartHint(pointer)from@noirwire/shared/presentation. - Testing note: draw
betaView().tag("Beta") as a small label beside the NoirWire mark in the app header and on Welcome. DrawaboutView().beta("NoirWire is in testing. Start with small amounts.") as a line on Settings' About page. Both are shown on every network, the main network included: they are about the product, not the network.networkLabel()and the test-network banner keep their rule.
For the web app:
-
app/portfolio/page.tsx(homeView,portfolioView),PortfolioDetail,TradeDialog(tradeFormView,noMoneyView),SendDialog,FundPrivatelyFlow,PieOrderDialog,app/earn/page.tsxandapp/markets/[symbol]/page.tsxare the call sites above. -
DesktopHomedraws the "could be earning" card fromportfolioCopy.earnPromo: draw it only whenhome.earnis not null. -
app/markets/[symbol]/page.tsxdrawscopy.chartHint: drawchartHint(pointer), wherepointeris "touch" when the device reports a coarse pointer (matchMedia("(pointer: coarse)")) and "mouse" otherwise. - The Risks row in Settings reads
settingsCopy.risks.description, which changed: nothing to do.
For the mobile app:
-
HomeScreen(view.earningbecomesview.earn),PortfolioScreen,TrackerScreen,TradeSheet(portfolioChoices,tradeFormView,noMoneyView),SendScreen,FundScreen(fundingAmountView,choosePortfolioView),PieOrderSheet(pieInvestView,noMoneyView) andEarnScreenare the call sites above. -
TrackerScreendrawsmobileMarketsCopy.detail.chartHint: drawchartHint("touch"). - The Settings row for Risks and its sublabel are drawn from the app's own strings if they are not read from
settingsCopy.risks.description: make the sublabel "What can go wrong".
Added
hasLoaded(read)in@noirwire/shared/domain: whether a read has ever come back.balancesView(read),balancesUnavailable(),BalancesView,UnavailableViewandFigurein@noirwire/shared/presentation: the one rule for balances that have never loaded.chartHint(pointer)andChartPointerin@noirwire/shared/presentation.betaView(),BetaViewandAboutView.beta;appCopy.beta.portfolioCopy.balances.unavailable.
Fixed
- A wallet whose balances had never loaded showed a total of "$0.00", "Ready to invest $0.00" and "$0.00" on each portfolio, and Home led with "Add money" as if the wallet were empty. Every figure is now null until the first read succeeds, and the wallet is not called empty.
- The notice over those zeros said "What you see may be out of date." That wording is now only for balances that did load once; where they never loaded the line is "We couldn't load your balances. Check your connection and try again.", with a retry.
- Send, Move to portfolio, Buy, Sell, a pie's Invest and Earn could be started against a balance that had never been read. They are held back until it has, with the same reason.
- The web's Move to portfolio sheet said "Available 0.00 USDC" before the funding wallet had been read.
- The chart hint told a phone's browser or a tablet to hover.
Changed
| Where | Was | Is |
|---|---|---|
settingsCopy.costs.move |
"Moving money into a portfolio privately: 0.1% + $0.20. It usually arrives within a minute and can ..." | "Moving money into a portfolio privately: 0.1% + $0.20." |
settingsCopy.risks.description |
"What can go wrong, stated once" | "What can go wrong" |
marketsCopy.detail.chartHint |
"Hover to see the price and date." (and the phone's "Press and hold ...") | { touch: "Press and hold to see the price and date.", mouse: "Hover to see the price and date." } |
portfolioCopy.balances.unavailable (new) |
"We couldn't load your balances. Check your connection and try again." | |
fundingCopy.leadPrivate, .leadPublic |
"... Available {amount}." | the same, and without the "Available" sentence when available is null |
appCopy.beta.tag, appCopy.beta.line (new) |
"Beta", "NoirWire is in testing. Start with small amounts." |
The arrival time of a private move is still said once in step 3 of the add-money sheet, and on the funding sheet. The costs lines state prices only; their numbers still come from the fee constants.