diff --git a/app/[locale]/enterprise/_components/CaseCard.tsx b/app/[locale]/enterprise/_components/CaseCard.tsx deleted file mode 100644 index 1d2336f985e..00000000000 --- a/app/[locale]/enterprise/_components/CaseCard.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { Card } from "@/components/ui/card" - -import { cn } from "@/lib/utils/cn" - -import type { Case } from "../types" - -type CaseCardProps = { - caseStudy: Case - className?: string -} - -const CaseCard = ({ - caseStudy: { name, content }, - className, -}: CaseCardProps) => ( - -

{name}

-

{content}

-
-) - -export default CaseCard diff --git a/app/[locale]/enterprise/_components/CasesColumn.tsx b/app/[locale]/enterprise/_components/CasesColumn.tsx deleted file mode 100644 index 2aa1c1a51c1..00000000000 --- a/app/[locale]/enterprise/_components/CasesColumn.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import { cn } from "@/lib/utils/cn" - -import type { Case } from "../types" - -import CaseCard from "./CaseCard" - -const CasesColumn = ({ - cases, - className, -}: { - cases: Case[] - className?: string -}) => ( -
- {cases.map((caseStudy, index) => ( - - ))} -
-) - -export default CasesColumn diff --git a/app/[locale]/enterprise/_components/CasesSwiper.tsx b/app/[locale]/enterprise/_components/CasesSwiper.tsx deleted file mode 100644 index 5100e3cf630..00000000000 --- a/app/[locale]/enterprise/_components/CasesSwiper.tsx +++ /dev/null @@ -1,34 +0,0 @@ -"use client" - -import { Swiper, SwiperSlide } from "@/components/ui/swiper" - -import type { Case } from "../types" - -import CaseCard from "./CaseCard" - -import { useBreakpointValue } from "@/hooks/useBreakpointValue" - -const CasesSwiper = ({ cases }: { cases: Case[] }) => { - const slidesPerView = useBreakpointValue({ - base: 1.2, - sm: 2.2, - }) - - return ( - - {cases.map((caseStudy) => ( - - - - ))} - - ) -} - -export default CasesSwiper diff --git a/app/[locale]/enterprise/_components/ContactForm/index.tsx b/app/[locale]/enterprise/_components/ContactForm/index.tsx deleted file mode 100644 index 37fb3932595..00000000000 --- a/app/[locale]/enterprise/_components/ContactForm/index.tsx +++ /dev/null @@ -1,295 +0,0 @@ -"use client" - -import React, { useState } from "react" -import { HeartHandshake, TriangleAlert } from "lucide-react" - -import { Button } from "@/components/ui/buttons/Button" -import Input from "@/components/ui/input" -import { Spinner } from "@/components/ui/spinner" -import { Textarea } from "@/components/ui/textarea" - -import { cn } from "@/lib/utils/cn" -import { sanitizeInput } from "@/lib/utils/sanitize" - -import { MAX_EMAIL_LENGTH, MAX_MESSAGE_LENGTH } from "../../constants" - -type EnterpriseContactFormProps = { - strings: { - error: { - domain: React.ReactNode // Link injected - emailInvalid: string - emailTooLong: string - general: React.ReactNode // Link injected - messageTooLong: string - required: string - } - placeholder: { - input: string - textarea: string - } - button: { - label: string - loading: string - } - success: { - heading: string - message: string - } - } -} - -type FormState = { - email: string - message: string -} - -type FormErrors = { - email?: React.ReactNode - message?: React.ReactNode - general?: React.ReactNode -} - -type SubmissionState = "idle" | "submitting" | "success" | "error" - -// Consumer email domains to block -const CONSUMER_DOMAINS = [ - "gmail.com", - "yahoo.com", - "hotmail.com", - "outlook.com", - "icloud.com", - "protonmail.com", - "proton.me", - "pm.me", - "aol.com", - "mail.com", - "yandex.com", - "tutanota.com", - "fastmail.com", - "zoho.com", - "gmx.com", - "live.com", - "msn.com", - "me.com", - "mac.com", - "rocketmail.com", - "yahoo.co.uk", - "googlemail.com", - "mailinator.com", - "10minutemail.com", - "guerrillamail.com", -] - -const EnterpriseContactForm = ({ strings }: EnterpriseContactFormProps) => { - const getCharacterCountClasses = (currentLength: number, maxLength: number) => - cn( - currentLength >= Math.floor(maxLength * 0.9) && "flex", // Show char count when within 10% remaining to limit - currentLength > maxLength - 64 && "text-warning-border", // Warning color within 64 chars (border version for proper contrast ratio), - currentLength > maxLength && "text-error [&_svg]:inline" // Error color over limit - ) - - const [formData, setFormData] = useState({ - email: "", - message: "", - }) - const [errors, setErrors] = useState({}) - const [submissionState, setSubmissionState] = - useState("idle") - - const handleInputChange = - (field: keyof FormState) => - (e: React.ChangeEvent) => { - const value = e.target.value - setFormData((prev) => ({ ...prev, [field]: value })) - - // Clear error when user starts typing - if (errors[field]) { - setErrors((prev) => ({ ...prev, [field]: undefined })) - } - } - - const handleBlur = - (field: keyof FormState) => - (e: React.FocusEvent) => { - const value = e.target.value - - if (field === "email") { - const emailError = validateEmail(value) - if (emailError) setErrors((prev) => ({ ...prev, email: emailError })) - return - } - if (field === "message") { - const messageError = validateMessage(value) - if (messageError) - setErrors((prev) => ({ ...prev, message: messageError })) - return - } - } - - const validateEmail = (email: string): React.ReactNode | undefined => { - const sanitized = sanitizeInput(email) - - if (!sanitized) return strings.error.required - - if (sanitized.length > MAX_EMAIL_LENGTH) return strings.error.emailTooLong - - const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/ - if (!emailRegex.test(sanitized)) return strings.error.emailInvalid - - const domain = sanitized.toLowerCase().split("@")[1] - if (CONSUMER_DOMAINS.includes(domain)) return strings.error.domain - - return undefined - } - - const validateMessage = ( - message: string - ): React.ReactNode | string | undefined => { - const sanitized = sanitizeInput(message) - - if (!sanitized) return strings.error.required - - if (sanitized.length > MAX_MESSAGE_LENGTH) - return strings.error.messageTooLong - - return undefined - } - - const validateForm = (): boolean => { - const newErrors: FormErrors = {} - - const emailError = validateEmail(formData.email) - if (emailError) newErrors.email = emailError - - const messageError = validateMessage(formData.message) - if (messageError) newErrors.message = messageError - - setErrors(newErrors) - return Object.keys(newErrors).length === 0 - } - - const handleSubmit = async () => { - if (!validateForm()) return - - setSubmissionState("submitting") - setErrors({}) - - try { - const sanitizedData = { - email: sanitizeInput(formData.email), - message: sanitizeInput(formData.message), - } - - const response = await fetch("/api/enterprise-contact", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify(sanitizedData), - }) - - if (!response.ok) throw new Error(`Server error: ${response.status}`) - - setSubmissionState("success") - } catch (error) { - console.error("Form submission error:", error) - setSubmissionState("error") - setErrors({ general: strings.error.general }) - } - } - - if (submissionState === "success") - return ( -
-
- -

{strings.success.heading}

-
-

{strings.success.message}

-
- ) - - return ( -
-
- - {errors.email && ( -

- {errors.email} -

- )} -
- -
-
-