mirror of
https://github.com/Dokploy/website.git
synced 2026-06-15 20:25:25 +02:00
feat: integrate free email domain validation in contact forms
- Added the `free-email-domains` package to validate email addresses in the contact forms. - Implemented checks to reject free email providers for sales inquiries in both the API and UI components. - Updated the `pnpm-lock.yaml` and `package.json` files to include the new dependency.
This commit is contained in:
@@ -4,6 +4,8 @@ import type { NextRequest } from "next/server";
|
|||||||
import { NextResponse } from "next/server";
|
import { NextResponse } from "next/server";
|
||||||
import { Resend } from "resend";
|
import { Resend } from "resend";
|
||||||
|
|
||||||
|
const FREE_EMAIL_DOMAINS: Set<string> = new Set(require("free-email-domains"));
|
||||||
|
|
||||||
interface ContactFormData {
|
interface ContactFormData {
|
||||||
inquiryType: "support" | "sales";
|
inquiryType: "support" | "sales";
|
||||||
firstName: string;
|
firstName: string;
|
||||||
@@ -52,6 +54,17 @@ export async function POST(request: NextRequest) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reject free email providers for sales inquiries
|
||||||
|
if (body.inquiryType === "sales") {
|
||||||
|
const domain = body.email.split("@")[1]?.toLowerCase();
|
||||||
|
if (domain && FREE_EMAIL_DOMAINS.has(domain)) {
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: "Please use your work email address to contact sales" },
|
||||||
|
{ status: 400 },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Submit to HubSpot if it's a sales inquiry
|
// Submit to HubSpot if it's a sales inquiry
|
||||||
if (body.inquiryType === "sales") {
|
if (body.inquiryType === "sales") {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ import {
|
|||||||
} from "@/components/ui/select";
|
} from "@/components/ui/select";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
|
||||||
|
const FREE_EMAIL_DOMAINS: Set<string> = new Set(require("free-email-domains"));
|
||||||
|
|
||||||
interface ContactFormData {
|
interface ContactFormData {
|
||||||
inquiryType: "" | "support" | "sales";
|
inquiryType: "" | "support" | "sales";
|
||||||
deploymentType: "" | "cloud" | "self-hosted";
|
deploymentType: "" | "cloud" | "self-hosted";
|
||||||
@@ -69,6 +71,12 @@ export function ContactForm({
|
|||||||
newErrors.email = "Email is required";
|
newErrors.email = "Email is required";
|
||||||
} else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(formData.email)) {
|
} else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(formData.email)) {
|
||||||
newErrors.email = "Please enter a valid email address";
|
newErrors.email = "Please enter a valid email address";
|
||||||
|
} else if (
|
||||||
|
formData.inquiryType === "sales" &&
|
||||||
|
FREE_EMAIL_DOMAINS.has(formData.email.split("@")[1]?.toLowerCase())
|
||||||
|
) {
|
||||||
|
newErrors.email =
|
||||||
|
"Please use your work email address to contact sales";
|
||||||
}
|
}
|
||||||
if (!formData.company.trim()) {
|
if (!formData.company.trim()) {
|
||||||
newErrors.company = "Company name is required";
|
newErrors.company = "Company name is required";
|
||||||
|
|||||||
@@ -35,6 +35,7 @@
|
|||||||
"class-variance-authority": "^0.7.0",
|
"class-variance-authority": "^0.7.0",
|
||||||
"clsx": "^2.1.0",
|
"clsx": "^2.1.0",
|
||||||
"framer-motion": "^11.3.19",
|
"framer-motion": "^11.3.19",
|
||||||
|
"free-email-domains": "^1.2.26",
|
||||||
"hast-util-to-jsx-runtime": "^2.3.5",
|
"hast-util-to-jsx-runtime": "^2.3.5",
|
||||||
"lucide-react": "0.364.0",
|
"lucide-react": "0.364.0",
|
||||||
"next": "16.1.5",
|
"next": "16.1.5",
|
||||||
|
|||||||
15
pnpm-lock.yaml
generated
15
pnpm-lock.yaml
generated
@@ -32,7 +32,7 @@ importers:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@next/third-parties':
|
'@next/third-parties':
|
||||||
specifier: 16.0.7
|
specifier: 16.0.7
|
||||||
version: 16.0.7(next@16.1.5(@babel/core@7.26.9)(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(react@19.2.1)
|
version: 16.0.7(next@16.1.5(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(react@19.2.1)
|
||||||
'@radix-ui/react-dropdown-menu':
|
'@radix-ui/react-dropdown-menu':
|
||||||
specifier: ^2.1.16
|
specifier: ^2.1.16
|
||||||
version: 2.1.16(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)
|
version: 2.1.16(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)
|
||||||
@@ -111,7 +111,7 @@ importers:
|
|||||||
version: 0.2.1(tailwindcss@3.4.7)
|
version: 0.2.1(tailwindcss@3.4.7)
|
||||||
'@next/third-parties':
|
'@next/third-parties':
|
||||||
specifier: 16.0.7
|
specifier: 16.0.7
|
||||||
version: 16.0.7(next@16.1.5(@babel/core@7.26.9)(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(react@19.2.1)
|
version: 16.0.7(next@16.1.5(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(react@19.2.1)
|
||||||
'@prettier/plugin-xml':
|
'@prettier/plugin-xml':
|
||||||
specifier: ^3.4.1
|
specifier: ^3.4.1
|
||||||
version: 3.4.1(prettier@3.3.3)
|
version: 3.4.1(prettier@3.3.3)
|
||||||
@@ -172,6 +172,9 @@ importers:
|
|||||||
framer-motion:
|
framer-motion:
|
||||||
specifier: ^11.3.19
|
specifier: ^11.3.19
|
||||||
version: 11.3.19(react-dom@19.2.1(react@19.2.1))(react@19.2.1)
|
version: 11.3.19(react-dom@19.2.1(react@19.2.1))(react@19.2.1)
|
||||||
|
free-email-domains:
|
||||||
|
specifier: ^1.2.26
|
||||||
|
version: 1.2.26
|
||||||
hast-util-to-jsx-runtime:
|
hast-util-to-jsx-runtime:
|
||||||
specifier: ^2.3.5
|
specifier: ^2.3.5
|
||||||
version: 2.3.6
|
version: 2.3.6
|
||||||
@@ -2783,6 +2786,10 @@ packages:
|
|||||||
react-dom:
|
react-dom:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
free-email-domains@1.2.26:
|
||||||
|
resolution: {integrity: sha512-HHk4Fp8ts63MDIpnd3LCbfUNAqj6Ea9kjXWUv15zbmEZRR7f7TtBLUvK56ZtyjR6voCdZ1xG1DNIme7yUl9vww==}
|
||||||
|
engines: {node: '>= 18'}
|
||||||
|
|
||||||
fsevents@2.3.3:
|
fsevents@2.3.3:
|
||||||
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
|
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
|
||||||
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
|
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
|
||||||
@@ -5153,7 +5160,7 @@ snapshots:
|
|||||||
'@next/swc-win32-x64-msvc@16.1.5':
|
'@next/swc-win32-x64-msvc@16.1.5':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@next/third-parties@16.0.7(next@16.1.5(@babel/core@7.26.9)(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(react@19.2.1)':
|
'@next/third-parties@16.0.7(next@16.1.5(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(react@19.2.1)':
|
||||||
dependencies:
|
dependencies:
|
||||||
next: 16.1.5(@babel/core@7.26.9)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)
|
next: 16.1.5(@babel/core@7.26.9)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)
|
||||||
react: 19.2.1
|
react: 19.2.1
|
||||||
@@ -6858,6 +6865,8 @@ snapshots:
|
|||||||
react: 19.2.1
|
react: 19.2.1
|
||||||
react-dom: 19.2.1(react@19.2.1)
|
react-dom: 19.2.1(react@19.2.1)
|
||||||
|
|
||||||
|
free-email-domains@1.2.26: {}
|
||||||
|
|
||||||
fsevents@2.3.3:
|
fsevents@2.3.3:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user