turash/bugulma/frontend/components/ui/DataCard.tsx
2025-12-15 10:06:41 +01:00

80 lines
2.4 KiB
TypeScript

import React from 'react';
import { useCommonTranslations } from '@/hooks/useCommonTranslations';
import { getIconClasses } from '@/lib/icons';
import { spacing } from '@/lib/spacing';
import Badge from '@/components/ui/Badge';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/Card';
import Spinner from '@/components/ui/Spinner';
interface DataCardProps<T> {
title: string;
data?: T[] | null;
count?: number;
isLoading?: boolean;
error?: Error | null;
emptyMessage?: string;
loadingMessage?: string;
errorMessage?: string;
countBadge?: boolean;
children?: (data: T[]) => React.ReactNode;
renderItem?: (item: T, index: number) => React.ReactNode;
}
function DataCard<T>({
title,
data,
count,
isLoading = false,
error,
emptyMessage,
loadingMessage,
errorMessage,
countBadge = true,
children,
renderItem,
}: DataCardProps<T>) {
const { common } = useCommonTranslations();
const defaultEmptyMessage = common.noData;
const defaultLoadingMessage = common.loading;
const defaultErrorMessage = common.error;
return (
<Card>
<CardHeader>
<div className="flex items-center justify-between">
<CardTitle>{title}</CardTitle>
{countBadge && count !== undefined && !isLoading && !error && (
<Badge variant="outline">{count}</Badge>
)}
</div>
</CardHeader>
<CardContent>
{isLoading ? (
<div className="flex items-center justify-center py-8">
<Spinner className={`${getIconClasses('lg')} mr-3`} />
<span className="text-muted-foreground">{loadingMessage || defaultLoadingMessage}</span>
</div>
) : error ? (
<div className="text-center py-8 text-destructive">
<p className="font-medium">{errorMessage || defaultErrorMessage}</p>
<p className="text-sm mt-1">{error.message}</p>
</div>
) : !data || data.length === 0 ? (
<div className="text-center py-8 text-muted-foreground">
<p>{emptyMessage || defaultEmptyMessage}</p>
</div>
) : children ? (
children(data)
) : renderItem ? (
<div className={spacing.content}>
{data.map((item, index) => renderItem(item, index))}
</div>
) : null}
</CardContent>
</Card>
);
}
export default React.memo(DataCard) as <T>(props: DataCardProps<T>) => React.JSX.Element;