-
Notifications
You must be signed in to change notification settings - Fork 0
/
page.tsx
136 lines (124 loc) · 3.76 KB
/
page.tsx
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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
/* eslint-disable @next/next/no-img-element */
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { Container } from "@/components/ui/container";
import { Navbar } from "@/components/ui/navbar";
import { z } from "zod";
import { fromZodError } from "zod-validation-error";
import type { Metadata } from "next";
export const metadata: Metadata = {
title: "With zod",
};
const getData = async () => {
const resp = await fetch("https://dummyjson.com/products?limit=5").then(
(res) => res.json(),
);
const schema = z.object({
products: z.array(
z.object({
id: z.number(),
title: z.string(),
description: z.string(),
cost: z.number(), // should be `price` instead of `cost`
discountPercentage: z.number(),
rating: z.number(),
stock: z.number(),
brand: z.string(),
category: z.string(),
thumbnail: z.string(),
images: z.array(z.string()),
}),
),
total: z.number(),
skip: z.number(),
limit: z.number(),
});
const parsedData = schema.safeParse(resp);
if (!parsedData.success) {
const readable = fromZodError(parsedData.error);
return {
error: parsedData.error,
readableError: readable.toString(),
};
}
return {
data: parsedData.data,
};
};
export default async function Home() {
const { data, error, readableError } = await getData();
if (error) {
return (
<Card>
<CardHeader>
<CardTitle>Error</CardTitle>
</CardHeader>
<CardContent>
<h2 className="text-red-600 font-semibold mt-4">
This is error format with{" "}
<a
href="https://www.npmjs.com/package/zod-validation-error"
className="underline font-semibold"
>
zod-validation-error
</a>
</h2>
<pre className="mt-2 bg-red-100 p-4 rounded-md text-red-600 font-semibold whitespace-normal text-sm">
{JSON.stringify(readableError, null, 2)}
</pre>
<h2 className="text-red-600 font-semibold mt-5">
Original error from{" "}
<a href="https://zod.dev/" className="underline font-semibold">
zod
</a>
</h2>
<pre className="mt-2 bg-red-100 p-4 rounded-md text-red-600 font-semibold text-sm">
{JSON.stringify(error, null, 2)}
</pre>
</CardContent>
</Card>
);
}
return (
<Card>
<CardHeader>
<CardTitle>Products</CardTitle>
<CardDescription>
Manage your products and view their sales performance.
</CardDescription>
</CardHeader>
<CardContent>
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
{data.products.map((product) => (
<Card key={product.id}>
<CardHeader>
<CardTitle>{product.title}</CardTitle>
</CardHeader>
<CardContent>
<img
src={product.thumbnail}
alt={product.title}
className="w-full h-48 object-cover rounded-lg shadow-lg"
/>
<p className="font-bold mt-4 text-gray-800">
<span className="font-semibold">Price:</span> ${product.cost}
</p>
<div className="text-xs bg-red-100 text-red-600 p-2 mt-2 rounded-md">
{"It should be a `price` but it's a `cost` in the code."}
</div>
<p className="mt-2 text-sm text-gray-600">
{product.description}
</p>
</CardContent>
</Card>
))}
</div>
</CardContent>
</Card>
);
}