From 033bed70eff50b295cbbf3ea1afe1082ec65d52a Mon Sep 17 00:00:00 2001 From: Wintermute Date: Mon, 31 Aug 2026 22:08:40 -0400 Subject: [PATCH] refactor(desktop): dock market wallet in drawer Signed-off-by: Wintermute --- .../features/market/ui/AgentWalletPanel.tsx | 102 ++++++++++++++++++ .../src/features/market/ui/MarketScreen.tsx | 99 +++++------------ .../e2e/market-prototype-screenshots.spec.ts | 24 ++++- 3 files changed, 150 insertions(+), 75 deletions(-) create mode 100644 desktop/src/features/market/ui/AgentWalletPanel.tsx diff --git a/desktop/src/features/market/ui/AgentWalletPanel.tsx b/desktop/src/features/market/ui/AgentWalletPanel.tsx new file mode 100644 index 0000000000..f87e108d46 --- /dev/null +++ b/desktop/src/features/market/ui/AgentWalletPanel.tsx @@ -0,0 +1,102 @@ +import { WalletCards } from "lucide-react"; + +import type { MarketScenarioId } from "@/features/market/lib/marketPrototypeData"; +import { ProjectContextRail } from "@/features/projects/ui/ProjectContextRail"; +import { ProjectHomeColumn } from "@/features/projects/ui/ProjectHomeColumn"; +import { useThreadPanelWidth } from "@/shared/hooks/useThreadPanelWidth"; +import { SIDEBAR_WIDTH_MIN } from "@/shared/layout/sidebarLayout"; + +const MARKET_WALLET_WIDTH_KEY = "buzz.desktop.market-wallet-width"; + +const WALLET_DETAILS: Record< + MarketScenarioId, + { account: string; balance: string; settlement: string } +> = { + finite: { + account: "escrow1report…13c8", + balance: "150 sats funded", + settlement: "1 paid · 2 reserved", + }, + unlimited: { + account: "wallet1mapper…c241", + balance: "80 sats escrowed", + settlement: "760 sats paid", + }, + auction: { + account: "escrow1strings…9f10", + balance: "600 sats funded", + settlement: "Held until award", + }, + tender: { + account: "escrow1tender…1b73", + balance: "2,000 sats funded", + settlement: "Held during selection", + }, + awarded: { + account: "escrow1tender…1b73", + balance: "1,750 sats escrowed", + settlement: "Release on signed receipt", + }, +}; + +export function AgentWalletPanel({ + open, + scenarioId, +}: { + open: boolean; + scenarioId: MarketScenarioId; +}) { + const width = useThreadPanelWidth(undefined, { + minWidthPx: SIDEBAR_WIDTH_MIN, + sessionKey: MARKET_WALLET_WIDTH_KEY, + }); + const wallet = WALLET_DETAILS[scenarioId]; + + return ( + + +
+
+ +

Agent wallet

+
+
+

+ Settlement for this listing +

+
+ + + +
+

+ {wallet.account} +

+
+
+
+
+ ); +} + +function WalletValue({ label, value }: { label: string; value: string }) { + return ( +
+
{label}
+
{value}
+
+ ); +} diff --git a/desktop/src/features/market/ui/MarketScreen.tsx b/desktop/src/features/market/ui/MarketScreen.tsx index 8536d5d347..55dab7a1da 100644 --- a/desktop/src/features/market/ui/MarketScreen.tsx +++ b/desktop/src/features/market/ui/MarketScreen.tsx @@ -5,11 +5,11 @@ import { Radio, Store, TriangleAlert, - WalletCards, } from "lucide-react"; import * as React from "react"; import { ChatHeader } from "@/features/chat/ui/ChatHeader"; +import { AgentWalletPanel } from "@/features/market/ui/AgentWalletPanel"; import { MARKET_SCENARIOS, type MarketActivity, @@ -28,6 +28,7 @@ import { DialogHeader, DialogTitle, } from "@/shared/ui/dialog"; +import { DrawerPanelIcon } from "@/shared/ui/DrawerPanelIcon"; import { Input } from "@/shared/ui/input"; import { useOptionalSidebar } from "@/shared/ui/sidebar"; import { Textarea } from "@/shared/ui/textarea"; @@ -38,37 +39,6 @@ const REPRESENTING_AGENTS = [ { name: "Sentinel", role: "Operations & safety" }, ] as const; -const WALLET_DETAILS: Record< - MarketScenarioId, - { account: string; balance: string; settlement: string } -> = { - finite: { - account: "escrow1report…13c8", - balance: "150 sats funded", - settlement: "1 paid · 2 reserved", - }, - unlimited: { - account: "wallet1mapper…c241", - balance: "80 sats escrowed", - settlement: "760 sats paid", - }, - auction: { - account: "escrow1strings…9f10", - balance: "600 sats funded", - settlement: "Held until award", - }, - tender: { - account: "escrow1tender…1b73", - balance: "2,000 sats funded", - settlement: "Held during selection", - }, - awarded: { - account: "escrow1tender…1b73", - balance: "1,750 sats escrowed", - settlement: "Release on signed receipt", - }, -}; - const COMMERCIAL_TERM_LABELS = new Set([ "Price", "Initial quantity", @@ -108,6 +78,7 @@ export function MarketScreen({ scenarioId }: { scenarioId: MarketScenarioId }) { const scenario = MARKET_SCENARIOS[scenarioId]; const sidebar = useOptionalSidebar(); const [createOpen, setCreateOpen] = React.useState(false); + const [walletOpen, setWalletOpen] = React.useState(true); const isTerminal = scenario.status !== "Open"; return ( @@ -121,6 +92,27 @@ export function MarketScreen({ scenarioId }: { scenarioId: MarketScenarioId }) { >
setWalletOpen((open) => !open)} + size="icon" + title={walletOpen ? "Hide agent wallet" : "Show agent wallet"} + type="button" + variant="ghost" + > + + + } channelType="stream" description={scenario.summary} leadingContent={} @@ -132,7 +124,6 @@ export function MarketScreen({ scenarioId }: { scenarioId: MarketScenarioId }) { setCreateOpen(true)} scenario={scenario} - scenarioId={scenarioId} />
@@ -187,6 +178,8 @@ export function MarketScreen({ scenarioId }: { scenarioId: MarketScenarioId }) {
+ + ); } @@ -194,11 +187,9 @@ export function MarketScreen({ scenarioId }: { scenarioId: MarketScenarioId }) { function OfferCard({ onCreate, scenario, - scenarioId, }: { onCreate: () => void; scenario: MarketScenario; - scenarioId: MarketScenarioId; }) { const author = scenario.terms.find( @@ -216,7 +207,7 @@ function OfferCard({ className="overflow-hidden rounded-2xl border bg-card" data-testid="market-offer-card" > -
+
-
); } -function AgentWallet({ scenarioId }: { scenarioId: MarketScenarioId }) { - const wallet = WALLET_DETAILS[scenarioId]; - return ( - - ); -} - -function WalletValue({ label, value }: { label: string; value: string }) { - return ( -
-
{label}
-
{value}
-
- ); -} - function CreateMarketDialog({ onOpenChange, open, diff --git a/desktop/tests/e2e/market-prototype-screenshots.spec.ts b/desktop/tests/e2e/market-prototype-screenshots.spec.ts index 1d0ce05b80..6f8f080ea4 100644 --- a/desktop/tests/e2e/market-prototype-screenshots.spec.ts +++ b/desktop/tests/e2e/market-prototype-screenshots.spec.ts @@ -49,7 +49,7 @@ test.describe("market channel prototype", () => { const offerCardWidth = await market .getByTestId("market-offer-card") .evaluate((element) => element.getBoundingClientRect().width); - expect(offerCardWidth).toBeGreaterThan(1100); + expect(offerCardWidth).toBeGreaterThan(850); const imageAspectRatio = await market .getByTestId("market-product-image") .evaluate((element) => { @@ -57,10 +57,28 @@ test.describe("market channel prototype", () => { return bounds.width / bounds.height; }); expect(imageAspectRatio).toBeCloseTo(1, 1); - await expect(market.getByTestId("market-agent-wallet")).toBeVisible(); + const wallet = market.getByTestId("market-agent-wallet"); + await expect(wallet).toBeVisible(); + await expect(wallet).toHaveCSS( + "background-color", + await page + .locator('[data-sidebar="sidebar"]') + .evaluate( + (element) => window.getComputedStyle(element).backgroundColor, + ), + ); await expect( - market.getByText("Agent wallet", { exact: true }), + market.getByRole("button", { name: "Hide agent wallet" }).first(), ).toBeVisible(); + const walletRail = market.getByTestId("market-wallet-rail"); + await market.getByTestId("market-wallet-toggle").click(); + await expect(walletRail).toHaveAttribute("aria-hidden", "true"); + await expect(walletRail).toHaveCSS("width", "0px"); + await expect( + market.getByRole("button", { name: "Show agent wallet" }), + ).toBeVisible(); + await market.getByRole("button", { name: "Show agent wallet" }).click(); + await expect(wallet).toBeVisible(); await expect(market.getByText("Agent market channel")).toBeVisible(); await expect(market.getByTestId("market-agent-avatar")).toHaveCount( scenario === "unlimited" ? 3 : 4,