11"use client" ;
22import React , { useState } from "react" ;
3+ import { motion } from "framer-motion"
34
45export default function AdminBlogForm ( ) {
56 const [ title , setTitle ] = useState ( "" ) ;
67 const [ content , setContent ] = useState ( "" ) ;
8+ const [ isSubmitting , setIsSubmitting ] = useState ( false ) ;
9+ const [ message , setMessage ] = useState < string | null > ( null ) ;
710
811 async function onSubmit ( e : React . FormEvent ) {
912 e . preventDefault ( ) ;
13+ setIsSubmitting ( true ) ;
14+ setMessage ( null ) ;
15+
16+ try {
17+ const res = await fetch ( "/api/admin/blogs" , {
18+ method : "POST" ,
19+ headers : { "Content-Type" : "application/json" } ,
20+ body : JSON . stringify ( { title, content, published : true } ) ,
21+ } ) ;
22+
23+ if ( ! res . ok ) {
24+ setMessage ( await res . text ( ) ) ;
25+ return ;
26+ }
1027
11- const res = await fetch ( "/api/admin/blogs" , {
12- method : "POST" ,
13- headers : { "Content-Type" : "application/json" } ,
14- body : JSON . stringify ( { title, content, published : true } ) ,
15- } ) ;
16- if ( ! res . ok ) alert ( await res . text ( ) ) ;
17- else {
1828 setTitle ( "" ) ;
1929 setContent ( "" ) ;
20- alert ( "Saved" ) ;
30+ setMessage ( "Blog succesfully saved!" ) ;
31+ } catch {
32+ setMessage ( "Something went wrong!" ) ;
33+ } finally {
34+ setIsSubmitting ( false ) ;
2135 }
22- }
36+ }
2337
2438 return (
25- < form onSubmit = { onSubmit } className = "space-y-2" >
26- < input value = { title } onChange = { e => setTitle ( e . target . value ) } placeholder = "Title" className = "border p-2 w-full" />
27- < textarea value = { content } onChange = { e => setContent ( e . target . value ) } placeholder = "Content" className = "border p-2 w-full" />
28- < button className = "border px-3 py-2" > Create</ button >
39+ < form onSubmit = { onSubmit } className = "space-y-4" >
40+ < motion . div
41+ initial = { { opacity : 0 , y : 12 } }
42+ animate = { { opacity : 1 , y : 0 } }
43+ transition = { { delay : 0.1 , duration : 0.4 } }
44+ >
45+ < label htmlFor = "title" className = "mb-2 block text-sm font-medium text-slate-700 dark:text-slate-300" >
46+ Title
47+ </ label >
48+ < input
49+ id = "title"
50+ value = { title }
51+ onChange = { ( e ) => setTitle ( e . target . value ) }
52+ placeholder = "Title..."
53+ required
54+ className = "w-full rounded-xl border border-slate-300 bg-white/90 px-4 py-3 text-slate-900 outline-none ring-blue-300 transition placeholder:text-slate-400 focus:ring-2 dark:border-slate-800 dark:bg-slate-950/60 dark:text-slate-100"
55+ />
56+ </ motion . div >
57+
58+ < motion . div
59+ initial = { { opacity : 0 , y : 12 } }
60+ animate = { { opacity : 1 , y : 0 } }
61+ transition = { { delay : 0.1 , duration : 0.4 } }
62+ >
63+ < label htmlFor = "content" className = "mb-2 block text-sm font-medium text-slate-700 dark:text-slate-300" >
64+ Content
65+ </ label >
66+ < textarea
67+ id = "content"
68+ value = { content }
69+ onChange = { ( e ) => setContent ( e . target . value ) }
70+ placeholder = "Content..."
71+ required
72+ className = "w-full rounded-xl border border-slate-300 bg-white/90 px-4 py-3 text-slate-900 outline-none ring-blue-300 transition placeholder:text-slate-400 focus:ring-2 dark:border-slate-800 dark:bg-slate-950/60 dark:text-slate-100"
73+ />
74+ </ motion . div >
75+
76+ { message ? (
77+ < p className = "text-sm text-slate-600 dark:text-slate-300" > { message } </ p >
78+ ) : null }
79+
80+ < motion . button
81+ type = "submit"
82+ disabled = { isSubmitting }
83+ whileHover = { { scale : 1.02 } }
84+ whileTap = { { scale : 0.98 } }
85+ className = "inline-flex items-center justify-center rounded-full border border-slate-200 bg-slate-900 px-5 py-2 text-sm font-medium text-white shadow-lg transition hover:bg-slate-800 disabled:cursor-not-allowed disabled:opacity-60 dark:border-slate-700 dark:bg-slate-800 dark:hover:bg-slate-700" >
86+ { isSubmitting ? "Saving..." : "Create Blog" }
87+ </ motion . button >
2988 </ form >
3089 ) ;
3190}
0 commit comments