-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathDataRenderer.tsx
More file actions
121 lines (112 loc) · 2.55 KB
/
Copy pathDataRenderer.tsx
File metadata and controls
121 lines (112 loc) · 2.55 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
import Image from "next/image";
import Link from "next/link";
import { DEFAULT_EMPTY, DEFAULT_ERROR } from "@/constants/states";
import { Button } from "./ui/button";
interface Props<T> {
success: boolean;
error?: {
message: string;
details?: Record<string, string[]>;
};
data: T[] | null | undefined;
empty: {
title: string;
message: string;
button?: {
text: string;
href: string;
};
};
render: (data: T[]) => React.ReactNode;
}
interface StateSkeletonProps {
image: {
light: string;
dark: string;
alt: string;
};
title: string;
message: string;
button?: {
text: string;
href: string;
};
}
const StateSkeleton = ({
image,
title,
message,
button,
}: StateSkeletonProps) => (
<div className="mt-16 flex w-full flex-col items-center justify-center sm:mt-20">
<>
<Image
src={image.light}
alt={image.alt}
width={270}
height={200}
className="block object-contain dark:hidden"
/>
<Image
src={image.dark}
alt={image.alt}
width={270}
height={200}
className="hidden object-contain dark:block"
/>
</>
<h2 className="h2-bold text-dark200_light900 mt-8">{title}</h2>
<p className="body-regular text-dark500_light700 my-3.5 max-w-md text-center">
{message}
</p>
{button && (
<Link href={button.href}>
<Button className="paragraph-medium bg-primary-500 text-light-900 hover:bg-primary-500 mt-5 min-h-[46px] rounded-lg px-4 py-3">
{button.text}
</Button>
</Link>
)}
</div>
);
const DataRenderer = <T,>({
success,
error,
data,
empty = DEFAULT_EMPTY,
render,
}: Props<T>) => {
if (!success) {
return (
<StateSkeleton
image={{
light: "/images/light-error.png",
dark: "/images/dark-error.png",
alt: "Error illustration",
}}
title={error?.message || DEFAULT_ERROR.title}
message={
error?.details
? JSON.stringify(error.details, null, 2)
: DEFAULT_ERROR.message
}
button={empty.button}
/>
);
}
if (!data || data.length === 0) {
return (
<StateSkeleton
image={{
light: "/images/light-illustration.png",
dark: "/images/dark-illustration.png",
alt: "Empty state illustration",
}}
title={empty.title}
message={empty.message}
button={empty.button}
/>
);
}
return <>{render(data)}</>;
};
export default DataRenderer;