feature: create post

This commit is contained in:
libertyoms
2025-04-22 08:50:55 +02:00
parent a8c6b5297b
commit 43f867cfe4
8 changed files with 518 additions and 12 deletions

160
components/ContactForm.tsx Normal file
View File

@ -0,0 +1,160 @@
"use client";
import React, { useActionState, useEffect, useRef } from "react";
import { useFormStatus } from "react-dom";
import { submitContactForm, ContactFormState } from "@/actions/contact";
import Button from "@/components/ui/Button"; // Use your existing Button component
// Submit button component with pending state
function SubmitButton() {
const { pending } = useFormStatus();
return (
<Button type="submit" variant="primary" size="lg" disabled={pending}>
{pending ? "Sending..." : "Send Message"}
</Button>
);
}
// The main contact form component
export default function ContactForm() {
const initialState: ContactFormState = {
message: null,
errors: {},
success: false,
};
const [state, dispatch] = useActionState(submitContactForm, initialState);
const formRef = useRef<HTMLFormElement>(null); // Ref to reset the form
// Reset form on successful submission
useEffect(() => {
if (state.success) {
formRef.current?.reset();
}
}, [state.success]);
return (
<form ref={formRef} action={dispatch} className="space-y-6">
{/* Name Input */}
<div>
<label
htmlFor="name"
className="block text-sm font-medium text-foreground mb-1"
>
Full Name
</label>
<input
type="text"
id="name"
name="name"
required
className="block w-full px-4 py-2 border border-border rounded-lg shadow-sm focus:ring-primary focus:border-primary sm:text-sm bg-input text-foreground placeholder-muted-foreground"
aria-describedby="name-error"
/>
<div id="name-error" aria-live="polite" aria-atomic="true">
{state.errors?.name &&
state.errors.name.map((error: string) => (
<p className="mt-1 text-sm text-destructive" key={error}>
{error}
</p>
))}
</div>
</div>
{/* Email Input */}
<div>
<label
htmlFor="email"
className="block text-sm font-medium text-foreground mb-1"
>
Email Address
</label>
<input
type="email"
id="email"
name="email"
required
className="block w-full px-4 py-2 border border-border rounded-lg shadow-sm focus:ring-primary focus:border-primary sm:text-sm bg-input text-foreground placeholder-muted-foreground"
aria-describedby="email-error"
/>
<div id="email-error" aria-live="polite" aria-atomic="true">
{state.errors?.email &&
state.errors.email.map((error: string) => (
<p className="mt-1 text-sm text-destructive" key={error}>
{error}
</p>
))}
</div>
</div>
{/* Subject Input */}
<div>
<label
htmlFor="subject"
className="block text-sm font-medium text-foreground mb-1"
>
Subject
</label>
<input
type="text"
id="subject"
name="subject"
required
className="block w-full px-4 py-2 border border-border rounded-lg shadow-sm focus:ring-primary focus:border-primary sm:text-sm bg-input text-foreground placeholder-muted-foreground"
aria-describedby="subject-error"
/>
<div id="subject-error" aria-live="polite" aria-atomic="true">
{state.errors?.subject &&
state.errors.subject.map((error: string) => (
<p className="mt-1 text-sm text-destructive" key={error}>
{error}
</p>
))}
</div>
</div>
{/* Message Textarea */}
<div>
<label
htmlFor="message"
className="block text-sm font-medium text-foreground mb-1"
>
Your Message
</label>
<textarea
id="message"
name="message"
rows={5}
required
className="block w-full px-4 py-2 border border-border rounded-lg shadow-sm focus:ring-primary focus:border-primary sm:text-sm bg-input text-foreground placeholder-muted-foreground"
aria-describedby="message-error"
></textarea>
<div id="message-error" aria-live="polite" aria-atomic="true">
{state.errors?.message &&
state.errors.message.map((error: string) => (
<p className="mt-1 text-sm text-destructive" key={error}>
{error}
</p>
))}
</div>
</div>
{/* General Form Message (Success or Error) */}
<div id="form-response" aria-live="polite" aria-atomic="true">
{state.message && (
<p
className={`text-sm ${
state.success ? "text-green-600" : "text-destructive"
}`}
>
{state.message}
</p>
)}
</div>
{/* Submit Button */}
<div className="pt-2">
<SubmitButton />
</div>
</form>
);
}