feat(client): transaction detail screen (wallet history → tap to inspect)
Users can now tap any row in the wallet history and see the full
transaction detail, matching what the block explorer shows for the
same tx. Covers every visible activity — transfers, contact
requests, likes, posts, follows, relay proofs, contract calls.
Components
lib/api.ts
- New TxDetail interface mirroring node/api_explorer.go's
txDetail JSON (id, type, from/to + their DC addresses, µT
amount + display string, fee, block coords, gas, payload,
signature hex).
- getTxDetail(txID) with 404→null handling.
app/(app)/tx/[id].tsx — new screen
- Hero row: icon + type label + local-time timestamp
- Big amount pill (only for txs that move tokens) — signed by
the viewer's perspective (+ when you received, − when you
paid, neutral when it's someone else's tx or a non-transfer)
- Info card rows with tap-to-copy on hashes and addresses:
Tx ID, From (highlighted "you" when it's the signed-in user),
To (same), Block, Fee, Gas used (when > 0), Memo (when set)
- Collapsible Payload section — renders JSON with 2-space
indent if the node could decode it, otherwise the raw hex
- Signature copy row at the bottom (useful for debugging / audits)
- txMeta() covers all EventTypes from blockchain/types.go
(TRANSFER, CONTACT_REQUEST/ACCEPT/BLOCK, REGISTER_KEY/RELAY,
BIND_WALLET, RELAY_PROOF, BLOCK_REWARD, HEARTBEAT, CREATE_POST,
DELETE_POST, LIKE_POST/UNLIKE_POST, FOLLOW/UNFOLLOW,
CALL_CONTRACT, DEPLOY_CONTRACT, STAKE/UNSTAKE) with
distinct icons + in/out/neutral tone.
- Nested Stack layout so router.back() pops to the caller;
safeBack() fallback when entered via deep link.
app/(app)/wallet.tsx
- TxTile's outer Pressable was a no-op onPress handler; now
router.push(`/(app)/tx/${tx.hash}`). Entire row is the
touch target (icon + type + addr + time + amount).
app/(app)/_layout.tsx
- /tx/* added to hideNav regex so the detail screen is
full-screen without the 5-icon bar at the bottom.
Translation quirk
The screen is English to match the rest of the UI (what the user
just asked for in the previous commit). Handles copying via
expo-clipboard — tapping an address/hash shows "Copied" for 1.5s
with a green check, then reverts.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -191,6 +191,43 @@ export async function submitTx(tx: RawTx): Promise<{ id: string; status: string
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Full transaction detail as returned by GET /api/tx/{id}. Matches the
|
||||
* explorer's txDetail wire format. Payload is JSON-decoded when the
|
||||
* node recognises the tx type, otherwise payload_hex is set.
|
||||
*/
|
||||
export interface TxDetail {
|
||||
id: string;
|
||||
type: string;
|
||||
memo?: string;
|
||||
from: string;
|
||||
from_addr?: string;
|
||||
to?: string;
|
||||
to_addr?: string;
|
||||
amount_ut: number;
|
||||
amount: string;
|
||||
fee_ut: number;
|
||||
fee: string;
|
||||
time: string; // ISO-8601 UTC
|
||||
block_index: number;
|
||||
block_hash: string;
|
||||
block_time: string; // ISO-8601 UTC
|
||||
gas_used?: number;
|
||||
payload?: unknown;
|
||||
payload_hex?: string;
|
||||
signature_hex?: string;
|
||||
}
|
||||
|
||||
/** Fetch full tx detail by hash/id. Returns null on 404. */
|
||||
export async function getTxDetail(txID: string): Promise<TxDetail | null> {
|
||||
try {
|
||||
return await get<TxDetail>(`/api/tx/${txID}`);
|
||||
} catch (e: any) {
|
||||
if (/→\s*404\b/.test(String(e?.message))) return null;
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
export async function getTxHistory(pubkey: string, limit = 50): Promise<TxRecord[]> {
|
||||
const data = await get<AddrResponse>(`/api/address/${pubkey}?limit=${limit}`);
|
||||
return (data.transactions ?? []).map(tx => ({
|
||||
|
||||
Reference in New Issue
Block a user