diff --git a/frontend/package.json b/frontend/package.json index fc1d6d4a..799ade9e 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -20,7 +20,7 @@ ] }, "dependencies": { - "@hookform/resolvers": "^3.3.4", + "@hookform/resolvers": "^3.5.0", "@tsparticles/react": "^3.0.0", "axios": "^1.6.1", "class-variance-authority": "^0.7.0", @@ -28,14 +28,14 @@ "lucide-react": "^0.292.0", "react": "^18.2.0", "react-dom": "^18.2.0", - "react-hook-form": "^7.51.2", + "react-hook-form": "^7.51.5", "react-router-dom": "^6.18.0", "react-tag-input": "^6.8.1", "react-toastify": "^9.1.3", "tailwind-merge": "^2.0.0", "tailwindcss-animate": "^1.0.7", "tsparticles": "^3.4.0", - "zod": "^3.22.4" + "zod": "^3.23.8" }, "devDependencies": { "@babel/preset-env": "^7.23.6", diff --git a/frontend/src/lib/types.ts b/frontend/src/lib/types.ts index adb164b8..881ab694 100644 --- a/frontend/src/lib/types.ts +++ b/frontend/src/lib/types.ts @@ -28,7 +28,14 @@ export const signUpSchema = z message: 'Confirm Password do not match', path: ['confirmPassword'], }); - +export const addBlogSchema = z.object({ + title: z.string().min(3), + authorName: z.string().min(3), + imageLink: z.string().url(), + categories: z.array(z.string()).min(1), + description: z.string().min(10), + isFeaturedPost: z.boolean(), +}); export interface AuthData { _id: string; role: string; @@ -38,3 +45,4 @@ export interface AuthData { export type TSignInSchema = z.infer; export type TSignUpSchema = z.infer; +export type TAddBlogScheme = z.infer; diff --git a/frontend/src/pages/add-blog.tsx b/frontend/src/pages/add-blog.tsx index a01c5353..3a7d40dc 100644 --- a/frontend/src/pages/add-blog.tsx +++ b/frontend/src/pages/add-blog.tsx @@ -1,4 +1,4 @@ -import { ChangeEvent, FormEvent, useState, useEffect } from 'react'; +import { useState, useEffect } from 'react'; import { useNavigate } from 'react-router-dom'; import { toast } from 'react-toastify'; import 'react-toastify/dist/ReactToastify.css'; @@ -10,67 +10,61 @@ import { categories } from '@/utils/category-colors'; import userState from '@/utils/user-state'; import axiosInstance from '@/helpers/axios-instance'; import { AxiosError, isAxiosError } from 'axios'; +import { useForm } from 'react-hook-form'; +import { TAddBlogScheme, addBlogSchema } from '@/lib/types'; +import { zodResolver } from '@hookform/resolvers/zod'; -type FormData = { - title: string; - authorName: string; - imageLink: string; - categories: string[]; - description: string; - isFeaturedPost: boolean; -}; function AddBlog() { const [selectedImage, setSelectedImage] = useState(''); - + const { + register, + handleSubmit, + reset, + setValue, + formState: { errors }, + watch, + } = useForm({ + resolver: zodResolver(addBlogSchema), + defaultValues: { + title: '', + authorName: '', + imageLink: '', + categories: [], + description: '', + isFeaturedPost: false, + }, + }); + const formData = watch(); const handleImageSelect = (imageUrl: string) => { setSelectedImage(imageUrl); }; const [modal, setmodal] = useState(false); - const [formData, setFormData] = useState({ - title: '', - authorName: '', - imageLink: '', - categories: [], - description: '', - isFeaturedPost: false, - }); //checks the length of the categories array and if the category is already selected const isValidCategory = (category: string): boolean => { return formData.categories.length >= 3 && !formData.categories.includes(category); }; - const handleInputChange = (e: ChangeEvent) => { - const { name, value } = e.target; - setFormData({ ...formData, [name]: value }); - }; - const handleCategoryClick = (category: string) => { if (isValidCategory(category)) return; if (formData.categories.includes(category)) { - setFormData({ - ...formData, - categories: formData.categories.filter((cat) => cat !== category), - }); + setValue( + 'categories', + formData.categories.filter((cat) => cat !== category) + ); } else { - setFormData({ - ...formData, - categories: [...formData.categories, category], - }); + setValue('categories', [...formData.categories, category]); } }; const handleselector = () => { - setFormData({ - ...formData, - imageLink: selectedImage, - }); + setValue('imageLink', selectedImage); setmodal(false); }; const handleCheckboxChange = () => { - setFormData({ ...formData, isFeaturedPost: !formData.isFeaturedPost }); + setValue('isFeaturedPost', !formData.isFeaturedPost); }; const validateFormData = () => { if ( @@ -95,24 +89,15 @@ function AddBlog() { return true; }; - const handleSubmit = async (e: FormEvent) => { - e.preventDefault(); + const onSumbit = async () => { if (validateFormData()) { try { const postPromise = axiosInstance.post('/api/posts/', formData); - toast.promise(postPromise, { pending: 'Creating blog post...', success: { render() { - setFormData({ - title: '', - authorName: '', - imageLink: '', - categories: [], - description: '', - isFeaturedPost: false, - }); + reset(); navigate('/'); return 'Blog created successfully'; }, @@ -136,7 +121,7 @@ function AddBlog() { userState.removeUser(); console.error(error.response?.data?.message); } else { - console.error(error); + console.log(error); } } } @@ -170,15 +155,15 @@ function AddBlog() {
-
+
+ {errors.title && ( + + This field need Atleast three characters + + )}
@@ -206,27 +195,32 @@ function AddBlog() { Blog content