Vendaweb-portal/components/NoData.tsx

117 lines
3.3 KiB
TypeScript

import React from "react";
import {
Empty,
EmptyContent,
EmptyDescription,
EmptyHeader,
EmptyMedia,
EmptyTitle,
} from "./ui/empty";
import {
IconFolderCode,
IconFileX,
IconSearch,
IconInbox,
IconDatabaseOff,
IconClipboardX,
} from "@tabler/icons-react";
import { ArrowUpRightIcon } from "lucide-react";
interface NoDataProps {
title?: string;
description?: string;
icon?:
| "search"
| "file"
| "inbox"
| "folder"
| "database"
| "clipboard"
| React.ReactNode;
action?: React.ReactNode;
variant?: "default" | "outline" | "muted" | "gradient";
showLearnMore?: boolean;
learnMoreHref?: string;
learnMoreText?: string;
}
const NoData: React.FC<NoDataProps> = ({
title = "Nenhum resultado encontrado",
description = "Não foram encontrados registros com os filtros informados. Tente ajustar os parâmetros de pesquisa.",
icon = "search",
action,
variant = "outline",
showLearnMore = false,
learnMoreHref = "#",
learnMoreText = "Saiba mais",
}) => {
const getIcon = () => {
if (React.isValidElement(icon)) {
return icon;
}
const iconClass = "h-10 w-10 text-slate-400";
switch (icon) {
case "file":
return <IconFileX className={iconClass} stroke={1.5} />;
case "inbox":
return <IconInbox className={iconClass} stroke={1.5} />;
case "folder":
return <IconFolderCode className={iconClass} stroke={1.5} />;
case "database":
return <IconDatabaseOff className={iconClass} stroke={1.5} />;
case "clipboard":
return <IconClipboardX className={iconClass} stroke={1.5} />;
case "search":
default:
return <IconSearch className={iconClass} stroke={1.5} />;
}
};
const getVariantClasses = () => {
const baseClasses = "min-h-[450px] w-full";
switch (variant) {
case "outline":
return `${baseClasses} border-2 border-dashed border-slate-200 bg-white`;
case "muted":
return `${baseClasses} bg-gradient-to-b from-slate-50/80 via-white to-white`;
case "gradient":
return `${baseClasses} bg-gradient-to-br from-slate-50 via-blue-50/30 to-white border border-slate-100`;
default:
return `${baseClasses} bg-white`;
}
};
return (
<Empty className={getVariantClasses()}>
<EmptyHeader>
<EmptyMedia variant="icon" className="mb-6">
<div className="flex h-20 w-20 items-center justify-center rounded-2xl bg-gradient-to-br from-slate-50 to-slate-100 border border-slate-200/50 shadow-sm">
{getIcon()}
</div>
</EmptyMedia>
<EmptyTitle className="text-xl font-black text-slate-900 mb-3">
{title}
</EmptyTitle>
<EmptyDescription className="text-sm text-slate-600 max-w-md leading-relaxed">
{description}
</EmptyDescription>
</EmptyHeader>
{action && <EmptyContent className="mt-8">{action}</EmptyContent>}
{showLearnMore && (
<a
href={learnMoreHref}
className="mt-6 inline-flex items-center gap-1 text-sm font-medium text-slate-500 hover:text-[#002147] transition-colors"
>
{learnMoreText}
<ArrowUpRightIcon className="h-4 w-4" />
</a>
)}
</Empty>
);
};
export default NoData;