214 lines
7.7 KiB
TypeScript
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>
|
|
)
|
|
}
|