From 78fbefc72188ca17577355306a2a29ed699348d6 Mon Sep 17 00:00:00 2001 From: Cho Young-Hwi Date: Sat, 28 Mar 2026 18:32:45 +0000 Subject: [PATCH] [#622] Redesign Trading History layout for mobile - Stacked two-line layout: type badge + story title on top, token count + date on bottom, PLOT cost right-aligned. No more row overflow. - Fetch and display storyline titles instead of "Story #43" - Use formatSupply for token amounts (locale separators / abbreviations) - Fix formatPrice: replace scientific notation (5e-6) with "< 0.001" - Add year to date formatting (Mar 27, 2026) - Buy/Sell badges styled as colored pills Fixes #622 Co-Authored-By: Claude Opus 4.6 (1M context) --- lib/format.ts | 2 +- src/app/dashboard/reader/page.tsx | 122 ++++++++++++++++++------------ 2 files changed, 76 insertions(+), 48 deletions(-) diff --git a/lib/format.ts b/lib/format.ts index 19d22af7..b198d1e0 100644 --- a/lib/format.ts +++ b/lib/format.ts @@ -9,7 +9,7 @@ export function formatPrice(value: string | number): string { const v = typeof value === "string" ? parseFloat(value) : value; if (v === 0 || isNaN(v)) return "0"; - if (v < 0.001) return v.toExponential(0); + if (v < 0.001) return "< 0.001"; if (v < 1) return v.toFixed(4); return v.toFixed(2); } diff --git a/src/app/dashboard/reader/page.tsx b/src/app/dashboard/reader/page.tsx index f073d16e..bbc2adb3 100644 --- a/src/app/dashboard/reader/page.tsx +++ b/src/app/dashboard/reader/page.tsx @@ -3,7 +3,7 @@ import { useAccount } from "wagmi"; import { useQuery, useInfiniteQuery } from "@tanstack/react-query"; import { supabase, type Donation, type TradeHistory } from "../../../../lib/supabase"; -import { formatPrice } from "../../../../lib/format"; +import { formatPrice, formatSupply } from "../../../../lib/format"; import { ReaderPortfolio } from "../../../components/ReaderPortfolio"; import Link from "next/link"; import { WriterIdentityClient } from "../../../components/WriterIdentityClient"; @@ -219,6 +219,23 @@ function TradingHistory({ address }: { address: string }) { const trades = data?.pages.flatMap((p) => p.rows) ?? []; const totalCount = data?.pages[0]?.totalCount ?? 0; + // Fetch storyline titles for displayed trades + const storylineIds = [...new Set(trades.map((t) => t.storyline_id))]; + const { data: storylineTitles } = useQuery({ + queryKey: ["storyline-titles", storylineIds.join(",")], + queryFn: async () => { + if (!supabase || storylineIds.length === 0) return {} as Record; + const { data: rows } = await supabase + .from("storylines") + .select("storyline_id, title") + .in("storyline_id", storylineIds); + const map: Record = {}; + for (const r of rows ?? []) map[r.storyline_id] = r.title; + return map; + }, + enabled: storylineIds.length > 0, + }); + return (

Trading History

@@ -229,53 +246,64 @@ function TradingHistory({ address }: { address: string }) { {isLoading &&

Loading...

}
- {trades.map((t) => ( -
-
- - {t.event_type === "mint" ? "Buy" : "Sell"} - - - Story #{t.storyline_id} - - {t.block_timestamp && ( - - )} -
-
- {t.price_per_token > 0 && ( - - {formatPrice(t.reserve_amount / t.price_per_token)} tokens - - )} - - {formatPrice(t.reserve_amount)} {RESERVE_LABEL} - - {t.tx_hash && ( - - ↗ - - )} + {trades.map((t) => { + const isBuy = t.event_type === "mint"; + const title = storylineTitles?.[t.storyline_id]; + const tokenCount = t.price_per_token > 0 ? t.reserve_amount / t.price_per_token : 0; + return ( +
+
+
+
+ + {isBuy ? "Buy" : "Sell"} + + + {title || `Story #${t.storyline_id}`} + +
+
+ {tokenCount > 0 && ( + {formatSupply(tokenCount)} tokens + )} + {t.block_timestamp && ( + + )} +
+
+
+ + {formatPrice(t.reserve_amount)} {RESERVE_LABEL} + + {t.tx_hash && ( + + ↗ + + )} +
+
-
- ))} + ); + })} {!isLoading && trades.length === 0 && (

No trades yet.