mirror of
https://github.com/OwethuManagedServices/oms-website-nextjs.git
synced 2025-12-17 17:18:09 +00:00
feature: create post
This commit is contained in:
160
components/ContactForm.tsx
Normal file
160
components/ContactForm.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
@ -20,10 +20,18 @@ export default function CreatePostForm() {
|
||||
// Use useActionState from React
|
||||
const [state, dispatch] = useActionState(createPost, initialState);
|
||||
|
||||
// Helper to get default value or empty string
|
||||
// Helper to get default value or empty string, ensuring string return type
|
||||
const getPreviousInput = (
|
||||
key: keyof NonNullable<CreatePostState["previousInput"]>
|
||||
) => state.previousInput?.[key] ?? "";
|
||||
): string => {
|
||||
const value = state.previousInput?.[key];
|
||||
// Ensure the return value is always a string for text/textarea defaultValue
|
||||
if (typeof value === "string") {
|
||||
return value;
|
||||
}
|
||||
// Return empty string for non-string types (like boolean) or null/undefined
|
||||
return "";
|
||||
};
|
||||
|
||||
return (
|
||||
// Remove encType="multipart/form-data"
|
||||
|
||||
Reference in New Issue
Block a user