Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 1 addition & 11 deletions app/src/agentworld/pages/FeedSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import {
import { fetchWalletStatus } from '../../services/walletApi';
import { apiClient } from '../AgentWorldShell';
import ConfirmDialog from '../components/ConfirmDialog';
import { relativeTime } from '../utils/relativeTime';

const log = debug('agentworld:feed');

Expand Down Expand Up @@ -65,17 +66,6 @@ type WalletResolution = { agentId: string | null; configured: WalletConfigured }

// ── Helpers ───────────────────────────────────────────────────────────────────

function relativeTime(iso: string): string {
const ms = Date.now() - new Date(iso).getTime();
const mins = Math.floor(ms / 60000);
if (mins < 1) return 'just now';
if (mins < 60) return `${mins}m ago`;
const hrs = Math.floor(mins / 60);
if (hrs < 24) return `${hrs}h ago`;
const days = Math.floor(hrs / 24);
return `${days}d ago`;
}

function isWalletLocked(message: string): boolean {
return (
message.includes('wallet is not configured') ||
Expand Down
13 changes: 1 addition & 12 deletions app/src/agentworld/pages/JobsSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import { useT } from '../../lib/i18n/I18nContext';
import { fetchWalletStatus } from '../../services/walletApi';
import { apiClient } from '../AgentWorldShell';
import { explorerTxUrl } from '../hooks/useX402Buy';
import { relativeTime } from '../utils/relativeTime';

// ── State types ───────────────────────────────────────────────────────────────

Expand All @@ -39,18 +40,6 @@ type JobsState =

// ── Helpers ───────────────────────────────────────────────────────────────────

// TODO: extract shared relativeTime helper once Feed/Ledger/Jobs all use it.
function relativeTime(iso: string): string {
const ms = Date.now() - new Date(iso).getTime();
const mins = Math.floor(ms / 60000);
if (mins < 1) return 'just now';
if (mins < 60) return `${mins}m ago`;
const hrs = Math.floor(mins / 60);
if (hrs < 24) return `${hrs}h ago`;
const days = Math.floor(hrs / 24);
return `${days}d ago`;
}

/**
* Group the integer part of a numeric amount with thousands separators while
* preserving the original decimals ("1000000" → "1,000,000", "0.50" → "0.50").
Expand Down
24 changes: 6 additions & 18 deletions app/src/agentworld/pages/LedgerSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,15 @@
* Pattern mirrors FeedSection: useState + useEffect fetch, PanelScaffold
* wrapper, StatusBlock for loading/error/empty states.
*/
import { useEffect, useState } from 'react';
import { Fragment, useEffect, useState } from 'react';

import PanelScaffold from '../../components/layout/PanelScaffold';
import { type GqlLedgerTransaction } from '../../lib/agentworld/invokeApiClient';
import { apiClient } from '../AgentWorldShell';
import { decimalsForAsset, resolveAssetSymbol } from '../assets';
import { formatUnits, friendlyNetwork } from '../components/X402ConfirmDialog';
import { explorerTxUrl } from '../hooks/useX402Buy';
import { relativeTime } from '../utils/relativeTime';

// ── State types ───────────────────────────────────────────────────────────────

Expand All @@ -27,17 +28,6 @@ type LedgerState =

// ── Helpers ───────────────────────────────────────────────────────────────────

function relativeTime(iso: string): string {
const ms = Date.now() - new Date(iso).getTime();
const mins = Math.floor(ms / 60000);
if (mins < 1) return 'just now';
if (mins < 60) return `${mins}m ago`;
const hrs = Math.floor(mins / 60);
if (hrs < 24) return `${hrs}h ago`;
const days = Math.floor(hrs / 24);
return `${days}d ago`;
}

export function abbreviateAddress(addr: string | undefined): string {
if (!addr) return '—';
if (addr.length <= 12) return addr;
Expand Down Expand Up @@ -287,14 +277,12 @@ function TransactionRow({
<p className="mb-1 text-xs font-medium text-content-muted">Metadata</p>
<dl className="grid grid-cols-[auto_1fr] gap-x-4 gap-y-1 text-xs">
{Object.entries(tx.metadata).map(([key, val]) => (
<>
<dt key={`k-${key}`} className="font-medium text-content-muted">
{key}
</dt>
<dd key={`v-${key}`} className="break-all text-content">
<Fragment key={key}>
<dt className="font-medium text-content-muted">{key}</dt>
<dd className="break-all text-content">
{typeof val === 'string' ? val : JSON.stringify(val)}
</dd>
</>
</Fragment>
))}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
</dl>
</div>
Expand Down
33 changes: 33 additions & 0 deletions app/src/agentworld/utils/relativeTime.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';

import { relativeTime } from './relativeTime';

describe('relativeTime', () => {
beforeEach(() => {
vi.useFakeTimers();
});

afterEach(() => {
vi.useRealTimers();
});

it('returns "just now" for under 1 minute ago', () => {
vi.setSystemTime(new Date('2025-01-01T00:00:30Z'));
expect(relativeTime('2025-01-01T00:00:00Z')).toBe('just now');
});

it('returns minutes for under 1 hour ago', () => {
vi.setSystemTime(new Date('2025-01-01T00:45:00Z'));
expect(relativeTime('2025-01-01T00:00:00Z')).toBe('45m ago');
});

it('returns hours for under 24 hours ago', () => {
vi.setSystemTime(new Date('2025-01-01T05:00:00Z'));
expect(relativeTime('2025-01-01T00:00:00Z')).toBe('5h ago');
});

it('returns days for 24+ hours ago', () => {
vi.setSystemTime(new Date('2025-01-04T00:00:00Z'));
expect(relativeTime('2025-01-01T00:00:00Z')).toBe('3d ago');
});
});
12 changes: 12 additions & 0 deletions app/src/agentworld/utils/relativeTime.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export function relativeTime(iso: string): string {
const date = new Date(iso);
if (isNaN(date.getTime())) return 'just now';
const ms = Date.now() - date.getTime();
const mins = Math.floor(ms / 60000);
if (mins < 1) return 'just now';
if (mins < 60) return `${mins}m ago`;
const hrs = Math.floor(mins / 60);
if (hrs < 24) return `${hrs}h ago`;
const days = Math.floor(hrs / 24);
return `${days}d ago`;
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Loading