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
32 changes: 4 additions & 28 deletions src/app/dashboard/loading.tsx
Original file line number Diff line number Diff line change
@@ -1,35 +1,11 @@
import { Skeleton } from "@/components/ui/skeleton";
import { DashboardSkeleton } from "@/components/ui/LoadingSkeletons";

export default function Loading() {
return (
<div className="min-h-screen bg-gray-50 dark:bg-gray-900 p-6 space-y-6">
{/* Header */}
<div className="flex justify-between items-center">
<Skeleton className="h-8 w-48" />
<Skeleton className="h-10 w-32" />
<div className="min-h-screen bg-gray-50 dark:bg-gray-900 p-6">
<div className="max-w-7xl mx-auto">
<DashboardSkeleton />
</div>

{/* Portfolio overview */}
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
{Array.from({ length: 4 }).map((_, i) => (
<div
key={i}
className="bg-white dark:bg-gray-800 rounded-xl p-4 border border-gray-200 dark:border-gray-700 space-y-2"
>
<Skeleton className="h-4 w-24" />
<Skeleton className="h-8 w-32" />
</div>
))}
</div>

{/* Charts row */}
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
<Skeleton className="h-72 rounded-xl" />
<Skeleton className="h-72 rounded-xl" />
</div>

{/* Transactions */}
<Skeleton className="h-56 rounded-xl" />
</div>
);
}
20 changes: 2 additions & 18 deletions src/app/dashboard/saved-searches/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import {
import { Input } from "@/components/ui/input";
import { Search, Filter, Settings, Bell, Mail, Bookmark } from "lucide-react";
import { Skeleton } from "@/components/ui/skeleton";
import { CardSkeleton } from "@/components/ui/LoadingSkeletons";

function SavedSearchesContent() {
const { address } = useWalletStore();
Expand Down Expand Up @@ -274,24 +275,7 @@ function SavedSearchesContent() {
)}

{/* Loading State */}
{isLoading && (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{Array.from({ length: 6 }).map((_, i) => (
<Card key={i}>
<CardHeader className="space-y-2">
<Skeleton className="h-4 w-3/4" />
<Skeleton className="h-3 w-1/2" />
</CardHeader>

<CardContent className="space-y-2">
<Skeleton className="h-3 w-full" />
<Skeleton className="h-3 w-5/6" />
<Skeleton className="h-3 w-4/6" />
</CardContent>
</Card>
))}
</div>
)}
{isLoading && <CardSkeleton count={6} className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6" />}

{!isLoading && filteredAndSortedSearches.length === 0 && (
<Card>
Expand Down
25 changes: 3 additions & 22 deletions src/app/properties/[id]/loading.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,10 @@
import { Skeleton } from "@/components/ui/skeleton";
import { PropertyDetailSkeleton } from "@/components/ui/LoadingSkeletons";

export default function Loading() {
return (
<div className="min-h-screen bg-gray-50 dark:bg-gray-900 p-6">
<div className="max-w-7xl mx-auto space-y-6">
{/* Back button + title */}
<div className="space-y-2">
<Skeleton className="h-8 w-24" />
<Skeleton className="h-10 w-96" />
</div>

{/* Main content grid */}
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
{/* Left column - images + details */}
<div className="lg:col-span-2 space-y-6">
<Skeleton className="h-96 rounded-xl" />
<Skeleton className="h-64 rounded-xl" />
</div>

{/* Right column - purchase card */}
<div className="space-y-6">
<Skeleton className="h-80 rounded-xl" />
<Skeleton className="h-48 rounded-xl" />
</div>
</div>
<div className="max-w-7xl mx-auto">
<PropertyDetailSkeleton />
</div>
</div>
);
Expand Down
6 changes: 2 additions & 4 deletions src/app/secondary-market/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { SecondaryMarketListing } from '@/types/property';
import { WalletConnector } from '@/components/WalletConnector';
import { Button } from '@/components/ui/button';
import { LoadingSpinner } from '@/components/LoadingSpinner';
import { CardSkeleton } from '@/components/ui/LoadingSkeletons';
import Link from 'next/link';
import Image from 'next/image';
import { toast } from 'sonner';
Expand Down Expand Up @@ -72,10 +73,7 @@ export default function SecondaryMarketPage() {
</div>

{isLoading ? (
<div className="flex flex-col items-center justify-center py-20">
<LoadingSpinner size="lg" />
<p className="mt-4 text-gray-600 dark:text-gray-400">Loading market listings...</p>
</div>
<CardSkeleton count={6} />
) : listings.length === 0 ? (
<div className="bg-white dark:bg-gray-800 rounded-xl p-12 text-center shadow-sm">
<p className="text-gray-600 dark:text-gray-400">No active listings in the secondary market yet.</p>
Expand Down
20 changes: 2 additions & 18 deletions src/components/PropertyPageSkeleton.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Skeleton } from "@/components/ui/skeleton";
import { CardSkeleton } from "@/components/ui/LoadingSkeletons";

/**
* Skeleton fallback for the properties listing page.
Expand Down Expand Up @@ -33,24 +34,7 @@ export default function PropertyPageSkeleton() {
</div>

{/* Property card grid skeleton */}
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
{Array.from({ length: 9 }).map((_, i) => (
<div
key={i}
className="bg-white dark:bg-gray-800 rounded-xl overflow-hidden border border-gray-200 dark:border-gray-700"
>
<Skeleton className="h-48 w-full rounded-none" />
<div className="p-4 space-y-3">
<Skeleton className="h-5 w-3/4" />
<Skeleton className="h-4 w-1/2" />
<div className="flex justify-between">
<Skeleton className="h-6 w-24" />
<Skeleton className="h-6 w-16" />
</div>
</div>
</div>
))}
</div>
<CardSkeleton count={9} viewMode="grid" />
</div>
</div>
);
Expand Down
110 changes: 52 additions & 58 deletions src/components/TransactionHistory.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { Skeleton } from '@/components/ui/skeleton';
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table';
import { EmptyState } from '@/components/ui/EmptyState';
import { History } from 'lucide-react';
import { TableSkeleton } from '@/components/ui/LoadingSkeletons';

const TRANSACTION_TYPES: TransactionType[] = ['purchase', 'transfer', 'management', 'other'];
const TRANSACTION_STATUSES: TransactionStatus[] = ['pending', 'processing', 'confirmed', 'failed', 'cancelled'];
Expand Down Expand Up @@ -289,68 +290,61 @@ export const TransactionHistory: React.FC = () => {
)}

{/* Transaction Table */}
<div className="max-h-96 overflow-y-auto rounded-lg border border-border">
<Table>
<TableHeader>
<TableRow>
<TableHead>Hash</TableHead>
<TableHead>Type</TableHead>
<TableHead>Status</TableHead>
<TableHead className="hidden md:table-cell">From</TableHead>
<TableHead className="hidden md:table-cell">To</TableHead>
<TableHead className="text-right">Time</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{isLoading ? (
Array.from({ length: 8 }).map((_, i) => (
<TableRow key={i}>
<TableCell><Skeleton className="h-4 w-28" /></TableCell>
<TableCell><Skeleton className="h-4 w-20" /></TableCell>
<TableCell><Skeleton className="h-4 w-24" /></TableCell>
<TableCell className="hidden md:table-cell"><Skeleton className="h-4 w-40" /></TableCell>
<TableCell className="hidden md:table-cell"><Skeleton className="h-4 w-40" /></TableCell>
<TableCell className="text-right"><Skeleton className="h-4 w-16 ml-auto" /></TableCell>
</TableRow>
))
) : rowsToRender.length === 0 ? (
{isLoading ? (
<TableSkeleton rows={8} columns={6} showHeader={true} />
) : (
<div className="max-h-96 overflow-y-auto rounded-lg border border-border">
<Table>
<TableHeader>
<TableRow>
<TableCell colSpan={6} className="p-0">
<EmptyState
title={searchTerm || typeFilter !== 'all' || statusFilter !== 'all'
? 'No transactions match your filters'
: 'No transactions found'}
description={searchTerm || typeFilter !== 'all' || statusFilter !== 'all'
? 'Try adjusting your search or filters to see more results.'
: 'Your transaction history will appear here once you start using the platform.'}
icon={History}
className="py-12"
/>
</TableCell>
<TableHead>Hash</TableHead>
<TableHead>Type</TableHead>
<TableHead>Status</TableHead>
<TableHead className="hidden md:table-cell">From</TableHead>
<TableHead className="hidden md:table-cell">To</TableHead>
<TableHead className="text-right">Time</TableHead>
</TableRow>
) : (
rowsToRender.map((tx) => (
<TableRow key={tx.id}>
<TableCell className="font-mono text-xs">
{tx.hash.slice(0, 10)}…{tx.hash.slice(-8)}
</TableCell>
<TableCell className="capitalize">{tx.type}</TableCell>
<TableCell className="capitalize">{tx.status}</TableCell>
<TableCell className="hidden md:table-cell font-mono text-xs">
{tx.from.slice(0, 10)}…{tx.from.slice(-8)}
</TableCell>
<TableCell className="hidden md:table-cell font-mono text-xs">
{tx.to ? `${tx.to.slice(0, 10)}…${tx.to.slice(-8)}` : '-'}
</TableCell>
<TableCell className="text-right text-xs text-muted-foreground">
{new Date(tx.timestamp).toLocaleString()}
</TableHeader>
<TableBody>
{rowsToRender.length === 0 ? (
<TableRow>
<TableCell colSpan={6} className="p-0">
<EmptyState
title={searchTerm || typeFilter !== 'all' || statusFilter !== 'all'
? 'No transactions match your filters'
: 'No transactions found'}
description={searchTerm || typeFilter !== 'all' || statusFilter !== 'all'
? 'Try adjusting your search or filters to see more results.'
: 'Your transaction history will appear here once you start using the platform.'}
icon={History}
className="py-12"
/>
</TableCell>
</TableRow>
))
)}
</TableBody>
</Table>
</div>
) : (
rowsToRender.map((tx) => (
<TableRow key={tx.id}>
<TableCell className="font-mono text-xs">
{tx.hash.slice(0, 10)}…{tx.hash.slice(-8)}
</TableCell>
<TableCell className="capitalize">{tx.type}</TableCell>
<TableCell className="capitalize">{tx.status}</TableCell>
<TableCell className="hidden md:table-cell font-mono text-xs">
{tx.from.slice(0, 10)}…{tx.from.slice(-8)}
</TableCell>
<TableCell className="hidden md:table-cell font-mono text-xs">
{tx.to ? `${tx.to.slice(0, 10)}…${tx.to.slice(-8)}` : '-'}
</TableCell>
<TableCell className="text-right text-xs text-muted-foreground">
{new Date(tx.timestamp).toLocaleString()}
</TableCell>
</TableRow>
))
)}
</TableBody>
</Table>
</div>
)}

{!isLoading && filteredTransactions.length > 0 && (
<div className="pt-4 border-t">
Expand Down
13 changes: 3 additions & 10 deletions src/components/referral/ReferralLeaderboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import { referralService } from '@/lib/referralService';
import { LeaderboardEntry, ReferralTier } from '@/types/referral';
import { formatUnits } from 'viem';

import { TableSkeleton } from '@/components/ui/LoadingSkeletons';

export interface ReferralLeaderboardProps {
limit?: number;
compact?: boolean;
Expand Down Expand Up @@ -83,16 +85,7 @@ export default function ReferralLeaderboard({
}

if (isLoading) {
return (
<div className="space-y-4">
{Array.from({ length: 5 }).map((_, i) => (
<div
key={i}
className="h-16 animate-pulse rounded-lg bg-slate-200"
/>
))}
</div>
);
return <TableSkeleton rows={5} columns={5} />;
}

if (error) {
Expand Down
Loading