8
Fullstack

Contact Form

A comprehensive full-stack contact form component with email functionality, admin dashboard, and message management built on top of AxionJS.

Contact Form

A full-stack contact form solution that provides form validation, email sending capabilities, database storage, and an admin dashboard for managing messages. Built with Next.js Server Actions and modern React patterns.

Contact Form with Admin Dashboard
Loading component registry...

This component streamlines communication by capturing inquiries efficiently and providing tools for effective follow-up, all powered by Next.js Server Actions.

Features

Server Actions

Utilizes Next.js Server Actions for secure and efficient backend operations.

Dual Validation

Robust client-side and server-side validation using Zod for data integrity.

Email & DB Integration

Automated email notifications and persistent message storage in PostgreSQL.

Admin Email

Admins receive instant notifications for new messages, ensuring timely responses.

Installation

Install the Component

Terminal
npx axionjs-ui add contact-form

This command installs the contact form system, including frontend components, server actions, and database configurations.

Configure Environment Variables

Update your .env file with necessary credentials:

# Database
DATABASE_URL="your-postgresql-connection-string"

# Email Configuration
EMAIL_SERVER_HOST="smtp.gmail.com"
EMAIL_SERVER_PORT="587"
EMAIL_SERVER_USER="your-email@gmail.com"
EMAIL_SERVER_PASSWORD="your-app-password" # Use app-specific password for Gmail
ADMIN_EMAIL="admin@yourdomain.com" # Email to receive notifications
EMAIL_FROM="Your App Name <noreply@yourdomain.com>" # Sender email address

Database Setup

The component uses Prisma. Add the following schema to your schema.prisma file.

schema.prisma
model ContactMessage {
  id        String   @id @default(cuid())
  name      String
  email     String
  message   String
  status    String   @default("UNREAD") // e.g., UNREAD, READ, ARCHIVED
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
 
  @@index([email])
  @@index([status])
  @@index([createdAt])
}

Run Database Migrations

Apply the schema changes to your database:

Terminal
npx prisma db push

Libraries Used

This component leverages several modern libraries and frameworks:

  • Next.js 14+: App Router with Server Actions
  • React Hook Form: Form state management and validation
  • Zod: Schema validation for both client and server
  • Prisma: Database ORM for PostgreSQL
  • Nodemailer: Email sending functionality
  • Lucide React: Modern icon library
  • date-fns: Date formatting utilities
  • Tailwind CSS: Utility-first CSS framework

Usage

Embed the contact form in any page.

app/contact/page.tsx
import ContactForm from "@/components/contact-form";
 
export default function ContactPage() {
  return (
    <main className="min-h-screen flex items-center justify-center">
      <ContactForm />
    </main>
  );
}

Component Structure

The contact form system consists of several interconnected components:

Core Components

  • ContactForm: Main form component with validation
  • MessageList: Admin interface for managing messages
  • Admin Dashboard: Overview of message statistics

Hooks

  • useContactForm: Form state management and submission logic
  • useMessageList: Message management operations

Server Actions (actions/contact-actions.ts)

  • sendEmail: Handles form submission and email sending
  • getMessages: Retrieves messages from database
  • updateMessageStatus: Updates message read/unread status
  • deleteMessage: Removes messages from database
  • getUnreadMessageCounts: Gets count of unread messages
  • getTotalMessageCount: Gets total message count

Customization

Customize form elements using Tailwind CSS.

components/contact-form.tsx
// Customize form appearance
<Input
  placeholder="Your name"
  className="h-12 bg-background border-blue-500 focus:ring-blue-500"
  {...field}
/>

Configuration Options

Form Behavior

You can customize form behavior by modifying the useContactForm hook parameters.

const form = useForm<FormValues>({
  resolver: zodResolver(formSchema),
  defaultValues: {
    name: "",
    email: "",
    message: "",
  },
  mode: "onChange", // Validate on change
});

Database Schema

Extend the ContactMessage model in schema.prisma as needed.

schema.prisma
model ContactMessage {
  id        String   @id @default(cuid())
  name      String
  email     String
  phone     String?  // Optional phone field
  company   String?  // Optional company field
  message   String
  status    String   @default("UNREAD")
  priority  String   @default("NORMAL") // Add priority field
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
}

Remember to run npx prisma db push after modifying your schema.

Admin Dashboard Features

Message Management

  • Status Tracking: Mark messages as read/unread
  • Filtering: Filter messages by status (all, unread, read)
  • Bulk Operations: Delete multiple messages
  • Search: Search through messages (can be extended)

Dashboard Metrics

The admin dashboard displays:

  • Total message count
  • Unread message count
  • Recent activity overview

Error Handling

The component includes comprehensive error handling:

Client-Side Errors

try {
  const result = await sendEmail(data);
  if (result.success) {
    // Success handling
  } else {
    toast({
      title: "Failed to send",
      description: result.error,
      variant: "destructive",
    });
  }
} catch (error) {
  // Network error handling
}

Server-Side Errors

export async function sendEmail(data: unknown) {
  try {
    // Validation
    const result = formSchema.safeParse(data);
    if (!result.success) {
      return { success: false, error: "Invalid form data" };
    }
    
    // Database and email operations
    // ...
    
    return { success: true };
  } catch (error) {
    console.error("Error:", error);
    return { success: false, error: "Server error occurred" };
  }
}

Security Considerations

Ensure proper security measures are in place for production use.

Email Security

  • Use app-specific passwords for Gmail
  • Store credentials securely in environment variables
  • Implement rate limiting for form submissions

Data Validation

  • Server-side validation is always performed
  • Input sanitization prevents XSS attacks
  • SQL injection protection via Prisma ORM

Access Control (Admin Routes)

Protect your admin dashboard using authentication.

app/admin/layout.tsx or middleware.ts
// Add authentication to admin routes
import { auth } from "@/lib/auth";
 
export default async function AdminLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  const session = await auth();
  
  if (!session?.user?.isAdmin) {
    redirect("/login");
  }
  
  return <>{children}</>;
}

Troubleshooting

Common Issues

Email not sending:

  • Verify SMTP credentials
  • Check email server settings
  • Ensure app passwords are used for Gmail

Database connection issues:

  • Verify DATABASE_URL format
  • Check database permissions
  • Run Prisma migrations

Form validation errors:

  • Check Zod schema configuration
  • Verify form field naming consistency
  • Ensure proper error handling

Debugging

Enable debug logging:

// Add to your environment variables
DEBUG=nodemailer:*

API Reference

Server Actions

PropTypeDefault
sendEmail
async (data: FormData) => Promise<{ success: boolean; error?: string }>
-
getMessages
async () => Promise<ContactMessage[]>
-
updateMessageStatus
async (id: string, status: string) => Promise<ContactMessage | { error: string }>
-
deleteMessage
async (id: string) => Promise<{ success: boolean; error?: string }>
-
getUnreadMessageCount
async () => Promise<number>
-

Hooks

PropTypeDefault
useContactForm()
() => { form: UseFormReturn; onSubmit: (data: FormValues) => Promise<void>; isPending: boolean; isSuccess: boolean; }
-
useMessageList(initialMessages: Message[])
(initialMessages: ContactMessage[]) => { /* ...return values... */ }
-

This contact form component provides a complete solution for handling user inquiries with professional email integration and admin management capabilities. The modular design allows for easy customization while maintaining robust functionality.