- Implemented FormStep component for user input (name, email, address). - Created OtpStep component for OTP verification. - Developed SuccessStep component to display success messages based on account creation. - Introduced eligibility-check.store for managing state throughout the eligibility check process. - Added commitlint configuration for standardized commit messages. - Configured knip for workspace management and project structure.
96 lines
2.7 KiB
TypeScript
96 lines
2.7 KiB
TypeScript
"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} />;
|
|
}
|