482 lines
19 KiB
TypeScript
482 lines
19 KiB
TypeScript
import React, { useState, useEffect } from 'react';
|
|
import { IoIosBusiness, IoIosContact, IoIosTime, IoIosRefresh } from 'react-icons/io';
|
|
import sharedStyles from '../PageManager/pages.module.css';
|
|
import styles from './SpeechSettings.module.css';
|
|
import { useLanguage } from '../../contexts/LanguageContext';
|
|
|
|
interface MandateData {
|
|
id: string;
|
|
mandate_general: {
|
|
company_name: string;
|
|
industry: string;
|
|
contact_info: {
|
|
email: string;
|
|
phone: string;
|
|
street: string;
|
|
postal_code: string;
|
|
city: string;
|
|
country: string;
|
|
};
|
|
business_hours: string;
|
|
timezone: string;
|
|
};
|
|
setup_contacts: boolean;
|
|
}
|
|
|
|
interface SpeechSettingsProps {
|
|
onDataUpdate?: (data: MandateData) => void;
|
|
}
|
|
|
|
function SpeechSettings({ onDataUpdate }: SpeechSettingsProps) {
|
|
const { t } = useLanguage();
|
|
const [formData, setFormData] = useState<MandateData | null>(null);
|
|
const [isLoading, setIsLoading] = useState(true);
|
|
const [isSaving, setIsSaving] = useState(false);
|
|
const [saveMessage, setSaveMessage] = useState<{ type: 'success' | 'error', text: string } | null>(null);
|
|
const [focusedFields, setFocusedFields] = useState<Set<string>>(new Set());
|
|
|
|
// Load data from localStorage on component mount
|
|
useEffect(() => {
|
|
const loadSpeechData = () => {
|
|
try {
|
|
const savedData = localStorage.getItem('speechSignUpData');
|
|
const timestamp = localStorage.getItem('speechSignUpTimestamp');
|
|
|
|
if (savedData && timestamp) {
|
|
const parsedData = JSON.parse(savedData);
|
|
const savedTime = parseInt(timestamp);
|
|
const now = Date.now();
|
|
const twentyFourHours = 24 * 60 * 60 * 1000;
|
|
|
|
// Check if data is still valid (within 24 hours)
|
|
if (now - savedTime < twentyFourHours) {
|
|
setFormData(parsedData);
|
|
} else {
|
|
// Data expired, clear it
|
|
localStorage.removeItem('speechSignUpData');
|
|
localStorage.removeItem('speechSignUpTimestamp');
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error('Error loading speech data:', error);
|
|
} finally {
|
|
setIsLoading(false);
|
|
}
|
|
};
|
|
|
|
loadSpeechData();
|
|
}, []);
|
|
|
|
const handleInputChange = (field: string, value: string) => {
|
|
if (!formData) return;
|
|
|
|
const newData = { ...formData };
|
|
const fieldParts = field.split('.');
|
|
|
|
if (fieldParts.length === 2) {
|
|
// Handle nested fields like mandate_general.company_name
|
|
const [parent, child] = fieldParts;
|
|
if (parent === 'mandate_general' && child in newData.mandate_general) {
|
|
(newData.mandate_general as any)[child] = value;
|
|
}
|
|
} else if (fieldParts.length === 3) {
|
|
// Handle deeply nested fields like mandate_general.contact_info.email
|
|
const [parent, child, grandchild] = fieldParts;
|
|
if (parent === 'mandate_general' && child === 'contact_info' && grandchild in newData.mandate_general.contact_info) {
|
|
(newData.mandate_general.contact_info as any)[grandchild] = value;
|
|
}
|
|
} else if (field === 'setup_contacts') {
|
|
newData.setup_contacts = value === 'true';
|
|
}
|
|
|
|
setFormData(newData);
|
|
setSaveMessage(null);
|
|
};
|
|
|
|
const handleFocus = (field: string) => {
|
|
setFocusedFields(prev => new Set(prev).add(field));
|
|
};
|
|
|
|
const handleBlur = (field: string) => {
|
|
setFocusedFields(prev => {
|
|
const newSet = new Set(prev);
|
|
newSet.delete(field);
|
|
return newSet;
|
|
});
|
|
};
|
|
|
|
const handleSave = async () => {
|
|
if (!formData) return;
|
|
|
|
setIsSaving(true);
|
|
try {
|
|
// Save to localStorage
|
|
localStorage.setItem('speechSignUpData', JSON.stringify(formData));
|
|
localStorage.setItem('speechSignUpTimestamp', Date.now().toString());
|
|
|
|
// Dispatch event to notify other components
|
|
window.dispatchEvent(new CustomEvent('speechSignUpChanged'));
|
|
|
|
setSaveMessage({ type: 'success', text: t('speech.settings.save_success') });
|
|
|
|
// Notify parent component if callback provided
|
|
if (onDataUpdate) {
|
|
onDataUpdate(formData);
|
|
}
|
|
|
|
// Clear message after 3 seconds
|
|
setTimeout(() => setSaveMessage(null), 3000);
|
|
} catch (error) {
|
|
console.error('Error saving speech settings:', error);
|
|
setSaveMessage({ type: 'error', text: t('speech.settings.save_error') });
|
|
} finally {
|
|
setIsSaving(false);
|
|
}
|
|
};
|
|
|
|
const handleReset = () => {
|
|
if (window.confirm(t('speech.settings.reset_confirm'))) {
|
|
localStorage.removeItem('speechSignUpData');
|
|
localStorage.removeItem('speechSignUpTimestamp');
|
|
window.dispatchEvent(new CustomEvent('speechSignUpChanged'));
|
|
setFormData(null);
|
|
setSaveMessage({ type: 'success', text: t('speech.settings.reset_success') });
|
|
setTimeout(() => setSaveMessage(null), 3000);
|
|
}
|
|
};
|
|
|
|
if (isLoading) {
|
|
return (
|
|
<div className={styles.container}>
|
|
<div className={styles.loading}>
|
|
{t('common.loading')}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
if (!formData) {
|
|
return (
|
|
<div className={styles.container}>
|
|
<div className={styles.noData}>
|
|
<p>{t('speech.settings.no_data')}</p>
|
|
<button
|
|
className={sharedStyles.primaryButton}
|
|
onClick={() => window.location.href = '/speech'}
|
|
>
|
|
{t('speech.settings.sign_up_now')}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div className={styles.container}>
|
|
<div className={styles.header}>
|
|
<h2 className={styles.title}>{t('speech.settings.title')}</h2>
|
|
<p className={styles.description}>{t('speech.settings.description')}</p>
|
|
</div>
|
|
|
|
{saveMessage && (
|
|
<div className={`${styles.message} ${saveMessage.type === 'success' ? styles.successMessage : styles.errorMessage}`}>
|
|
{saveMessage.text}
|
|
</div>
|
|
)}
|
|
|
|
<div className={styles.form}>
|
|
{/* Company Information Section */}
|
|
<div className={styles.section}>
|
|
<div className={styles.sectionHeader}>
|
|
<IoIosBusiness className={styles.sectionIcon} />
|
|
<h3 className={styles.sectionTitle}>{t('speech.settings.company_info')}</h3>
|
|
</div>
|
|
|
|
<div className={styles.formRow}>
|
|
<div className={styles.formField}>
|
|
<div className={styles.inputContainer}>
|
|
<input
|
|
type="text"
|
|
id="company_name"
|
|
className={styles.formInput}
|
|
value={formData.mandate_general.company_name}
|
|
onChange={(e) => handleInputChange('mandate_general.company_name', e.target.value)}
|
|
onFocus={() => handleFocus('company_name')}
|
|
onBlur={() => handleBlur('company_name')}
|
|
required
|
|
/>
|
|
<label
|
|
htmlFor="company_name"
|
|
className={`${styles.floatingLabel} ${formData.mandate_general.company_name || focusedFields.has('company_name') ? styles.floatingLabelActive : ''}`}
|
|
>
|
|
{t('speech.signup.company_name')} *
|
|
</label>
|
|
</div>
|
|
</div>
|
|
|
|
<div className={styles.formField}>
|
|
<div className={styles.inputContainer}>
|
|
<input
|
|
type="text"
|
|
id="industry"
|
|
className={styles.formInput}
|
|
value={formData.mandate_general.industry}
|
|
onChange={(e) => handleInputChange('mandate_general.industry', e.target.value)}
|
|
onFocus={() => handleFocus('industry')}
|
|
onBlur={() => handleBlur('industry')}
|
|
required
|
|
/>
|
|
<label
|
|
htmlFor="industry"
|
|
className={`${styles.floatingLabel} ${formData.mandate_general.industry || focusedFields.has('industry') ? styles.floatingLabelActive : ''}`}
|
|
>
|
|
{t('speech.signup.industry')} *
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Contact Information Section */}
|
|
<div className={styles.section}>
|
|
<div className={styles.sectionHeader}>
|
|
<IoIosContact className={styles.sectionIcon} />
|
|
<h3 className={styles.sectionTitle}>{t('speech.settings.contact_info')}</h3>
|
|
</div>
|
|
|
|
<div className={styles.formRow}>
|
|
<div className={styles.formField}>
|
|
<div className={styles.inputContainer}>
|
|
<input
|
|
type="email"
|
|
id="email"
|
|
className={styles.formInput}
|
|
value={formData.mandate_general.contact_info.email}
|
|
onChange={(e) => handleInputChange('mandate_general.contact_info.email', e.target.value)}
|
|
onFocus={() => handleFocus('email')}
|
|
onBlur={() => handleBlur('email')}
|
|
required
|
|
/>
|
|
<label
|
|
htmlFor="email"
|
|
className={`${styles.floatingLabel} ${formData.mandate_general.contact_info.email || focusedFields.has('email') ? styles.floatingLabelActive : ''}`}
|
|
>
|
|
{t('speech.signup.email')} *
|
|
</label>
|
|
</div>
|
|
</div>
|
|
|
|
<div className={styles.formField}>
|
|
<div className={styles.inputContainer}>
|
|
<input
|
|
type="tel"
|
|
id="phone"
|
|
className={styles.formInput}
|
|
value={formData.mandate_general.contact_info.phone}
|
|
onChange={(e) => handleInputChange('mandate_general.contact_info.phone', e.target.value)}
|
|
onFocus={() => handleFocus('phone')}
|
|
onBlur={() => handleBlur('phone')}
|
|
required
|
|
/>
|
|
<label
|
|
htmlFor="phone"
|
|
className={`${styles.floatingLabel} ${formData.mandate_general.contact_info.phone || focusedFields.has('phone') ? styles.floatingLabelActive : ''}`}
|
|
>
|
|
{t('speech.signup.phone')} *
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div className={styles.formRow}>
|
|
<div className={styles.formField}>
|
|
<div className={styles.inputContainer}>
|
|
<input
|
|
type="text"
|
|
id="street"
|
|
className={styles.formInput}
|
|
value={formData.mandate_general.contact_info.street}
|
|
onChange={(e) => handleInputChange('mandate_general.contact_info.street', e.target.value)}
|
|
onFocus={() => handleFocus('street')}
|
|
onBlur={() => handleBlur('street')}
|
|
required
|
|
/>
|
|
<label
|
|
htmlFor="street"
|
|
className={`${styles.floatingLabel} ${formData.mandate_general.contact_info.street || focusedFields.has('street') ? styles.floatingLabelActive : ''}`}
|
|
>
|
|
{t('speech.signup.street')} *
|
|
</label>
|
|
</div>
|
|
</div>
|
|
|
|
<div className={styles.formField}>
|
|
<div className={styles.inputContainer}>
|
|
<input
|
|
type="text"
|
|
id="postal_code"
|
|
className={styles.formInput}
|
|
value={formData.mandate_general.contact_info.postal_code}
|
|
onChange={(e) => handleInputChange('mandate_general.contact_info.postal_code', e.target.value)}
|
|
onFocus={() => handleFocus('postal_code')}
|
|
onBlur={() => handleBlur('postal_code')}
|
|
required
|
|
/>
|
|
<label
|
|
htmlFor="postal_code"
|
|
className={`${styles.floatingLabel} ${formData.mandate_general.contact_info.postal_code || focusedFields.has('postal_code') ? styles.floatingLabelActive : ''}`}
|
|
>
|
|
{t('speech.signup.postal_code')} *
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div className={styles.formRow}>
|
|
<div className={styles.formField}>
|
|
<div className={styles.inputContainer}>
|
|
<input
|
|
type="text"
|
|
id="city"
|
|
className={styles.formInput}
|
|
value={formData.mandate_general.contact_info.city}
|
|
onChange={(e) => handleInputChange('mandate_general.contact_info.city', e.target.value)}
|
|
onFocus={() => handleFocus('city')}
|
|
onBlur={() => handleBlur('city')}
|
|
required
|
|
/>
|
|
<label
|
|
htmlFor="city"
|
|
className={`${styles.floatingLabel} ${formData.mandate_general.contact_info.city || focusedFields.has('city') ? styles.floatingLabelActive : ''}`}
|
|
>
|
|
{t('speech.signup.city')} *
|
|
</label>
|
|
</div>
|
|
</div>
|
|
|
|
<div className={styles.formField}>
|
|
<div className={styles.inputContainer}>
|
|
<input
|
|
type="text"
|
|
id="country"
|
|
className={styles.formInput}
|
|
value={formData.mandate_general.contact_info.country}
|
|
onChange={(e) => handleInputChange('mandate_general.contact_info.country', e.target.value)}
|
|
onFocus={() => handleFocus('country')}
|
|
onBlur={() => handleBlur('country')}
|
|
required
|
|
/>
|
|
<label
|
|
htmlFor="country"
|
|
className={`${styles.floatingLabel} ${formData.mandate_general.contact_info.country || focusedFields.has('country') ? styles.floatingLabelActive : ''}`}
|
|
>
|
|
{t('speech.signup.country')} *
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Business Hours Section */}
|
|
<div className={styles.section}>
|
|
<div className={styles.sectionHeader}>
|
|
<IoIosTime className={styles.sectionIcon} />
|
|
<h3 className={styles.sectionTitle}>{t('speech.settings.business_hours')}</h3>
|
|
</div>
|
|
|
|
<div className={styles.formRow}>
|
|
<div className={styles.formField}>
|
|
<div className={styles.inputContainer}>
|
|
<input
|
|
type="text"
|
|
id="business_hours"
|
|
className={styles.formInput}
|
|
value={formData.mandate_general.business_hours}
|
|
onChange={(e) => handleInputChange('mandate_general.business_hours', e.target.value)}
|
|
onFocus={() => handleFocus('business_hours')}
|
|
onBlur={() => handleBlur('business_hours')}
|
|
required
|
|
/>
|
|
<label
|
|
htmlFor="business_hours"
|
|
className={`${styles.floatingLabel} ${formData.mandate_general.business_hours || focusedFields.has('business_hours') ? styles.floatingLabelActive : ''}`}
|
|
>
|
|
{t('speech.signup.business_hours')} *
|
|
</label>
|
|
</div>
|
|
</div>
|
|
|
|
<div className={styles.formField}>
|
|
<div className={styles.inputContainer}>
|
|
<select
|
|
id="timezone"
|
|
className={styles.formSelect}
|
|
value={formData.mandate_general.timezone}
|
|
onChange={(e) => handleInputChange('mandate_general.timezone', e.target.value)}
|
|
onFocus={() => handleFocus('timezone')}
|
|
onBlur={() => handleBlur('timezone')}
|
|
required
|
|
>
|
|
<option value="">{t('speech.signup.select_timezone')}</option>
|
|
<option value="UTC-12">UTC-12 (Baker Island)</option>
|
|
<option value="UTC-11">UTC-11 (American Samoa)</option>
|
|
<option value="UTC-10">UTC-10 (Hawaii)</option>
|
|
<option value="UTC-9">UTC-9 (Alaska)</option>
|
|
<option value="UTC-8">UTC-8 (Pacific Time)</option>
|
|
<option value="UTC-7">UTC-7 (Mountain Time)</option>
|
|
<option value="UTC-6">UTC-6 (Central Time)</option>
|
|
<option value="UTC-5">UTC-5 (Eastern Time)</option>
|
|
<option value="UTC-4">UTC-4 (Atlantic Time)</option>
|
|
<option value="UTC-3">UTC-3 (Brazil)</option>
|
|
<option value="UTC-2">UTC-2 (Mid-Atlantic)</option>
|
|
<option value="UTC-1">UTC-1 (Azores)</option>
|
|
<option value="UTC+0">UTC+0 (Greenwich Mean Time)</option>
|
|
<option value="UTC+1">UTC+1 (Central European Time)</option>
|
|
<option value="UTC+2">UTC+2 (Eastern European Time)</option>
|
|
<option value="UTC+3">UTC+3 (Moscow Time)</option>
|
|
<option value="UTC+4">UTC+4 (Gulf Standard Time)</option>
|
|
<option value="UTC+5">UTC+5 (Pakistan Standard Time)</option>
|
|
<option value="UTC+6">UTC+6 (Bangladesh Standard Time)</option>
|
|
<option value="UTC+7">UTC+7 (Indochina Time)</option>
|
|
<option value="UTC+8">UTC+8 (China Standard Time)</option>
|
|
<option value="UTC+9">UTC+9 (Japan Standard Time)</option>
|
|
<option value="UTC+10">UTC+10 (Australian Eastern Time)</option>
|
|
<option value="UTC+11">UTC+11 (Solomon Islands)</option>
|
|
<option value="UTC+12">UTC+12 (New Zealand)</option>
|
|
</select>
|
|
<label
|
|
htmlFor="timezone"
|
|
className={`${styles.floatingLabel} ${formData.mandate_general.timezone || focusedFields.has('timezone') ? styles.floatingLabelActive : ''}`}
|
|
>
|
|
{t('speech.signup.timezone')} *
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Actions */}
|
|
<div className={styles.actions}>
|
|
<button
|
|
className={sharedStyles.secondaryButton}
|
|
onClick={handleReset}
|
|
disabled={isSaving}
|
|
>
|
|
<IoIosRefresh className={styles.resetIcon} />
|
|
{t('speech.settings.reset')}
|
|
</button>
|
|
|
|
<button
|
|
className={sharedStyles.primaryButton}
|
|
onClick={handleSave}
|
|
disabled={isSaving}
|
|
>
|
|
{isSaving ? t('speech.settings.saving') : t('speech.settings.save')}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export default SpeechSettings;
|