mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-05-17 18:35:19 +02:00
feat: added drizzle for contact management
This commit is contained in:
parent
1a3faf03d5
commit
ba62489715
8 changed files with 762 additions and 18 deletions
|
|
@ -1,13 +1,72 @@
|
|||
"use client";
|
||||
import React from "react";
|
||||
import React, { useState } from "react";
|
||||
import { IconMailFilled } from "@tabler/icons-react";
|
||||
import { useId } from "react";
|
||||
import { cn } from "@/lib/utils";
|
||||
import Image from "next/image";
|
||||
import { motion } from "motion/react";
|
||||
import Link from "next/link";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { z } from "zod";
|
||||
import { toast } from "sonner";
|
||||
|
||||
// Define validation schema matching the database schema
|
||||
const contactFormSchema = z.object({
|
||||
name: z.string().min(1, 'Name is required').max(255, 'Name is too long'),
|
||||
email: z.string().email('Invalid email address').max(255, 'Email is too long'),
|
||||
company: z.string().min(1, 'Company is required').max(255, 'Company name is too long'),
|
||||
message: z.string().optional().default(''),
|
||||
});
|
||||
|
||||
type ContactFormData = z.infer<typeof contactFormSchema>;
|
||||
|
||||
export function ContactFormGridWithDetails() {
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
|
||||
const {
|
||||
register,
|
||||
handleSubmit,
|
||||
formState: { errors },
|
||||
reset,
|
||||
} = useForm<ContactFormData>({
|
||||
resolver: zodResolver(contactFormSchema),
|
||||
});
|
||||
|
||||
const onSubmit = async (data: ContactFormData) => {
|
||||
setIsSubmitting(true);
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/contact', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(data),
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (response.ok) {
|
||||
toast.success('Message sent successfully!', {
|
||||
description: 'We will get back to you as soon as possible.',
|
||||
});
|
||||
reset();
|
||||
} else {
|
||||
toast.error('Failed to send message', {
|
||||
description: result.message || 'Please try again later.',
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error submitting form:', error);
|
||||
toast.error('Something went wrong', {
|
||||
description: 'Please try again later.',
|
||||
});
|
||||
} finally {
|
||||
setIsSubmitting(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="mx-auto grid w-full max-w-7xl grid-cols-1 gap-10 px-4 py-10 md:px-6 md:py-20 lg:grid-cols-2">
|
||||
<div className="relative flex flex-col items-center overflow-hidden lg:items-start">
|
||||
|
|
@ -26,17 +85,12 @@ export function ContactFormGridWithDetails() {
|
|||
|
||||
<div className="mt-10 hidden flex-col items-center gap-4 md:flex-row lg:flex">
|
||||
<Link href="mailto:rohan@surfsense.com" className="text-sm text-neutral-500 dark:text-neutral-400">
|
||||
rohan@surfsense.com
|
||||
rohan@surfsense.com
|
||||
</Link>
|
||||
|
||||
{/* <div className="h-1 w-1 rounded-full bg-neutral-500 dark:bg-neutral-400" />
|
||||
<p className="text-sm text-neutral-500 dark:text-neutral-400">
|
||||
+1 (800) 123 XX21
|
||||
</p> */}
|
||||
<div className="h-1 w-1 rounded-full bg-neutral-500 dark:bg-neutral-400" />
|
||||
|
||||
<Link href="https://cal.com/mod-surfsense" className="text-sm text-neutral-500 dark:text-neutral-400">
|
||||
https://cal.com/mod-surfsense
|
||||
https://cal.com/mod-surfsense
|
||||
</Link>
|
||||
</div>
|
||||
<div className="div relative mt-20 flex w-[600px] flex-shrink-0 -translate-x-10 items-center justify-center [perspective:800px] [transform-style:preserve-3d] sm:-translate-x-0 lg:-translate-x-32">
|
||||
|
|
@ -51,7 +105,10 @@ export function ContactFormGridWithDetails() {
|
|||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="relative mx-auto flex w-full max-w-2xl flex-col items-start gap-4 overflow-hidden rounded-3xl bg-gradient-to-b from-gray-100 to-gray-200 p-4 sm:p-10 dark:from-neutral-900 dark:to-neutral-950">
|
||||
<form
|
||||
onSubmit={handleSubmit(onSubmit)}
|
||||
className="relative mx-auto flex w-full max-w-2xl flex-col items-start gap-4 overflow-hidden rounded-3xl bg-gradient-to-b from-gray-100 to-gray-200 p-4 sm:p-10 dark:from-neutral-900 dark:to-neutral-950"
|
||||
>
|
||||
<Grid size={20} />
|
||||
<div className="relative z-20 mb-4 w-full">
|
||||
<label
|
||||
|
|
@ -64,8 +121,15 @@ export function ContactFormGridWithDetails() {
|
|||
id="name"
|
||||
type="text"
|
||||
placeholder="John Doe"
|
||||
className="shadow-input h-10 w-full rounded-md border border-transparent bg-white pl-4 text-sm text-neutral-700 placeholder-neutral-500 outline-none focus:ring-2 focus:ring-neutral-800 focus:outline-none active:outline-none dark:border-neutral-800 dark:bg-neutral-800 dark:text-white"
|
||||
{...register("name")}
|
||||
className={cn(
|
||||
"shadow-input h-10 w-full rounded-md border bg-white pl-4 text-sm text-neutral-700 placeholder-neutral-500 outline-none focus:ring-2 focus:ring-neutral-800 focus:outline-none active:outline-none dark:border-neutral-800 dark:bg-neutral-800 dark:text-white",
|
||||
errors.name ? "border-red-500" : "border-transparent"
|
||||
)}
|
||||
/>
|
||||
{errors.name && (
|
||||
<p className="mt-1 text-xs text-red-500">{errors.name.message}</p>
|
||||
)}
|
||||
</div>
|
||||
<div className="relative z-20 mb-4 w-full">
|
||||
<label
|
||||
|
|
@ -78,8 +142,15 @@ export function ContactFormGridWithDetails() {
|
|||
id="email"
|
||||
type="email"
|
||||
placeholder="john.doe@example.com"
|
||||
className="shadow-input h-10 w-full rounded-md border border-transparent bg-white pl-4 text-sm text-neutral-700 placeholder-neutral-500 outline-none focus:ring-2 focus:ring-neutral-800 focus:outline-none active:outline-none dark:border-neutral-800 dark:bg-neutral-800 dark:text-white"
|
||||
{...register("email")}
|
||||
className={cn(
|
||||
"shadow-input h-10 w-full rounded-md border bg-white pl-4 text-sm text-neutral-700 placeholder-neutral-500 outline-none focus:ring-2 focus:ring-neutral-800 focus:outline-none active:outline-none dark:border-neutral-800 dark:bg-neutral-800 dark:text-white",
|
||||
errors.email ? "border-red-500" : "border-transparent"
|
||||
)}
|
||||
/>
|
||||
{errors.email && (
|
||||
<p className="mt-1 text-xs text-red-500">{errors.email.message}</p>
|
||||
)}
|
||||
</div>
|
||||
<div className="relative z-20 mb-4 w-full">
|
||||
<label
|
||||
|
|
@ -92,8 +163,15 @@ export function ContactFormGridWithDetails() {
|
|||
id="company"
|
||||
type="text"
|
||||
placeholder="Example Inc."
|
||||
className="shadow-input h-10 w-full rounded-md border border-transparent bg-white pl-4 text-sm text-neutral-700 placeholder-neutral-500 outline-none focus:ring-2 focus:ring-neutral-800 focus:outline-none active:outline-none dark:border-neutral-800 dark:bg-neutral-800 dark:text-white"
|
||||
{...register("company")}
|
||||
className={cn(
|
||||
"shadow-input h-10 w-full rounded-md border bg-white pl-4 text-sm text-neutral-700 placeholder-neutral-500 outline-none focus:ring-2 focus:ring-neutral-800 focus:outline-none active:outline-none dark:border-neutral-800 dark:bg-neutral-800 dark:text-white",
|
||||
errors.company ? "border-red-500" : "border-transparent"
|
||||
)}
|
||||
/>
|
||||
{errors.company && (
|
||||
<p className="mt-1 text-xs text-red-500">{errors.company.message}</p>
|
||||
)}
|
||||
</div>
|
||||
<div className="relative z-20 mb-4 w-full">
|
||||
<label
|
||||
|
|
@ -106,13 +184,24 @@ export function ContactFormGridWithDetails() {
|
|||
id="message"
|
||||
rows={5}
|
||||
placeholder="Type your message here"
|
||||
className="shadow-input w-full rounded-md border border-transparent bg-white pt-4 pl-4 text-sm text-neutral-700 placeholder-neutral-500 outline-none focus:ring-2 focus:ring-neutral-800 focus:outline-none active:outline-none dark:border-neutral-800 dark:bg-neutral-800 dark:text-white"
|
||||
{...register("message")}
|
||||
className={cn(
|
||||
"shadow-input w-full rounded-md border bg-white pt-4 pl-4 text-sm text-neutral-700 placeholder-neutral-500 outline-none focus:ring-2 focus:ring-neutral-800 focus:outline-none active:outline-none dark:border-neutral-800 dark:bg-neutral-800 dark:text-white",
|
||||
errors.message ? "border-red-500" : "border-transparent"
|
||||
)}
|
||||
/>
|
||||
{errors.message && (
|
||||
<p className="mt-1 text-xs text-red-500">{errors.message.message}</p>
|
||||
)}
|
||||
</div>
|
||||
<button className="relative z-10 flex items-center justify-center rounded-md border border-transparent bg-neutral-800 px-4 py-2 text-sm font-medium text-white shadow-[0px_1px_0px_0px_#FFFFFF20_inset] transition duration-200 hover:bg-neutral-900 md:text-sm">
|
||||
Submit
|
||||
<button
|
||||
type="submit"
|
||||
disabled={isSubmitting}
|
||||
className="relative z-10 flex items-center justify-center rounded-md border border-transparent bg-neutral-800 px-4 py-2 text-sm font-medium text-white shadow-[0px_1px_0px_0px_#FFFFFF20_inset] transition duration-200 hover:bg-neutral-900 disabled:cursor-not-allowed disabled:opacity-50 md:text-sm"
|
||||
>
|
||||
{isSubmitting ? 'Submitting...' : 'Submit'}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue