refactor: shared skeleton for table

This commit is contained in:
nams1570 2026-07-14 10:35:36 -07:00
parent be619368fc
commit 970abc0f03
3 changed files with 17 additions and 23 deletions

View File

@ -9,6 +9,7 @@ import {
ActionCell,
Alert,
AvatarCell,
AvatarCellSkeleton,
Badge,
Button,
Checkbox,
@ -1552,11 +1553,11 @@ function ProductCustomersSection({ productId, product }: ProductCustomersSection
width: 200,
renderCell: ({ row }) => (
row.customerType === 'user' ? (
<Suspense fallback={<CustomerAvatarSkeleton />}>
<Suspense fallback={<AvatarCellSkeleton />}>
<UserCell userId={row.customerId} />
</Suspense>
) : row.customerType === 'team' ? (
<Suspense fallback={<CustomerAvatarSkeleton />}>
<Suspense fallback={<AvatarCellSkeleton />}>
<TeamCell teamId={row.customerId} />
</Suspense>
) : (
@ -1643,15 +1644,6 @@ function ProductCustomersSection({ productId, product }: ProductCustomersSection
);
}
function CustomerAvatarSkeleton() {
return (
<div className="flex items-center gap-2">
<Skeleton className="h-6 w-6 shrink-0 rounded-full" />
<Skeleton className="h-4 w-24" />
</div>
);
}
function CustomerRowActions({ customerType, customerId }: { customerType: string, customerId: string }) {
const adminApp = useAdminApp();
return (

View File

@ -5,7 +5,7 @@
'use client';
import { useAdminApp } from '@/app/(main)/(protected)/projects/[projectId]/use-admin-app';
import { ActionCell, ActionDialog, Alert, AlertDescription, AvatarCell, Badge, Input, Label, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, SimpleTooltip, Skeleton } from '@/components/ui';
import { ActionCell, ActionDialog, Alert, AlertDescription, AvatarCell, AvatarCellSkeleton, Badge, Input, Label, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, SimpleTooltip } from '@/components/ui';
import type { Icon as PhosphorIcon } from '@phosphor-icons/react';
import { ArrowClockwiseIcon, ArrowCounterClockwiseIcon, GearIcon, ProhibitIcon, QuestionIcon, ReceiptXIcon, ShoppingCartIcon, ShuffleIcon } from '@phosphor-icons/react';
import { DataGrid, DataGridToolbar, useDataGridUrlState, useDataSource, type DataGridColumnDef, type DataGridDataSource, type DataGridExportField, type DataGridExportScope } from '@hexclave/dashboard-ui-components';
@ -153,15 +153,6 @@ function TeamAvatarCell({ teamId }: { teamId: string }) {
);
}
function CustomerAvatarSkeleton() {
return (
<div className="flex items-center gap-2 max-w-40">
<Skeleton className="h-6 w-6 shrink-0 rounded-full" />
<Skeleton className="h-4 w-24" />
</div>
);
}
function pickChargedAmountDisplay(entry: MoneyTransferEntry | undefined): string {
if (!entry) {
return '—';
@ -521,14 +512,14 @@ function TransactionTableBody(props: {
const summary = summaryByIdRef.current.get(row.id);
if (summary?.customerType === 'user' && summary.customerId) {
return (
<Suspense fallback={<CustomerAvatarSkeleton />}>
<Suspense fallback={<AvatarCellSkeleton className="max-w-40" />}>
<UserAvatarCell userId={summary.customerId} />
</Suspense>
);
}
if (summary?.customerType === 'team' && summary.customerId) {
return (
<Suspense fallback={<CustomerAvatarSkeleton />}>
<Suspense fallback={<AvatarCellSkeleton className="max-w-40" />}>
<TeamAvatarCell teamId={summary.customerId} />
</Suspense>
);

View File

@ -6,6 +6,7 @@ import { Badge } from "../badge";
import { Button } from "../button";
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger } from "../dropdown-menu";
import { SimpleTooltip } from "../simple-tooltip";
import { Skeleton } from "../skeleton";
import { cn } from "@/lib/utils";
export function TextCell(props: { children: React.ReactNode, size?: number, icon?: React.ReactNode }) {
@ -55,6 +56,16 @@ export function AvatarCell(props: { src?: string, fallback?: string }) {
);
}
/** Loading placeholder matching AvatarCell + adjacent label layout. */
export function AvatarCellSkeleton(props: { className?: string }) {
return (
<div className={cn("flex items-center gap-2", props.className)}>
<Skeleton className="h-6 w-6 shrink-0 rounded-full" />
<Skeleton className="h-4 w-24" />
</div>
);
}
export function DateCell(props: { date: Date, ignoreAfterYears?: number }) {
const ignore = !!props.ignoreAfterYears && new Date(new Date().setFullYear(new Date().getFullYear() + props.ignoreAfterYears)) < props.date;
const timeString = props.date.toLocaleTimeString([], { year: 'numeric', month: 'numeric', day: 'numeric', hour: '2-digit', minute: '2-digit' });