Skip to content
Merged
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
28 changes: 19 additions & 9 deletions src/components/BottomNav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,34 +14,44 @@ export function BottomNav() {
const location = useLocation();
const navigate = useNavigate();

const handleNavClick = (path: string) => {
// Haptic feedback for mobile devices
if ('vibrate' in navigator && navigator.vibrate) {
navigator.vibrate(10);
}
navigate(path);
};

return (
<nav className="fixed bottom-0 left-0 right-0 bg-card border-t border-border px-4 pb-safe z-50" aria-label="Main navigation">
<div className="max-w-lg mx-auto flex items-center justify-around py-2">
<nav className="fixed bottom-0 left-0 right-0 bg-card/95 backdrop-blur-lg border-t border-border/50 px-2 pb-safe pt-2 z-50" aria-label="Main navigation">
<div className="max-w-lg mx-auto flex items-center justify-around">
{navItems.map(({ icon: Icon, label, path }) => {
const isActive = location.pathname === path;
return (
<button
key={path}
onClick={() => navigate(path)}
onClick={() => handleNavClick(path)}
className={cn(
'flex flex-col items-center gap-1 px-4 py-2 rounded-xl transition-all duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary',
'relative flex flex-col items-center justify-center gap-1 px-3 py-3 min-w-[64px] min-h-[64px] rounded-2xl transition-all duration-200',
'active:scale-95 active:bg-accent',
'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-2',
isActive
? 'text-primary'
: 'text-muted-foreground hover:text-foreground'
? 'text-primary bg-primary/10'
: 'text-muted-foreground hover:text-foreground hover:bg-accent/50'
)}
aria-label={`${label}${isActive ? ' (current page)' : ''}`}
aria-current={isActive ? 'page' : undefined}
>
<Icon
className={cn(
'w-6 h-6 transition-transform duration-200',
'w-6 h-6 transition-all duration-200',
isActive && 'scale-110'
)}
aria-hidden="true"
/>
<span className="text-xs font-medium">{label}</span>
<span className="text-[11px] font-medium leading-tight">{label}</span>
{isActive && (
<span className="absolute -bottom-0.5 w-1 h-1 rounded-full bg-primary" aria-hidden="true" />
<span className="absolute top-2 right-2 w-1.5 h-1.5 rounded-full bg-primary" aria-hidden="true" />
)}
</button>
);
Expand Down
54 changes: 42 additions & 12 deletions src/components/TransactionItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { ArrowUpRight, ArrowDownLeft, Phone, Receipt, Clock, ExternalLink, Zap,
import { Transaction } from '@/types';
import { StatusBadge } from './StatusBadge';
import { Badge } from './ui/badge';
import { Button } from './ui/button';
import { cn } from '@/lib/utils';
import { formatDistanceToNow, format } from 'date-fns';
import { splitFee } from '@/lib/fees';
Expand Down Expand Up @@ -118,8 +119,30 @@ function TransactionItemComponent({
<span>{relativeTime}</span>
</div>
</div>
<div className="flex justify-end mt-1">
<div className="flex items-center justify-between mt-1">
<StatusBadge status={transaction.status} />
{(transaction.explorerUrl || transaction.txHash) && (
<Button
variant="ghost"
size="sm"
asChild
className="h-7 text-xs px-2"
onClick={(event) => event.stopPropagation()}
>
<a
href={
transaction.explorerUrl ||
`https://stellar.expert/explorer/public/tx/${transaction.txHash}`
}
target="_blank"
rel="noreferrer"
className="inline-flex items-center gap-1 text-blue-600 hover:text-blue-700"
>
View on Explorer
<ExternalLink className="w-3 h-3" />
</a>
</Button>
)}
</div>
</div>
</div>
Expand Down Expand Up @@ -183,19 +206,26 @@ function TransactionItemComponent({
</p>
)}
{(transaction.explorerUrl || transaction.txHash) && (
<a
href={
transaction.explorerUrl ||
`https://stellar.expert/explorer/public/tx/${transaction.txHash}`
}
target="_blank"
rel="noreferrer"
className="mt-1 inline-flex items-center gap-1 text-[11px] text-blue-600 hover:underline"
<Button
variant="outline"
size="sm"
asChild
className="mt-2 h-7 text-xs"
onClick={(event) => event.stopPropagation()}
>
Open in Stellar Explorer
<ExternalLink className="w-3 h-3" />
</a>
<a
href={
transaction.explorerUrl ||
`https://stellar.expert/explorer/public/tx/${transaction.txHash}`
}
target="_blank"
rel="noreferrer"
className="inline-flex items-center gap-1"
>
View on Explorer
<ExternalLink className="w-3 h-3" />
</a>
</Button>
)}
</div>
</div>
Expand Down
27 changes: 26 additions & 1 deletion src/components/__tests__/TransactionItem.metadata.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,32 @@ describe('TransactionItem detailed metadata (#92)', () => {
/>,
);

expect(screen.getByText('Open in Stellar Explorer')).toBeInTheDocument();
expect(screen.getByText('View on Explorer')).toBeInTheDocument();
expect(screen.getByText(/Hash:/)).toBeInTheDocument();
});

it('shows explorer button in main view when tx hash exists', () => {
render(
<TransactionItem
transaction={buildTransaction({
txHash: 'abc123hashxyz987654',
})}
senderName="Sender"
/>,
);

expect(screen.getByText('View on Explorer')).toBeInTheDocument();
});

it('does not show explorer button when tx hash is missing', () => {
render(
<TransactionItem
transaction={buildTransaction()}
showDetailedView
senderName="Sender"
/>,
);

expect(screen.queryByText('View on Explorer')).not.toBeInTheDocument();
});
});
5 changes: 4 additions & 1 deletion src/pages/History.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { Input } from '@/components/ui/input';
import { Button } from '@/components/ui/button';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/ui/collapsible';
import { BottomNav } from '@/components/BottomNav';
import { useNavigate } from 'react-router-dom';
import { ChartContainer, ChartLegend, ChartLegendContent, ChartTooltip, ChartTooltipContent } from '@/components/ui/chart';
import { Bar, BarChart, Cell, Pie, PieChart, XAxis, YAxis } from 'recharts';
Expand Down Expand Up @@ -133,7 +134,7 @@ const History: React.FC = () => {
];

return (
<div className="mx-auto w-full max-w-3xl bg-background min-h-screen px-3 sm:px-5 lg:px-6 pb-20">
<div className="mx-auto w-full max-w-3xl bg-background min-h-screen px-3 sm:px-5 lg:px-6 pb-24">
<div className="sticky top-0 bg-background/95 backdrop-blur-sm z-10 border-b border-border/50">
<div className="py-6 pb-4">
{/* Header with back button */}
Expand Down Expand Up @@ -425,6 +426,8 @@ const History: React.FC = () => {
</div>
)}
</div>

<BottomNav />
</div>
);
};
Expand Down
5 changes: 4 additions & 1 deletion src/pages/Refunds.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { useNavigate } from 'react-router-dom';
import { ArrowLeft, RotateCcw } from 'lucide-react';
import { Button } from '@/components/ui/button';
import { Separator } from '@/components/ui/separator';
import { BottomNav } from '@/components/BottomNav';
import { useQuery } from '@tanstack/react-query';
import { fetchRefunds } from '@/lib/activity';
import { RefundTracker, RefundCard } from '@/components/RefundTracker';
Expand All @@ -22,7 +23,7 @@ const Refunds: React.FC = () => {
);

return (
<div className="min-h-screen bg-background">
<div className="min-h-screen bg-background pb-24">
{/* Header */}
<div className="sticky top-0 z-10 bg-background/80 backdrop-blur-sm border-b border-border/40">
<div className="flex items-center gap-3 px-4 py-3">
Expand Down Expand Up @@ -84,6 +85,8 @@ const Refunds: React.FC = () => {
</div>
)}
</div>

<BottomNav />
</div>
);
};
Expand Down
2 changes: 1 addition & 1 deletion src/pages/SendMoney.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -883,7 +883,7 @@ export default function SendMoney() {
}

return (
<div className="min-h-screen bg-background pb-32 overflow-x-hidden">
<div className="min-h-screen bg-background pb-24 overflow-x-hidden">
{/* Header */}
<header className="sticky top-0 z-10 bg-background/95 backdrop-blur-sm border-b border-border px-4 sm:px-6 py-4">
<div className="max-w-lg mx-auto flex items-center gap-3 sm:gap-4">
Expand Down
Loading