첫 커밋

This commit is contained in:
focp212@naver.com
2025-09-05 15:36:48 +09:00
commit 05238b04c1
825 changed files with 176358 additions and 0 deletions

318
src/pages/Contact.tsx Normal file
View File

@@ -0,0 +1,318 @@
import React, { useState } from 'react';
interface FormData {
name: string;
email: string;
phone: string;
subject: string;
message: string;
}
interface FormErrors {
name?: string;
email?: string;
phone?: string;
subject?: string;
message?: string;
}
const Contact: React.FC = () => {
const [formData, setFormData] = useState<FormData>({
name: '',
email: '',
phone: '',
subject: '',
message: '',
});
const [errors, setErrors] = useState<FormErrors>({});
const [isSubmitting, setIsSubmitting] = useState(false);
const [isSubmitted, setIsSubmitted] = useState(false);
const validateForm = (): boolean => {
const newErrors: FormErrors = {};
if (!formData.name.trim()) {
newErrors.name = '이름을 입력해주세요.';
}
if (!formData.email.trim()) {
newErrors.email = '이메일을 입력해주세요.';
} else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(formData.email)) {
newErrors.email = '올바른 이메일 형식을 입력해주세요.';
}
if (!formData.phone.trim()) {
newErrors.phone = '전화번호를 입력해주세요.';
} else if (!/^[0-9-+\s()]+$/.test(formData.phone)) {
newErrors.phone = '올바른 전화번호 형식을 입력해주세요.';
}
if (!formData.subject.trim()) {
newErrors.subject = '문의 제목을 입력해주세요.';
}
if (!formData.message.trim()) {
newErrors.message = '문의 내용을 입력해주세요.';
} else if (formData.message.length < 10) {
newErrors.message = '문의 내용을 최소 10자 이상 입력해주세요.';
}
setErrors(newErrors);
return Object.keys(newErrors).length === 0;
};
const handleChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>) => {
const { name, value } = e.target;
setFormData(prev => ({
...prev,
[name]: value,
}));
if (errors[name as keyof FormErrors]) {
setErrors(prev => ({
...prev,
[name]: undefined,
}));
}
};
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
if (!validateForm()) return;
setIsSubmitting(true);
try {
// 실제 구현에서는 API 호출
await new Promise(resolve => setTimeout(resolve, 1000));
setIsSubmitted(true);
setFormData({
name: '',
email: '',
phone: '',
subject: '',
message: '',
});
} catch (error) {
console.error('Form submission error:', error);
} finally {
setIsSubmitting(false);
}
};
if (isSubmitted) {
return (
<div className="min-h-screen bg-gray-50 flex items-center justify-center">
<div className="bg-white p-8 rounded-lg shadow-lg max-w-md w-full mx-4">
<div className="text-center">
<div className="w-16 h-16 bg-green-100 rounded-full flex items-center justify-center mx-auto mb-4">
<svg className="w-8 h-8 text-green-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
</svg>
</div>
<h2 className="text-2xl font-bold text-gray-900 mb-2">
</h2>
<p className="text-gray-600 mb-6">
.
</p>
<button
onClick={() => setIsSubmitted(false)}
className="bg-blue-600 text-white px-6 py-2 rounded-md hover:bg-blue-700 transition-colors"
>
</button>
</div>
</div>
</div>
);
}
return (
<div className="min-h-screen bg-gray-50 py-12">
<div className="container mx-auto px-4">
<div className="max-w-4xl mx-auto">
<div className="text-center mb-12">
<h1 className="text-4xl font-bold text-gray-900 mb-4">
</h1>
<p className="text-lg text-gray-600">
.
</p>
</div>
<div className="grid md:grid-cols-2 gap-12">
{/* Contact Information */}
<div>
<h2 className="text-2xl font-bold text-gray-900 mb-6">
</h2>
<div className="space-y-4">
<div className="flex items-start space-x-3">
<div className="w-6 h-6 bg-blue-100 rounded-full flex items-center justify-center flex-shrink-0 mt-1">
<svg className="w-3 h-3 text-blue-600" fill="currentColor" viewBox="0 0 24 24">
<path d="M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7zm0 9.5c-1.38 0-2.5-1.12-2.5-2.5s1.12-2.5 2.5-2.5 2.5 1.12 2.5 2.5-1.12 2.5-2.5 2.5z"/>
</svg>
</div>
<div>
<div className="font-semibold text-gray-900"></div>
<div className="text-gray-600"> 123</div>
</div>
</div>
<div className="flex items-start space-x-3">
<div className="w-6 h-6 bg-blue-100 rounded-full flex items-center justify-center flex-shrink-0 mt-1">
<svg className="w-3 h-3 text-blue-600" fill="currentColor" viewBox="0 0 24 24">
<path d="M20 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 4l-8 5-8-5V6l8 5 8-5v2z"/>
</svg>
</div>
<div>
<div className="font-semibold text-gray-900"></div>
<div className="text-gray-600">contact@nicepayments.com</div>
</div>
</div>
<div className="flex items-start space-x-3">
<div className="w-6 h-6 bg-blue-100 rounded-full flex items-center justify-center flex-shrink-0 mt-1">
<svg className="w-3 h-3 text-blue-600" fill="currentColor" viewBox="0 0 24 24">
<path d="M20.01 15.38c-1.23 0-2.42-.2-3.53-.56-.35-.12-.74-.03-1.01.24l-1.57 1.97c-2.83-1.35-5.48-3.9-6.89-6.83l1.95-1.66c.27-.28.35-.67.24-1.02-.37-1.11-.56-2.3-.56-3.53 0-.54-.45-.99-.99-.99H4.19C3.65 3 3 3.24 3 3.99 3 13.28 10.73 21 20.01 21c.71 0 .99-.63.99-1.18v-3.45c0-.54-.45-.99-.99-.99z"/>
</svg>
</div>
<div>
<div className="font-semibold text-gray-900"></div>
<div className="text-gray-600">02-1234-5678</div>
</div>
</div>
<div className="flex items-start space-x-3">
<div className="w-6 h-6 bg-blue-100 rounded-full flex items-center justify-center flex-shrink-0 mt-1">
<svg className="w-3 h-3 text-blue-600" fill="currentColor" viewBox="0 0 24 24">
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"/>
</svg>
</div>
<div>
<div className="font-semibold text-gray-900"></div>
<div className="text-gray-600"> 09:00 - 18:00</div>
</div>
</div>
</div>
</div>
{/* Contact Form */}
<div className="bg-white p-8 rounded-lg shadow-lg">
<h2 className="text-2xl font-bold text-gray-900 mb-6">
</h2>
<form onSubmit={handleSubmit} className="space-y-6">
<div>
<label htmlFor="name" className="block text-sm font-medium text-gray-700 mb-2">
*
</label>
<input
type="text"
id="name"
name="name"
value={formData.name}
onChange={handleChange}
className={`w-full px-3 py-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 ${
errors.name ? 'border-red-500' : 'border-gray-300'
}`}
placeholder="이름을 입력하세요"
/>
{errors.name && <p className="mt-1 text-sm text-red-600">{errors.name}</p>}
</div>
<div>
<label htmlFor="email" className="block text-sm font-medium text-gray-700 mb-2">
*
</label>
<input
type="email"
id="email"
name="email"
value={formData.email}
onChange={handleChange}
className={`w-full px-3 py-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 ${
errors.email ? 'border-red-500' : 'border-gray-300'
}`}
placeholder="이메일을 입력하세요"
/>
{errors.email && <p className="mt-1 text-sm text-red-600">{errors.email}</p>}
</div>
<div>
<label htmlFor="phone" className="block text-sm font-medium text-gray-700 mb-2">
*
</label>
<input
type="tel"
id="phone"
name="phone"
value={formData.phone}
onChange={handleChange}
className={`w-full px-3 py-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 ${
errors.phone ? 'border-red-500' : 'border-gray-300'
}`}
placeholder="전화번호를 입력하세요"
/>
{errors.phone && <p className="mt-1 text-sm text-red-600">{errors.phone}</p>}
</div>
<div>
<label htmlFor="subject" className="block text-sm font-medium text-gray-700 mb-2">
*
</label>
<select
id="subject"
name="subject"
value={formData.subject}
onChange={handleChange}
className={`w-full px-3 py-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 ${
errors.subject ? 'border-red-500' : 'border-gray-300'
}`}
>
<option value=""> </option>
<option value="service"> </option>
<option value="technical"> </option>
<option value="billing">/ </option>
<option value="partnership"> </option>
<option value="other"></option>
</select>
{errors.subject && <p className="mt-1 text-sm text-red-600">{errors.subject}</p>}
</div>
<div>
<label htmlFor="message" className="block text-sm font-medium text-gray-700 mb-2">
*
</label>
<textarea
id="message"
name="message"
value={formData.message}
onChange={handleChange}
rows={5}
className={`w-full px-3 py-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 ${
errors.message ? 'border-red-500' : 'border-gray-300'
}`}
placeholder="문의 내용을 자세히 입력하세요"
/>
{errors.message && <p className="mt-1 text-sm text-red-600">{errors.message}</p>}
</div>
<button
type="submit"
disabled={isSubmitting}
className="w-full bg-blue-600 text-white py-3 px-4 rounded-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
>
{isSubmitting ? '전송 중...' : '문의 보내기'}
</button>
</form>
</div>
</div>
</div>
</div>
</div>
);
};
export default Contact;