|
@@ -38,6 +38,72 @@ const Step1 = () => {
|
|
|
|
|
|
|
|
const currentLang = i18n.language === 'zh' ? 'zh' : 'en';
|
|
const currentLang = i18n.language === 'zh' ? 'zh' : 'en';
|
|
|
|
|
|
|
|
|
|
+ // Form State
|
|
|
|
|
+ const [formData, setFormData] = useState({
|
|
|
|
|
+ name: '',
|
|
|
|
|
+ contact: '',
|
|
|
|
|
+ industry: ''
|
|
|
|
|
+ });
|
|
|
|
|
+ const [status, setStatus] = useState<'idle' | 'loading' | 'success' | 'error'>('idle');
|
|
|
|
|
+ const [message, setMessage] = useState('');
|
|
|
|
|
+
|
|
|
|
|
+ const handleInputChange = (e: React.ChangeEvent<HTMLInputElement | HTMLSelectElement>) => {
|
|
|
|
|
+ const { name, value } = e.target;
|
|
|
|
|
+ setFormData(prev => ({ ...prev, [name]: value }));
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ const handleSubmit = async (e: React.FormEvent) => {
|
|
|
|
|
+ e.preventDefault();
|
|
|
|
|
+
|
|
|
|
|
+ // Basic validation
|
|
|
|
|
+ if (!formData.contact) {
|
|
|
|
|
+ setStatus('error');
|
|
|
|
|
+ setMessage(currentLang === 'zh' ? '请填写联系方式' : 'Please enter your contact info');
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Email validation (assuming contact is email for the API)
|
|
|
|
|
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
|
|
|
+ if (!emailRegex.test(formData.contact)) {
|
|
|
|
|
+ setStatus('error');
|
|
|
|
|
+ setMessage(currentLang === 'zh' ? '请输入有效的邮箱地址' : 'Please enter a valid email');
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ setStatus('loading');
|
|
|
|
|
+ setMessage('');
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ // We verify email format, and pass other fields as extra data
|
|
|
|
|
+ const payload = {
|
|
|
|
|
+ email: formData.contact,
|
|
|
|
|
+ name: formData.name,
|
|
|
|
|
+ industry: formData.industry,
|
|
|
|
|
+ source: 'Step1_Consulting'
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ const response = await fetch('/api/send-welcome-email', {
|
|
|
|
|
+ method: 'POST',
|
|
|
|
|
+ headers: { 'Content-Type': 'application/json' },
|
|
|
|
|
+ body: JSON.stringify(payload),
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ const data = await response.json();
|
|
|
|
|
+
|
|
|
|
|
+ if (data.success) {
|
|
|
|
|
+ setStatus('success');
|
|
|
|
|
+ setMessage(data.message || (currentLang === 'zh' ? '提交成功!我们会尽快联系您。' : 'Submitted successfully! We will contact you soon.'));
|
|
|
|
|
+ setFormData({ name: '', contact: '', industry: '' });
|
|
|
|
|
+ } else {
|
|
|
|
|
+ setStatus('error');
|
|
|
|
|
+ setMessage(data.message || (currentLang === 'zh' ? '提交失败,请稍后重试。' : 'Submission failed. Please try again later.'));
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ setStatus('error');
|
|
|
|
|
+ setMessage(currentLang === 'zh' ? '网络错误,请稍后重试。' : 'Network error. Please try again later.');
|
|
|
|
|
+ }
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
// Theme utility classes
|
|
// Theme utility classes
|
|
|
const themeClasses = {
|
|
const themeClasses = {
|
|
|
bg: isDark ? 'bg-stone-900' : 'bg-white',
|
|
bg: isDark ? 'bg-stone-900' : 'bg-white',
|
|
@@ -319,36 +385,63 @@ const Step1 = () => {
|
|
|
</p>
|
|
</p>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
- <div className={`border p-8 md:p-12 rounded-sm text-left ${themeClasses.borderStrong} ${themeClasses.cardBg} ${themeClasses.shadow}`}>
|
|
|
|
|
|
|
+ <div
|
|
|
|
|
+ className={`border p-8 md:p-12 rounded-sm text-left ${themeClasses.borderStrong} ${themeClasses.cardBg} ${themeClasses.shadow}`}>
|
|
|
<h3 className="font-bold text-lg mb-6 flex items-center gap-2">
|
|
<h3 className="font-bold text-lg mb-6 flex items-center gap-2">
|
|
|
<MessageSquare className="w-5 h-5" />
|
|
<MessageSquare className="w-5 h-5" />
|
|
|
{t('step1.contact_form_title')}
|
|
{t('step1.contact_form_title')}
|
|
|
</h3>
|
|
</h3>
|
|
|
- <form className="space-y-4">
|
|
|
|
|
|
|
+ <form className="space-y-4" onSubmit={handleSubmit}>
|
|
|
<div>
|
|
<div>
|
|
|
<label className={`block text-xs font-bold uppercase mb-1 ${themeClasses.textLight}`}>{t('step1.form.name')}</label>
|
|
<label className={`block text-xs font-bold uppercase mb-1 ${themeClasses.textLight}`}>{t('step1.form.name')}</label>
|
|
|
- <input type="text"
|
|
|
|
|
- className={`w-full border-b py-2 focus:outline-none transition bg-transparent ${themeClasses.inputBorder}`}
|
|
|
|
|
- placeholder={t('step1.form.placeholders.name')} />
|
|
|
|
|
|
|
+ <input
|
|
|
|
|
+ type="text"
|
|
|
|
|
+ name="name"
|
|
|
|
|
+ value={formData.name}
|
|
|
|
|
+ onChange={handleInputChange}
|
|
|
|
|
+ disabled={status === 'loading' || status === 'success'}
|
|
|
|
|
+ className={`w-full border-b py-2 focus:outline-none transition bg-transparent ${themeClasses.inputBorder} disabled:opacity-50`}
|
|
|
|
|
+ placeholder={t('step1.form.placeholders.name')}
|
|
|
|
|
+ />
|
|
|
</div>
|
|
</div>
|
|
|
<div>
|
|
<div>
|
|
|
<label className={`block text-xs font-bold uppercase mb-1 ${themeClasses.textLight}`}>{t('step1.form.contact')}</label>
|
|
<label className={`block text-xs font-bold uppercase mb-1 ${themeClasses.textLight}`}>{t('step1.form.contact')}</label>
|
|
|
- <input type="text"
|
|
|
|
|
- className={`w-full border-b py-2 focus:outline-none transition bg-transparent ${themeClasses.inputBorder}`}
|
|
|
|
|
- placeholder={t('step1.form.placeholders.contact')} />
|
|
|
|
|
|
|
+ <input
|
|
|
|
|
+ type="email" // Suggest email input
|
|
|
|
|
+ name="contact"
|
|
|
|
|
+ value={formData.contact}
|
|
|
|
|
+ onChange={handleInputChange}
|
|
|
|
|
+ disabled={status === 'loading' || status === 'success'}
|
|
|
|
|
+ className={`w-full border-b py-2 focus:outline-none transition bg-transparent ${themeClasses.inputBorder} disabled:opacity-50`}
|
|
|
|
|
+ placeholder={t('step1.form.placeholders.contact')}
|
|
|
|
|
+ />
|
|
|
</div>
|
|
</div>
|
|
|
<div>
|
|
<div>
|
|
|
<label className={`block text-xs font-bold uppercase mb-1 ${themeClasses.textLight}`}>{t('step1.form.industry')}</label>
|
|
<label className={`block text-xs font-bold uppercase mb-1 ${themeClasses.textLight}`}>{t('step1.form.industry')}</label>
|
|
|
<select
|
|
<select
|
|
|
- className={`w-full border-b py-2 focus:outline-none transition bg-transparent ${themeClasses.inputBorder} ${isDark ? 'text-stone-300' : 'text-slate-700'}`}>
|
|
|
|
|
|
|
+ name="industry"
|
|
|
|
|
+ value={formData.industry}
|
|
|
|
|
+ onChange={handleInputChange}
|
|
|
|
|
+ disabled={status === 'loading' || status === 'success'}
|
|
|
|
|
+ className={`w-full border-b py-2 focus:outline-none transition bg-transparent ${themeClasses.inputBorder} ${isDark ? 'text-stone-300' : 'text-slate-700'} disabled:opacity-50`}>
|
|
|
|
|
+ <option value="" disabled>{currentLang === 'zh' ? '请选择' : 'Select...'}</option>
|
|
|
{(t('step1.form.options', { returnObjects: true }) as string[]).map((opt, i) => (
|
|
{(t('step1.form.options', { returnObjects: true }) as string[]).map((opt, i) => (
|
|
|
- <option key={i} className="text-black">{opt}</option>
|
|
|
|
|
|
|
+ <option key={i} value={opt} className="text-black">{opt}</option>
|
|
|
))}
|
|
))}
|
|
|
</select>
|
|
</select>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
+
|
|
|
|
|
+ {message && (
|
|
|
|
|
+ <div className={`text-sm font-medium ${status === 'success' ? 'text-green-500' : 'text-red-500'}`}>
|
|
|
|
|
+ {message}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ )}
|
|
|
|
|
+
|
|
|
<button
|
|
<button
|
|
|
- className={`w-full py-4 mt-8 font-medium transition rounded-sm ${themeClasses.buttonPrimary}`}>
|
|
|
|
|
- {t('step1.form.btn_submit')}
|
|
|
|
|
|
|
+ type="submit"
|
|
|
|
|
+ disabled={status === 'loading' || status === 'success'}
|
|
|
|
|
+ className={`w-full py-4 mt-8 font-medium transition rounded-sm ${themeClasses.buttonPrimary} disabled:opacity-50 disabled:cursor-not-allowed`}>
|
|
|
|
|
+ {status === 'loading' ? (currentLang === 'zh' ? '提交中...' : 'Submitting...') : t('step1.form.btn_submit')}
|
|
|
</button>
|
|
</button>
|
|
|
</form>
|
|
</form>
|
|
|
</div>
|
|
</div>
|