Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
141 changes: 17 additions & 124 deletions app/(dashboard)/page.tsx
Original file line number Diff line number Diff line change
@@ -1,130 +1,23 @@
import { Button } from '@/components/ui/button';
import { ArrowRight, CreditCard, Database } from 'lucide-react';
import { Terminal } from './terminal';
import { ContactForm } from '@/components/contact-form';

export default function HomePage() {
return (
<main>
<section className="py-20">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="lg:grid lg:grid-cols-12 lg:gap-8">
<div className="sm:text-center md:max-w-2xl md:mx-auto lg:col-span-6 lg:text-left">
<h1 className="text-4xl font-bold text-gray-900 tracking-tight sm:text-5xl md:text-6xl">
Build Your SaaS
<span className="block text-orange-500">Faster Than Ever</span>
</h1>
<p className="mt-3 text-base text-gray-500 sm:mt-5 sm:text-xl lg:text-lg xl:text-xl">
Launch your SaaS product in record time with our powerful,
ready-to-use template. Packed with modern technologies and
essential integrations.
</p>
<div className="mt-8 sm:max-w-lg sm:mx-auto sm:text-center lg:text-left lg:mx-0">
<a
href="https://vercel.com/templates/next.js/next-js-saas-starter"
target="_blank"
>
<Button
size="lg"
variant="outline"
className="text-lg rounded-full"
>
Deploy your own
<ArrowRight className="ml-2 h-5 w-5" />
</Button>
</a>
</div>
</div>
<div className="mt-12 relative sm:max-w-lg sm:mx-auto lg:mt-0 lg:max-w-none lg:mx-0 lg:col-span-6 lg:flex lg:items-center">
<Terminal />
</div>
</div>
<main className="flex min-h-screen flex-col">
<div className="flex-1">
<section className="flex items-center justify-center p-24">
<h1 className="text-4xl font-bold">Welcome to Next.js</h1>
</section>

{/* Contact Form Section */}
<ContactForm />
</div>

{/* Footer will go here */}
<footer className="bg-gray-100 dark:bg-gray-900 py-8 px-4">
<div className="max-w-7xl mx-auto text-center text-gray-600 dark:text-gray-400">
<p>&copy; 2024 Your Company. All rights reserved.</p>
</div>
</section>

<section className="py-16 bg-white w-full">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="lg:grid lg:grid-cols-3 lg:gap-8">
<div>
<div className="flex items-center justify-center h-12 w-12 rounded-md bg-orange-500 text-white">
<svg viewBox="0 0 24 24" className="h-6 w-6">
<path
fill="currentColor"
d="M14.23 12.004a2.236 2.236 0 0 1-2.235 2.236 2.236 2.236 0 0 1-2.236-2.236 2.236 2.236 0 0 1 2.235-2.236 2.236 2.236 0 0 1 2.236 2.236zm2.648-10.69c-1.346 0-3.107.96-4.888 2.622-1.78-1.653-3.542-2.602-4.887-2.602-.41 0-.783.093-1.106.278-1.375.793-1.683 3.264-.973 6.365C1.98 8.917 0 10.42 0 12.004c0 1.59 1.99 3.097 5.043 4.03-.704 3.113-.39 5.588.988 6.38.32.187.69.275 1.102.275 1.345 0 3.107-.96 4.888-2.624 1.78 1.654 3.542 2.603 4.887 2.603.41 0 .783-.09 1.106-.275 1.374-.792 1.683-3.263.973-6.365C22.02 15.096 24 13.59 24 12.004c0-1.59-1.99-3.097-5.043-4.032.704-3.11.39-5.587-.988-6.38-.318-.184-.688-.277-1.092-.278zm-.005 1.09v.006c.225 0 .406.044.558.127.666.382.955 1.835.73 3.704-.054.46-.142.945-.25 1.44-.96-.236-2.006-.417-3.107-.534-.66-.905-1.345-1.727-2.035-2.447 1.592-1.48 3.087-2.292 4.105-2.295zm-9.77.02c1.012 0 2.514.808 4.11 2.28-.686.72-1.37 1.537-2.02 2.442-1.107.117-2.154.298-3.113.538-.112-.49-.195-.964-.254-1.42-.23-1.868.054-3.32.714-3.707.19-.09.4-.127.563-.132zm4.882 3.05c.455.468.91.992 1.36 1.564-.44-.02-.89-.034-1.345-.034-.46 0-.915.01-1.36.034.44-.572.895-1.096 1.345-1.565zM12 8.1c.74 0 1.477.034 2.202.093.406.582.802 1.203 1.183 1.86.372.64.71 1.29 1.018 1.946-.308.655-.646 1.31-1.013 1.95-.38.66-.773 1.288-1.18 1.87-.728.063-1.466.098-2.21.098-.74 0-1.477-.035-2.202-.093-.406-.582-.802-1.204-1.183-1.86-.372-.64-.71-1.29-1.018-1.946.303-.657.646-1.313 1.013-1.954.38-.66.773-1.286 1.18-1.868.728-.064 1.466-.098 2.21-.098zm-3.635.254c-.24.377-.48.763-.704 1.16-.225.39-.435.782-.635 1.174-.265-.656-.49-1.31-.676-1.947.64-.15 1.315-.283 2.015-.386zm7.26 0c.695.103 1.365.23 2.006.387-.18.632-.405 1.282-.66 1.933-.2-.39-.41-.783-.64-1.174-.225-.392-.465-.774-.705-1.146zm3.063.675c.484.15.944.317 1.375.498 1.732.74 2.852 1.708 2.852 2.476-.005.768-1.125 1.74-2.857 2.475-.42.18-.88.342-1.355.493-.28-.958-.646-1.956-1.1-2.98.45-1.017.81-2.01 1.085-2.964zm-13.395.004c.278.96.645 1.957 1.1 2.98-.45 1.017-.812 2.01-1.086 2.964-.484-.15-.944-.318-1.37-.5-1.732-.737-2.852-1.706-2.852-2.474 0-.768 1.12-1.742 2.852-2.476.42-.18.88-.342 1.356-.494zm11.678 4.28c.265.657.49 1.312.676 1.948-.64.157-1.316.29-2.016.39.24-.375.48-.762.705-1.158.225-.39.435-.788.636-1.18zm-9.945.02c.2.392.41.783.64 1.175.23.39.465.772.705 1.143-.695-.102-1.365-.23-2.006-.386.18-.63.406-1.282.66-1.933zM17.92 16.32c.112.493.2.968.254 1.423.23 1.868-.054 3.32-.714 3.708-.147.09-.338.128-.563.128-1.012 0-2.514-.807-4.11-2.28.686-.72 1.37-1.536 2.02-2.44 1.107-.118 2.154-.3 3.113-.54zm-11.83.01c.96.234 2.006.415 3.107.532.66.905 1.345 1.727 2.035 2.446-1.595 1.483-3.092 2.295-4.11 2.295-.22-.005-.406-.05-.553-.132-.666-.38-.955-1.834-.73-3.703.054-.46.142-.944.25-1.438zm4.56.64c.44.02.89.034 1.345.034.46 0 .915-.01 1.36-.034-.44.572-.895 1.095-1.345 1.565-.455-.47-.91-.993-1.36-1.565z"
/>
</svg>
</div>
<div className="mt-5">
<h2 className="text-lg font-medium text-gray-900">
Next.js and React
</h2>
<p className="mt-2 text-base text-gray-500">
Leverage the power of modern web technologies for optimal
performance and developer experience.
</p>
</div>
</div>

<div className="mt-10 lg:mt-0">
<div className="flex items-center justify-center h-12 w-12 rounded-md bg-orange-500 text-white">
<Database className="h-6 w-6" />
</div>
<div className="mt-5">
<h2 className="text-lg font-medium text-gray-900">
Postgres and Drizzle ORM
</h2>
<p className="mt-2 text-base text-gray-500">
Robust database solution with an intuitive ORM for efficient
data management and scalability.
</p>
</div>
</div>

<div className="mt-10 lg:mt-0">
<div className="flex items-center justify-center h-12 w-12 rounded-md bg-orange-500 text-white">
<CreditCard className="h-6 w-6" />
</div>
<div className="mt-5">
<h2 className="text-lg font-medium text-gray-900">
Stripe Integration
</h2>
<p className="mt-2 text-base text-gray-500">
Seamless payment processing and subscription management with
industry-leading Stripe integration.
</p>
</div>
</div>
</div>
</div>
</section>

<section className="py-16 bg-gray-50">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="lg:grid lg:grid-cols-2 lg:gap-8 lg:items-center">
<div>
<h2 className="text-3xl font-bold text-gray-900 sm:text-4xl">
Ready to launch your SaaS?
</h2>
<p className="mt-3 max-w-3xl text-lg text-gray-500">
Our template provides everything you need to get your SaaS up
and running quickly. Don't waste time on boilerplate - focus on
what makes your product unique.
</p>
</div>
<div className="mt-8 lg:mt-0 flex justify-center lg:justify-end">
<a href="https://github.com/nextjs/saas-starter" target="_blank">
<Button
size="lg"
variant="outline"
className="text-lg rounded-full"
>
View the code
<ArrowRight className="ml-3 h-6 w-6" />
</Button>
</a>
</div>
</div>
</div>
</section>
</footer>
</main>
);
}
}
60 changes: 60 additions & 0 deletions app/actions/contact.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
'use server';

