import type { ReactNode } from "react";
import Link from "next/link";
import { ArrowLeftIcon } from "@heroicons/react/24/outline";
import { Skeleton } from "@/components/atoms/loading-skeleton";
import { ErrorState } from "@/components/atoms/error-state";
interface PageLayoutProps {
icon?: ReactNode | undefined;
title: string;
description?: string | undefined;
actions?: ReactNode | undefined;
backLink?: { label: string; href: string } | undefined;
statusPill?: ReactNode | undefined;
loading?: boolean | undefined;
loadingFallback?: ReactNode | undefined;
error?: Error | string | null | undefined;
onRetry?: (() => void) | undefined;
children: ReactNode;
}
export function PageLayout({
icon,
title,
description,
actions,
backLink,
statusPill,
loading = false,
loadingFallback,
error = null,
onRetry,
children,
}: PageLayoutProps) {
return (
{/* Page header */}
{backLink && (
)}
{icon && (
{icon}
)}
{title}
{statusPill}
{description && (
{description}
)}
{actions && (
{actions}
)}
{/* Content */}
{renderPageContent({
loading,
error: error ?? undefined,
children,
onRetry,
loadingFallback,
})}
);
}
function renderPageContent({
loading,
error,
children,
onRetry,
loadingFallback,
}: {
loading: boolean | undefined;
error: Error | string | undefined;
children: React.ReactNode;
onRetry: (() => void) | undefined;
loadingFallback: React.ReactNode;
}): React.ReactNode {
if (loading) {
return loadingFallback ?? ;
}
if (error) {
return ;
}
return children;
}
function PageLoadingState() {
return (
{Array.from({ length: 3 }).map((_, i) => (
))}
);
}
interface PageErrorStateProps {
error: Error | string;
onRetry?: (() => void) | undefined;
}
function PageErrorState({ error, onRetry }: PageErrorStateProps) {
const errorMessage = typeof error === "string" ? error : error.message;
return (
);
}