96 lines
2.7 KiB
TypeScript
Raw Normal View History

"use client";
import React from "react";
import { Skeleton } from "@/components/atoms/loading-skeleton";
import { ErrorState } from "@/components/atoms/error-state";
import { getErrorMessage } from "@/shared/utils";
interface AsyncBlockProps {
isLoading?: boolean;
error?: unknown;
loadingText?: string;
variant?: "page" | "card" | "inline";
children: React.ReactNode;
}
export function AsyncBlock({
isLoading,
error,
loadingText,
variant = "card",
children,
}: AsyncBlockProps) {
if (isLoading) {
if (variant === "page") {
return (
<div className="py-8" aria-busy="true" aria-live="polite">
<div className="max-w-5xl mx-auto px-4 sm:px-6 md:px-8 space-y-6">
{loadingText ? <p className="text-sm text-muted-foreground">{loadingText}</p> : null}
<div className="flex items-center gap-3">
<Skeleton className="h-8 w-8 rounded-full" />
<div className="space-y-2">
<Skeleton className="h-6 w-48" />
<Skeleton className="h-4 w-64" />
</div>
</div>
<div className="space-y-4">
{Array.from({ length: 3 }).map((_, i) => (
<div
key={i}
className="bg-card border border-border rounded-lg p-4 shadow-[var(--cp-shadow-1)]"
>
<Skeleton className="h-4 w-1/2 mb-2" />
<Skeleton className="h-3 w-3/4" />
</div>
))}
</div>
</div>
</div>
);
}
return (
<div className="space-y-3" aria-busy="true" aria-live="polite">
{loadingText ? <p className="text-sm text-muted-foreground">{loadingText}</p> : null}
<Skeleton className="h-4 w-40" />
<Skeleton className="h-3 w-3/5" />
<Skeleton className="h-3 w-2/5" />
</div>
);
}
if (error) {
// Map variant to ErrorState variant (they're the same values)
const errorVariantMap = {
page: "page",
card: "card",
inline: "inline",
} as const;
return (
<ErrorState
title={"Unable to load"}
message={getErrorMessage(error)}
variant={errorVariantMap[variant]}
/>
);
}
return <>{children}</>;
}
export type { AsyncBlockProps };
// Preset helpers
type PresetProps = Omit<AsyncBlockProps, "variant">;
export function PageAsync(props: PresetProps) {
return <AsyncBlock variant="page" {...props} />;
}
export function CardAsync(props: PresetProps) {
return <AsyncBlock variant="card" {...props} />;
}
export function InlineAsync(props: PresetProps) {
return <AsyncBlock variant="inline" {...props} />;
}