Skip to content

Commit 3e996c2

Browse files
committed
feat(types, lib): add zod schemas for resource and feedback validation, implement date formatting utility
1 parent 4a161c5 commit 3e996c2

File tree

4 files changed

+72
-4
lines changed

4 files changed

+72
-4
lines changed

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@
2222
"next-themes": "^0.4.6",
2323
"react": "^18.3.1",
2424
"react-dom": "^18.3.1",
25-
"react-hook-form": "^7.55.0",
26-
"zod": "^3.24.2",
25+
"react-hook-form": "^7.56.1",
26+
"zod": "^3.24.3",
2727
"zustand": "5.0.3"
2828
},
2929
"devDependencies": {

src/lib/dates.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
export const formatDate = (dateStr: string) => {
2+
const date = new Date(dateStr);
3+
if (isNaN(date.getTime())) return "Invalid Date";
4+
5+
return new Intl.DateTimeFormat("es-ES", {
6+
year: "numeric",
7+
month: "2-digit",
8+
day: "2-digit",
9+
}).format(date);
10+
};

src/lib/zod.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { z } from "zod";
2+
3+
export const resourceSchema = z.object({
4+
name: z
5+
.string()
6+
.min(1, "Name is required")
7+
.max(50, "Name must be less than 50 characters"),
8+
url: z.string().max(1000, "URL must be less than 1000 characters"),
9+
description: z
10+
.string()
11+
.max(1000, "Description must be less than 1000 characters")
12+
.optional(),
13+
image: z
14+
.instanceof(File)
15+
.refine((file) => file.size <= 1024 * 1024, {
16+
message: "Image size must be less than 1MB.",
17+
})
18+
.refine((file) => file.type === "image/webp", {
19+
message: "Image must be a .webp file.",
20+
})
21+
.refine((file) => file.name.endsWith(".webp"), {
22+
message: "Image must be a .webp file.",
23+
}),
24+
tags: z.array(z.string()).max(5, "Tags must be less than 5 items"),
25+
category: z.string().max(10, "Category must be less than 10 characters"),
26+
});
27+
28+
export const feedbackSchema = z.object({
29+
name: z
30+
.string({ required_error: "Name is required" })
31+
.min(2, { message: "Name must be at least 2 characters long." })
32+
.max(50, { message: "Name must not exceed 50 characters." }),
33+
email: z
34+
.string({ required_error: "Email is required" })
35+
.min(1, "Email is required")
36+
.email("Invalid email"),
37+
message: z
38+
.string({ required_error: "Message is required" })
39+
.min(10, { message: "Message must be at least 10 characters long." })
40+
.max(1000, { message: "Message must not exceed 1000 characters." }),
41+
});

src/types/index.ts

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import { z } from "zod";
2+
import { feedbackSchema, resourceSchema } from "@/lib/zod";
3+
14
// Supabase Types
25

36
export type User = {
@@ -22,11 +25,25 @@ export type Resource = {
2225
name: string;
2326
slug: string;
2427
url: string;
25-
description: string;
28+
description?: string;
2629
image: string;
2730
tags: string[];
2831
author: string;
29-
category: Omit<Category, "id" | "created_at">;
32+
category: Category;
3033
status: "pending" | "approved" | "rejected";
3134
created_at: string;
3235
};
36+
37+
export type CreateResourceInput = Omit<Resource, "id" | "created_at">;
38+
39+
export type UpdateResourceInput = Partial<
40+
Omit<Resource, "id" | "created_at">
41+
> & {
42+
id: string;
43+
};
44+
45+
// Zod Types
46+
47+
export type ResourceForm = z.infer<typeof resourceSchema>;
48+
49+
export type FeedbackForm = z.infer<typeof feedbackSchema>;

0 commit comments

Comments
 (0)