o2o-negosium-original/landing/app/components/sections/contact.tsx

214 lines
7.7 KiB
TypeScript

import { useState } from "react"
import { AnimatePresence, motion } from "motion/react"
import { Building, CheckCircle2, Loader2, Mail, Phone, Send } from "lucide-react"
import { Button } from "@/components/ui/button"
import { Input, Textarea } from "@/components/ui/input"
import { Section } from "@/components/ui/section"
import { SectionHeading } from "@/components/ui/section-heading"
import { Typography } from "@/components/ui/typography"
import { EASE_OUT_EXPO } from "@/lib/motion"
import type { LucideIcon } from "lucide-react"
const EMPTY_FORM = {
companyName: '',
contactName: '',
email: '',
phone: '',
message: '',
}
/** 도입 문의 폼. 백엔드 미연결 — 제출은 데모 처리(1.2초 후 성공 화면). */
export function Contact() {
const [formData, setFormData] = useState(EMPTY_FORM)
const [status, setStatus] = useState<'idle' | 'submitting' | 'success'>('idle')
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault()
if (!formData.companyName || !formData.contactName || !formData.email || !formData.phone) {
return
}
setStatus('submitting')
setTimeout(() => setStatus('success'), 1200)
}
const handleChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
const { name, value } = e.target
setFormData((prev) => ({ ...prev, [name]: value }))
}
const submitting = status === 'submitting'
return (
<Section
id="contact-section"
bordered
decor={
<>
<div className="absolute top-[20%] right-[10%] w-72 h-72 bg-primary/5 blur-[100px] rounded-full pointer-events-none" />
<div className="absolute bottom-[10%] left-[5%] w-96 h-96 bg-primary/3 blur-[120px] rounded-full pointer-events-none" />
</>
}
>
<SectionHeading
align="center"
className="mb-16"
eyebrow="GET IN TOUCH"
title="도입 문의 및 컨택하기"
description="사내 ERP 연동부터 우리 기업에 맞춘 흥정 시나리오 구성까지, negotium의 구매 혁신 컨설턴트가 상세히 안내해 드립니다."
descriptionClassName="max-w-xl"
/>
<div className="max-w-2xl mx-auto">
<AnimatePresence mode="wait">
{status !== 'success' ? (
<motion.form
key="contact-form"
onSubmit={handleSubmit}
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -20 }}
transition={{ duration: 0.5, ease: EASE_OUT_EXPO }}
className="space-y-6"
>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-6">
<FormField label="회사명" icon={Building} required>
<Input
type="text"
name="companyName"
required
placeholder="예: (주)한빛유통"
value={formData.companyName}
onChange={handleChange}
disabled={submitting}
/>
</FormField>
<FormField label="담당자 성함 / 직책" required>
<Input
type="text"
name="contactName"
required
placeholder="예: 홍길동 팀장"
value={formData.contactName}
onChange={handleChange}
disabled={submitting}
/>
</FormField>
</div>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-6">
<FormField label="이메일 주소" icon={Mail} required>
<Input
type="email"
name="email"
required
placeholder="example@company.com"
value={formData.email}
onChange={handleChange}
disabled={submitting}
/>
</FormField>
<FormField label="연락처" icon={Phone} required>
<Input
type="tel"
name="phone"
required
placeholder="010-0000-0000"
value={formData.phone}
onChange={handleChange}
disabled={submitting}
/>
</FormField>
</div>
<FormField label="상세 문의 및 요구사항">
<Textarea
name="message"
rows={4}
placeholder="현재 겪고 계신 구매 조율 상의 번거로움이나, 자동화를 원하시는 구체적인 부자재 품목 정보를 남겨주시면 더욱 맞춤화된 상담이 가능합니다."
value={formData.message}
onChange={handleChange}
disabled={submitting}
/>
</FormField>
<Typography variant="caption" className="font-medium">
* 제출 시 입력하신 정보는 문의 사항 응답 및 도입 검토 목적에 한하여 사용되며, 관련 법령에 의거하여 안전하게
보호됩니다.
</Typography>
<div className="pt-2">
<Button type="submit" disabled={submitting} className="w-full shadow-sm hover:shadow-md">
{submitting ? (
<>
<Loader2 className="w-5 h-5 animate-spin" />
<span>신청서 전송 중...</span>
</>
) : (
<>
<Send className="w-5 h-5" />
<span>도입 문의 및 상담 신청하기</span>
</>
)}
</Button>
</div>
</motion.form>
) : (
<motion.div
key="success-message"
initial={{ opacity: 0, scale: 0.95 }}
animate={{ opacity: 1, scale: 1 }}
transition={{ duration: 0.6, ease: EASE_OUT_EXPO }}
className="text-center py-16 px-6 bg-primary/5 rounded-[32px] text-ink break-keep"
>
<div className="w-16 h-16 bg-primary/10 text-primary rounded-full flex items-center justify-center mx-auto mb-6">
<CheckCircle2 className="w-8 h-8" />
</div>
<h3 className="text-2xl font-extrabold text-ink mb-3">도입 문의 신청이 접수되었습니다</h3>
<p className="text-ink-soft font-semibold text-[15px] leading-relaxed max-w-md mx-auto mb-8">
작성해주신 담당자 정보({formData.contactName} 님)를 통해 24시간 이내에 전담 혁신 컨설턴트가 유선 혹은 이메일로
연락을 드리겠습니다.
</p>
<Button
type="button"
size="md"
onClick={() => {
setFormData(EMPTY_FORM)
setStatus('idle')
}}
>
새로 문의하기
</Button>
</motion.div>
)}
</AnimatePresence>
</div>
</Section>
)
}
function FormField({
label,
icon: Icon,
required = false,
children,
}: {
label: string
icon?: LucideIcon
required?: boolean
children: React.ReactNode
}) {
return (
<div className="space-y-2">
<label className="text-xs font-bold text-ink-soft flex items-center gap-1.5">
{Icon && <Icon className="w-3.5 h-3.5 text-ink-muted" />}
{label} {required && <span className="text-primary">*</span>}
</label>
{children}
</div>
)
}