import { z } from 'zod';

// Define the schema for contact form validation
const contactFormSchema = z.object({
name: z.string().min(2).max(100),
email: z.string().email(),
message: z.string().min(10).max(1000),
});

export type ContactFormData = z.infer<typeof contactFormSchema>;

export async function submitContactForm(data: ContactFormData) {
try {
// Validate the data
const validatedData = contactFormSchema.parse(data);

// Here you would typically:
// 1. Save to database
// 2. Send email notification
// 3. Integrate with CRM or support system

// For now, we'll simulate a successful submission
console.log('Contact form submission:', validatedData);

// Simulate API delay
await new Promise(resolve => setTimeout(resolve, 1000));

// In production, you might want to:
// - Send an email using a service like SendGrid, Resend, or AWS SES
// - Store in your database using Drizzle ORM
// - Send to a CRM like HubSpot or Salesforce
// - Create a ticket in a support system

// Example database save (uncomment when ready):
// await db.insert(contactSubmissions).values({
// name: validatedData.name,
// email: validatedData.email,
// message: validatedData.message,
// createdAt: new Date(),
// });

return { success: true };
} catch (error) {
console.error('Contact form error:', error);

if (error instanceof z.ZodError) {
return {
success: false,
error: 'Invalid form data. Please check your inputs.'
};
}

return {
success: false,
error: 'Failed to submit form. Please try again later.'
};
}
}
Loading