updates
This commit is contained in:
@@ -47,7 +47,7 @@ const SettingsPage: React.FC = () => {
|
||||
const { currency, supportedCurrencies, refreshCurrency } = useCurrency();
|
||||
const [activeTab, setActiveTab] = useState<SettingsTab>('general');
|
||||
|
||||
// Cookie Settings State
|
||||
|
||||
const [policy, setPolicy] = useState<CookiePolicySettings>({
|
||||
analytics_enabled: true,
|
||||
marketing_enabled: true,
|
||||
@@ -61,10 +61,10 @@ const SettingsPage: React.FC = () => {
|
||||
Pick<CookiePolicySettingsResponse, 'updated_at' | 'updated_by'> | null
|
||||
>(null);
|
||||
|
||||
// Currency Settings State
|
||||
|
||||
const [selectedCurrency, setSelectedCurrency] = useState<string>(currency);
|
||||
|
||||
// Stripe Settings State
|
||||
|
||||
const [stripeSettings, setStripeSettings] = useState<StripeSettingsResponse['data'] | null>(null);
|
||||
const [formData, setFormData] = useState<UpdateStripeSettingsRequest>({
|
||||
stripe_secret_key: '',
|
||||
@@ -74,7 +74,7 @@ const SettingsPage: React.FC = () => {
|
||||
const [showSecretKey, setShowSecretKey] = useState(false);
|
||||
const [showWebhookSecret, setShowWebhookSecret] = useState(false);
|
||||
|
||||
// PayPal Settings State
|
||||
|
||||
const [paypalSettings, setPaypalSettings] = useState<PayPalSettingsResponse['data'] | null>(null);
|
||||
const [paypalFormData, setPaypalFormData] = useState<UpdatePayPalSettingsRequest>({
|
||||
paypal_client_id: '',
|
||||
@@ -83,7 +83,7 @@ const SettingsPage: React.FC = () => {
|
||||
});
|
||||
const [showPayPalSecret, setShowPayPalSecret] = useState(false);
|
||||
|
||||
// SMTP Settings State
|
||||
|
||||
const [smtpSettings, setSmtpSettings] = useState<SmtpSettingsResponse['data'] | null>(null);
|
||||
const [smtpFormData, setSmtpFormData] = useState<UpdateSmtpSettingsRequest>({
|
||||
smtp_host: '',
|
||||
@@ -98,7 +98,7 @@ const SettingsPage: React.FC = () => {
|
||||
const [testingEmail, setTestingEmail] = useState(false);
|
||||
const [testEmailAddress, setTestEmailAddress] = useState('email@example.com');
|
||||
|
||||
// Company Settings State
|
||||
|
||||
const [companySettings, setCompanySettings] = useState<CompanySettingsResponse['data'] | null>(null);
|
||||
const [companyFormData, setCompanyFormData] = useState<UpdateCompanySettingsRequest>({
|
||||
company_name: '',
|
||||
@@ -113,7 +113,7 @@ const SettingsPage: React.FC = () => {
|
||||
const [uploadingLogo, setUploadingLogo] = useState(false);
|
||||
const [uploadingFavicon, setUploadingFavicon] = useState(false);
|
||||
|
||||
// reCAPTCHA Settings State
|
||||
|
||||
const [recaptchaSettings, setRecaptchaSettings] = useState<RecaptchaSettingsAdminResponse['data'] | null>(null);
|
||||
const [recaptchaFormData, setRecaptchaFormData] = useState<UpdateRecaptchaSettingsRequest>({
|
||||
recaptcha_site_key: '',
|
||||
@@ -145,7 +145,7 @@ const SettingsPage: React.FC = () => {
|
||||
return `${name} (${symbol})`;
|
||||
};
|
||||
|
||||
// Load all settings
|
||||
|
||||
useEffect(() => {
|
||||
loadAllSettings();
|
||||
}, []);
|
||||
@@ -236,7 +236,7 @@ const SettingsPage: React.FC = () => {
|
||||
tax_rate: companyRes.data.tax_rate || 0,
|
||||
});
|
||||
|
||||
// Set previews if URLs exist
|
||||
|
||||
if (companyRes.data.company_logo_url) {
|
||||
const baseUrl = import.meta.env.VITE_API_URL || 'http://localhost:8000';
|
||||
const logoUrl = companyRes.data.company_logo_url.startsWith('http')
|
||||
@@ -257,7 +257,7 @@ const SettingsPage: React.FC = () => {
|
||||
}
|
||||
};
|
||||
|
||||
// Cookie Settings Handlers
|
||||
|
||||
const handleToggle = (key: keyof CookiePolicySettings) => {
|
||||
setPolicy((prev) => ({
|
||||
...prev,
|
||||
@@ -286,7 +286,7 @@ const SettingsPage: React.FC = () => {
|
||||
}
|
||||
};
|
||||
|
||||
// Currency Settings Handlers
|
||||
|
||||
const handleSaveCurrency = async () => {
|
||||
try {
|
||||
setSaving(true);
|
||||
@@ -301,7 +301,7 @@ const SettingsPage: React.FC = () => {
|
||||
}
|
||||
};
|
||||
|
||||
// Stripe Settings Handlers
|
||||
|
||||
const handleSaveStripe = async () => {
|
||||
try {
|
||||
setSaving(true);
|
||||
@@ -340,7 +340,7 @@ const SettingsPage: React.FC = () => {
|
||||
}
|
||||
};
|
||||
|
||||
// PayPal Settings Handlers
|
||||
|
||||
const handleSavePayPal = async () => {
|
||||
try {
|
||||
setSaving(true);
|
||||
@@ -379,7 +379,7 @@ const SettingsPage: React.FC = () => {
|
||||
}
|
||||
};
|
||||
|
||||
// SMTP Settings Handlers
|
||||
|
||||
const handleSaveSmtp = async () => {
|
||||
try {
|
||||
setSaving(true);
|
||||
@@ -433,14 +433,14 @@ const SettingsPage: React.FC = () => {
|
||||
}
|
||||
};
|
||||
|
||||
// Test Email Handler
|
||||
|
||||
const handleTestEmail = async () => {
|
||||
if (!testEmailAddress || !testEmailAddress.trim()) {
|
||||
toast.error('Please enter an email address');
|
||||
return;
|
||||
}
|
||||
|
||||
// Basic email validation
|
||||
|
||||
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||||
if (!emailRegex.test(testEmailAddress.trim())) {
|
||||
toast.error('Please enter a valid email address');
|
||||
@@ -462,13 +462,13 @@ const SettingsPage: React.FC = () => {
|
||||
}
|
||||
};
|
||||
|
||||
// Company Settings Handlers
|
||||
|
||||
const handleSaveCompany = async () => {
|
||||
try {
|
||||
setSaving(true);
|
||||
await systemSettingsService.updateCompanySettings(companyFormData);
|
||||
await loadCompanySettings();
|
||||
// Refresh company settings context to update all components
|
||||
|
||||
if (typeof window !== 'undefined') {
|
||||
window.dispatchEvent(new CustomEvent('refreshCompanySettings'));
|
||||
}
|
||||
@@ -488,19 +488,19 @@ const SettingsPage: React.FC = () => {
|
||||
const file = e.target.files?.[0];
|
||||
if (!file) return;
|
||||
|
||||
// Validate file type
|
||||
|
||||
if (!file.type.startsWith('image/')) {
|
||||
toast.error('Please select an image file');
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate file size (max 2MB)
|
||||
|
||||
if (file.size > 2 * 1024 * 1024) {
|
||||
toast.error('Logo size must be less than 2MB');
|
||||
return;
|
||||
}
|
||||
|
||||
// Create preview
|
||||
|
||||
const reader = new FileReader();
|
||||
reader.onloadend = () => {
|
||||
setLogoPreview(reader.result as string);
|
||||
@@ -512,7 +512,7 @@ const SettingsPage: React.FC = () => {
|
||||
const response = await systemSettingsService.uploadCompanyLogo(file);
|
||||
if (response.status === 'success') {
|
||||
await loadCompanySettings();
|
||||
// Refresh company settings context to update all components
|
||||
|
||||
if (typeof window !== 'undefined') {
|
||||
window.dispatchEvent(new CustomEvent('refreshCompanySettings'));
|
||||
}
|
||||
@@ -527,7 +527,7 @@ const SettingsPage: React.FC = () => {
|
||||
setLogoPreview(null);
|
||||
} finally {
|
||||
setUploadingLogo(false);
|
||||
// Reset input
|
||||
|
||||
e.target.value = '';
|
||||
}
|
||||
};
|
||||
@@ -536,7 +536,7 @@ const SettingsPage: React.FC = () => {
|
||||
const file = e.target.files?.[0];
|
||||
if (!file) return;
|
||||
|
||||
// Validate file type (ico, png, svg)
|
||||
|
||||
const validTypes = ['image/x-icon', 'image/vnd.microsoft.icon', 'image/png', 'image/svg+xml'];
|
||||
const validExtensions = ['.ico', '.png', '.svg'];
|
||||
const fileExtension = file.name.toLowerCase().substring(file.name.lastIndexOf('.'));
|
||||
@@ -546,13 +546,13 @@ const SettingsPage: React.FC = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate file size (max 500KB)
|
||||
|
||||
if (file.size > 500 * 1024) {
|
||||
toast.error('Favicon size must be less than 500KB');
|
||||
return;
|
||||
}
|
||||
|
||||
// Create preview
|
||||
|
||||
const reader = new FileReader();
|
||||
reader.onloadend = () => {
|
||||
setFaviconPreview(reader.result as string);
|
||||
@@ -564,12 +564,12 @@ const SettingsPage: React.FC = () => {
|
||||
const response = await systemSettingsService.uploadCompanyFavicon(file);
|
||||
if (response.status === 'success') {
|
||||
await loadCompanySettings();
|
||||
// Refresh company settings context to update all components
|
||||
|
||||
if (typeof window !== 'undefined') {
|
||||
window.dispatchEvent(new CustomEvent('refreshCompanySettings'));
|
||||
}
|
||||
toast.success('Favicon uploaded successfully');
|
||||
// Update favicon in document
|
||||
|
||||
const link = document.querySelector("link[rel~='icon']") as HTMLLinkElement;
|
||||
if (link) {
|
||||
link.href = response.data.full_url;
|
||||
@@ -589,7 +589,7 @@ const SettingsPage: React.FC = () => {
|
||||
setFaviconPreview(null);
|
||||
} finally {
|
||||
setUploadingFavicon(false);
|
||||
// Reset input
|
||||
|
||||
e.target.value = '';
|
||||
}
|
||||
};
|
||||
@@ -646,9 +646,9 @@ const SettingsPage: React.FC = () => {
|
||||
return (
|
||||
<div className="min-h-screen bg-gradient-to-br from-slate-50 via-white to-slate-50">
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8 space-y-10 animate-fade-in">
|
||||
{/* Luxury Header */}
|
||||
{}
|
||||
<div className="relative">
|
||||
{/* Background decorative elements */}
|
||||
{}
|
||||
<div className="absolute inset-0 bg-gradient-to-r from-amber-400/5 via-transparent to-amber-600/5 rounded-3xl blur-3xl"></div>
|
||||
<div className="relative bg-white/80 backdrop-blur-xl rounded-3xl shadow-2xl border border-amber-200/30 p-8 md:p-10">
|
||||
<div className="flex flex-col md:flex-row md:items-center md:justify-between gap-8">
|
||||
@@ -674,7 +674,7 @@ const SettingsPage: React.FC = () => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Premium Tab Navigation */}
|
||||
{}
|
||||
<div className="mt-10 pt-8 border-t border-gradient-to-r from-transparent via-amber-200/30 to-transparent">
|
||||
<div className="flex flex-wrap gap-3">
|
||||
{tabs.map((tab) => {
|
||||
@@ -710,7 +710,7 @@ const SettingsPage: React.FC = () => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* General Overview Tab */}
|
||||
{}
|
||||
{activeTab === 'general' && (
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 lg:gap-8">
|
||||
<div
|
||||
@@ -904,10 +904,10 @@ const SettingsPage: React.FC = () => {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Cookie & Privacy Tab */}
|
||||
{}
|
||||
{activeTab === 'cookie' && (
|
||||
<div className="space-y-8">
|
||||
{/* Section Header */}
|
||||
{}
|
||||
<div className="bg-white/90 backdrop-blur-xl rounded-2xl shadow-xl border border-gray-200/50 p-8">
|
||||
<div className="flex flex-col md:flex-row md:items-center md:justify-between gap-6">
|
||||
<div className="space-y-3">
|
||||
@@ -936,7 +936,7 @@ const SettingsPage: React.FC = () => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Info Card */}
|
||||
{}
|
||||
<div className="relative bg-gradient-to-br from-blue-50/80 via-indigo-50/60 to-blue-50/80 backdrop-blur-xl rounded-2xl shadow-xl border border-blue-200/50 p-8 overflow-hidden">
|
||||
<div className="absolute top-0 right-0 w-64 h-64 bg-gradient-to-br from-blue-400/20 to-transparent rounded-bl-full"></div>
|
||||
<div className="relative flex gap-6">
|
||||
@@ -956,7 +956,7 @@ const SettingsPage: React.FC = () => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Cookie Toggles */}
|
||||
{}
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
|
||||
{[
|
||||
{ key: 'analytics_enabled' as keyof CookiePolicySettings, label: 'Analytics Cookies', desc: 'Anonymous traffic and performance measurement', color: 'emerald' as const, icon: SlidersHorizontal },
|
||||
@@ -1023,7 +1023,7 @@ const SettingsPage: React.FC = () => {
|
||||
})}
|
||||
</div>
|
||||
|
||||
{/* Integration IDs */}
|
||||
{}
|
||||
<div className="relative bg-white/90 backdrop-blur-xl rounded-2xl shadow-xl border border-gray-200/50 p-8">
|
||||
<div className="space-y-8">
|
||||
<div className="flex items-start gap-4 pb-6 border-b border-gray-200/60">
|
||||
@@ -1086,10 +1086,10 @@ const SettingsPage: React.FC = () => {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Currency Tab */}
|
||||
{}
|
||||
{activeTab === 'currency' && (
|
||||
<div className="space-y-8">
|
||||
{/* Section Header */}
|
||||
{}
|
||||
<div className="bg-white/90 backdrop-blur-xl rounded-2xl shadow-xl border border-gray-200/50 p-8">
|
||||
<div className="flex flex-col md:flex-row md:items-center md:justify-between gap-6">
|
||||
<div className="space-y-3">
|
||||
@@ -1118,7 +1118,7 @@ const SettingsPage: React.FC = () => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Info Card */}
|
||||
{}
|
||||
<div className="relative bg-gradient-to-br from-emerald-50/80 via-green-50/60 to-emerald-50/80 backdrop-blur-xl rounded-2xl shadow-xl border border-emerald-200/50 p-8 overflow-hidden">
|
||||
<div className="absolute top-0 right-0 w-64 h-64 bg-gradient-to-br from-emerald-400/20 to-transparent rounded-bl-full"></div>
|
||||
<div className="relative flex gap-6">
|
||||
@@ -1138,7 +1138,7 @@ const SettingsPage: React.FC = () => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Currency Selection */}
|
||||
{}
|
||||
<div className="relative bg-white/90 backdrop-blur-xl rounded-2xl shadow-xl border border-gray-200/50 p-8">
|
||||
<div className="space-y-8">
|
||||
<div className="flex items-start gap-4 pb-6 border-b border-gray-200/60">
|
||||
@@ -1180,10 +1180,10 @@ const SettingsPage: React.FC = () => {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Payment Tab */}
|
||||
{}
|
||||
{activeTab === 'payment' && (
|
||||
<div className="space-y-8">
|
||||
{/* Section Header */}
|
||||
{}
|
||||
<div className="bg-white/90 backdrop-blur-xl rounded-2xl shadow-xl border border-gray-200/50 p-8">
|
||||
<div className="flex flex-col md:flex-row md:items-center md:justify-between gap-6">
|
||||
<div className="space-y-3">
|
||||
@@ -1212,7 +1212,7 @@ const SettingsPage: React.FC = () => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Info Card */}
|
||||
{}
|
||||
<div className="relative bg-gradient-to-br from-indigo-50/80 via-purple-50/60 to-indigo-50/80 backdrop-blur-xl rounded-2xl shadow-xl border border-indigo-200/50 p-8 overflow-hidden">
|
||||
<div className="absolute top-0 right-0 w-64 h-64 bg-gradient-to-br from-indigo-400/20 to-transparent rounded-bl-full"></div>
|
||||
<div className="relative flex gap-6">
|
||||
@@ -1237,7 +1237,7 @@ const SettingsPage: React.FC = () => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Stripe Settings Form */}
|
||||
{}
|
||||
<div className="relative bg-white/90 backdrop-blur-xl rounded-2xl shadow-xl border border-gray-200/50 p-8">
|
||||
<div className="space-y-8">
|
||||
<div className="flex items-start gap-4 pb-6 border-b border-gray-200/60">
|
||||
@@ -1261,7 +1261,7 @@ const SettingsPage: React.FC = () => {
|
||||
</div>
|
||||
|
||||
<div className="space-y-8">
|
||||
{/* Secret Key */}
|
||||
{}
|
||||
<div className="space-y-4">
|
||||
<label className="flex items-center gap-2 text-sm font-bold text-gray-900 tracking-wide">
|
||||
<Lock className="w-4 h-4 text-gray-600" />
|
||||
@@ -1306,7 +1306,7 @@ const SettingsPage: React.FC = () => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Publishable Key */}
|
||||
{}
|
||||
<div className="space-y-4">
|
||||
<label className="flex items-center gap-2 text-sm font-bold text-gray-900 tracking-wide">
|
||||
<Globe className="w-4 h-4 text-gray-600" />
|
||||
@@ -1337,7 +1337,7 @@ const SettingsPage: React.FC = () => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Webhook Secret */}
|
||||
{}
|
||||
<div className="space-y-4">
|
||||
<label className="flex items-center gap-2 text-sm font-bold text-gray-900 tracking-wide">
|
||||
<Lock className="w-4 h-4 text-gray-600" />
|
||||
@@ -1385,7 +1385,7 @@ const SettingsPage: React.FC = () => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Webhook URL Info */}
|
||||
{}
|
||||
<div className="relative mt-8 p-6 bg-gradient-to-br from-yellow-50 to-amber-50/50 border border-yellow-200/60 rounded-xl overflow-hidden">
|
||||
<div className="absolute top-0 right-0 w-32 h-32 bg-gradient-to-br from-yellow-400/20 to-transparent rounded-bl-full"></div>
|
||||
<div className="relative space-y-3">
|
||||
@@ -1393,7 +1393,7 @@ const SettingsPage: React.FC = () => {
|
||||
<p className="text-sm text-yellow-800">
|
||||
Configure this URL in your{' '}
|
||||
<a
|
||||
href="https://dashboard.stripe.com/webhooks"
|
||||
href="https://dashboard.stripe.com/test/apikeys"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="underline font-medium hover:text-yellow-900"
|
||||
@@ -1414,7 +1414,7 @@ const SettingsPage: React.FC = () => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* PayPal Payment Settings Section */}
|
||||
{}
|
||||
<div className="relative bg-white/90 backdrop-blur-xl rounded-2xl shadow-xl border border-gray-200/50 p-8">
|
||||
<div className="flex flex-col md:flex-row md:items-center md:justify-between gap-6 mb-8">
|
||||
<div className="space-y-3">
|
||||
@@ -1442,7 +1442,7 @@ const SettingsPage: React.FC = () => {
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Info Card */}
|
||||
{}
|
||||
<div className="relative bg-gradient-to-br from-blue-50/80 via-cyan-50/60 to-blue-50/80 backdrop-blur-xl rounded-2xl shadow-xl border border-blue-200/50 p-8 overflow-hidden mb-8">
|
||||
<div className="absolute top-0 right-0 w-64 h-64 bg-gradient-to-br from-blue-400/20 to-transparent rounded-bl-full"></div>
|
||||
<div className="relative flex gap-6">
|
||||
@@ -1467,7 +1467,7 @@ const SettingsPage: React.FC = () => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* PayPal Settings Form */}
|
||||
{}
|
||||
<div className="space-y-8">
|
||||
<div className="flex items-start gap-4 pb-6 border-b border-gray-200/60">
|
||||
<div className="p-3 rounded-xl bg-gradient-to-br from-blue-500/10 to-cyan-500/10 border border-blue-200/40">
|
||||
@@ -1478,7 +1478,7 @@ const SettingsPage: React.FC = () => {
|
||||
<p className="text-sm text-gray-600 leading-relaxed">
|
||||
Get these credentials from your{' '}
|
||||
<a
|
||||
href="https://developer.paypal.com/dashboard"
|
||||
href="https://dashboard.stripe.com/test/apikeys"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-blue-600 hover:text-blue-700 underline font-medium"
|
||||
@@ -1490,7 +1490,7 @@ const SettingsPage: React.FC = () => {
|
||||
</div>
|
||||
|
||||
<div className="space-y-8">
|
||||
{/* Client ID */}
|
||||
{}
|
||||
<div className="space-y-4">
|
||||
<label className="flex items-center gap-2 text-sm font-bold text-gray-900 tracking-wide">
|
||||
<Globe className="w-4 h-4 text-gray-600" />
|
||||
@@ -1520,7 +1520,7 @@ const SettingsPage: React.FC = () => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Client Secret */}
|
||||
{}
|
||||
<div className="space-y-4">
|
||||
<label className="flex items-center gap-2 text-sm font-bold text-gray-900 tracking-wide">
|
||||
<Lock className="w-4 h-4 text-gray-600" />
|
||||
@@ -1563,7 +1563,7 @@ const SettingsPage: React.FC = () => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Mode */}
|
||||
{}
|
||||
<div className="space-y-4">
|
||||
<label className="flex items-center gap-2 text-sm font-bold text-gray-900 tracking-wide">
|
||||
<Globe className="w-4 h-4 text-gray-600" />
|
||||
@@ -1590,10 +1590,10 @@ const SettingsPage: React.FC = () => {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* SMTP Email Server Tab */}
|
||||
{}
|
||||
{activeTab === 'smtp' && (
|
||||
<div className="space-y-8">
|
||||
{/* Section Header */}
|
||||
{}
|
||||
<div className="bg-white/90 backdrop-blur-xl rounded-2xl shadow-xl border border-gray-200/50 p-8">
|
||||
<div className="flex flex-col md:flex-row md:items-center md:justify-between gap-6">
|
||||
<div className="space-y-3">
|
||||
@@ -1624,7 +1624,7 @@ const SettingsPage: React.FC = () => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Test Email Section */}
|
||||
{}
|
||||
<div className="bg-white/90 backdrop-blur-xl rounded-2xl shadow-xl border border-gray-200/50 p-8">
|
||||
<div className="flex items-start gap-4 mb-6">
|
||||
<div className="p-3 rounded-xl bg-gradient-to-br from-teal-500/10 to-cyan-500/10 border border-teal-200/40">
|
||||
@@ -1672,7 +1672,7 @@ const SettingsPage: React.FC = () => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Info Card */}
|
||||
{}
|
||||
<div className="relative bg-gradient-to-br from-teal-50/80 via-cyan-50/60 to-teal-50/80 backdrop-blur-xl rounded-2xl shadow-xl border border-teal-200/50 p-8 overflow-hidden">
|
||||
<div className="absolute top-0 right-0 w-64 h-64 bg-gradient-to-br from-teal-400/20 to-transparent rounded-bl-full"></div>
|
||||
<div className="relative flex gap-6">
|
||||
@@ -1697,7 +1697,7 @@ const SettingsPage: React.FC = () => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* SMTP Settings Form */}
|
||||
{}
|
||||
<div className="relative bg-white/90 backdrop-blur-xl rounded-2xl shadow-xl border border-gray-200/50 p-8">
|
||||
<div className="space-y-8">
|
||||
<div className="flex items-start gap-4 pb-6 border-b border-gray-200/60">
|
||||
@@ -1713,7 +1713,7 @@ const SettingsPage: React.FC = () => {
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
{/* SMTP Host */}
|
||||
{}
|
||||
<div className="space-y-4">
|
||||
<label className="flex items-center gap-2 text-sm font-bold text-gray-900 tracking-wide">
|
||||
<Globe className="w-4 h-4 text-gray-600" />
|
||||
@@ -1744,7 +1744,7 @@ const SettingsPage: React.FC = () => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* SMTP Port */}
|
||||
{}
|
||||
<div className="space-y-4">
|
||||
<label className="flex items-center gap-2 text-sm font-bold text-gray-900 tracking-wide">
|
||||
<Key className="w-4 h-4 text-gray-600" />
|
||||
@@ -1771,7 +1771,7 @@ const SettingsPage: React.FC = () => {
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
{/* SMTP User */}
|
||||
{}
|
||||
<div className="space-y-4">
|
||||
<label className="flex items-center gap-2 text-sm font-bold text-gray-900 tracking-wide">
|
||||
<Mail className="w-4 h-4 text-gray-600" />
|
||||
@@ -1802,7 +1802,7 @@ const SettingsPage: React.FC = () => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* SMTP Password */}
|
||||
{}
|
||||
<div className="space-y-4">
|
||||
<label className="flex items-center gap-2 text-sm font-bold text-gray-900 tracking-wide">
|
||||
<Lock className="w-4 h-4 text-gray-600" />
|
||||
@@ -1848,7 +1848,7 @@ const SettingsPage: React.FC = () => {
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
{/* From Email */}
|
||||
{}
|
||||
<div className="space-y-4">
|
||||
<label className="flex items-center gap-2 text-sm font-bold text-gray-900 tracking-wide">
|
||||
<Mail className="w-4 h-4 text-gray-600" />
|
||||
@@ -1872,7 +1872,7 @@ const SettingsPage: React.FC = () => {
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* From Name */}
|
||||
{}
|
||||
<div className="space-y-4">
|
||||
<label className="flex items-center gap-2 text-sm font-bold text-gray-900 tracking-wide">
|
||||
<Globe className="w-4 h-4 text-gray-600" />
|
||||
@@ -1897,7 +1897,7 @@ const SettingsPage: React.FC = () => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* TLS/SSL Toggle */}
|
||||
{}
|
||||
<div className="space-y-4">
|
||||
<label className="flex items-center gap-2 text-sm font-bold text-gray-900 tracking-wide">
|
||||
<Lock className="w-4 h-4 text-gray-600" />
|
||||
@@ -1932,7 +1932,7 @@ const SettingsPage: React.FC = () => {
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Common Providers Info */}
|
||||
{}
|
||||
<div className="relative mt-8 p-6 bg-gradient-to-br from-yellow-50 to-amber-50/50 border border-yellow-200/60 rounded-xl overflow-hidden">
|
||||
<div className="absolute top-0 right-0 w-32 h-32 bg-gradient-to-br from-yellow-400/20 to-transparent rounded-bl-full"></div>
|
||||
<div className="relative space-y-3">
|
||||
@@ -1950,10 +1950,10 @@ const SettingsPage: React.FC = () => {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Company Info Tab */}
|
||||
{}
|
||||
{activeTab === 'company' && (
|
||||
<div className="space-y-8">
|
||||
{/* Section Header */}
|
||||
{}
|
||||
<div className="bg-white/90 backdrop-blur-xl rounded-2xl shadow-xl border border-gray-200/50 p-8">
|
||||
<div className="flex flex-col md:flex-row md:items-center md:justify-between gap-6">
|
||||
<div className="space-y-3">
|
||||
@@ -1982,9 +1982,9 @@ const SettingsPage: React.FC = () => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Logo & Favicon Upload Section */}
|
||||
{}
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
{/* Logo Upload */}
|
||||
{}
|
||||
<div className="bg-white/90 backdrop-blur-xl rounded-2xl shadow-xl border border-gray-200/50 p-8">
|
||||
<div className="flex items-start gap-4 mb-6">
|
||||
<div className="p-3 rounded-xl bg-gradient-to-br from-purple-500/10 to-pink-500/10 border border-purple-200/40">
|
||||
@@ -2025,17 +2025,9 @@ const SettingsPage: React.FC = () => {
|
||||
disabled={uploadingLogo}
|
||||
/>
|
||||
</label>
|
||||
|
||||
{uploadingLogo && (
|
||||
<div className="flex items-center justify-center text-sm text-gray-600">
|
||||
<div className="animate-spin rounded-full h-4 w-4 border-b-2 border-purple-600 mr-2"></div>
|
||||
Uploading logo...
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Favicon Upload */}
|
||||
<div className="bg-white/90 backdrop-blur-xl rounded-2xl shadow-xl border border-gray-200/50 p-8">
|
||||
<div className="flex items-start gap-4 mb-6">
|
||||
<div className="p-3 rounded-xl bg-gradient-to-br from-purple-500/10 to-pink-500/10 border border-purple-200/40">
|
||||
@@ -2087,7 +2079,7 @@ const SettingsPage: React.FC = () => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Company Information Form */}
|
||||
{}
|
||||
<div className="relative bg-white/90 backdrop-blur-xl rounded-2xl shadow-xl border border-gray-200/50 p-8">
|
||||
<div className="space-y-8">
|
||||
<div className="flex items-start gap-4 pb-6 border-b border-gray-200/60">
|
||||
@@ -2103,7 +2095,7 @@ const SettingsPage: React.FC = () => {
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 gap-6">
|
||||
{/* Company Name */}
|
||||
{}
|
||||
<div className="space-y-4">
|
||||
<label className="flex items-center gap-2 text-sm font-bold text-gray-900 tracking-wide">
|
||||
<Building2 className="w-4 h-4 text-gray-600" />
|
||||
@@ -2123,7 +2115,7 @@ const SettingsPage: React.FC = () => {
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Company Tagline */}
|
||||
{}
|
||||
<div className="space-y-4">
|
||||
<label className="flex items-center gap-2 text-sm font-bold text-gray-900 tracking-wide">
|
||||
<Sparkles className="w-4 h-4 text-gray-600" />
|
||||
@@ -2145,7 +2137,7 @@ const SettingsPage: React.FC = () => {
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
{/* Phone */}
|
||||
{}
|
||||
<div className="space-y-4">
|
||||
<label className="flex items-center gap-2 text-sm font-bold text-gray-900 tracking-wide">
|
||||
<Globe className="w-4 h-4 text-gray-600" />
|
||||
@@ -2165,7 +2157,7 @@ const SettingsPage: React.FC = () => {
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Email */}
|
||||
{}
|
||||
<div className="space-y-4">
|
||||
<label className="flex items-center gap-2 text-sm font-bold text-gray-900 tracking-wide">
|
||||
<Mail className="w-4 h-4 text-gray-600" />
|
||||
@@ -2186,7 +2178,7 @@ const SettingsPage: React.FC = () => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Address */}
|
||||
{}
|
||||
<div className="space-y-4">
|
||||
<label className="flex items-center gap-2 text-sm font-bold text-gray-900 tracking-wide">
|
||||
<Globe className="w-4 h-4 text-gray-600" />
|
||||
@@ -2206,7 +2198,7 @@ const SettingsPage: React.FC = () => {
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Tax Rate */}
|
||||
{}
|
||||
<div className="space-y-4">
|
||||
<label className="flex items-center gap-2 text-sm font-bold text-gray-900 tracking-wide">
|
||||
<DollarSign className="w-4 h-4 text-gray-600" />
|
||||
@@ -2231,7 +2223,7 @@ const SettingsPage: React.FC = () => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Info Card */}
|
||||
{}
|
||||
<div className="relative bg-gradient-to-br from-purple-50/80 via-pink-50/60 to-purple-50/80 backdrop-blur-xl rounded-2xl shadow-xl border border-purple-200/50 p-8 overflow-hidden">
|
||||
<div className="absolute top-0 right-0 w-64 h-64 bg-gradient-to-br from-purple-400/20 to-transparent rounded-bl-full"></div>
|
||||
<div className="relative flex gap-6">
|
||||
@@ -2255,7 +2247,7 @@ const SettingsPage: React.FC = () => {
|
||||
|
||||
{activeTab === 'recaptcha' && (
|
||||
<div className="space-y-8">
|
||||
{/* Section Header */}
|
||||
{}
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<h2 className="text-2xl font-bold text-gray-900 flex items-center gap-3">
|
||||
@@ -2268,10 +2260,10 @@ const SettingsPage: React.FC = () => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* reCAPTCHA Settings Form */}
|
||||
{}
|
||||
<div className="bg-white rounded-xl shadow-lg border border-gray-200 p-8">
|
||||
<div className="space-y-6">
|
||||
{/* Enable/Disable Toggle */}
|
||||
{}
|
||||
<div className="flex items-center justify-between p-4 bg-gray-50 rounded-lg border border-gray-200">
|
||||
<div>
|
||||
<label className="text-sm font-semibold text-gray-900">
|
||||
@@ -2297,7 +2289,7 @@ const SettingsPage: React.FC = () => {
|
||||
</label>
|
||||
</div>
|
||||
|
||||
{/* Site Key */}
|
||||
{}
|
||||
<div className="space-y-2">
|
||||
<label className="flex items-center gap-2 text-sm font-bold text-gray-900 tracking-wide">
|
||||
<Key className="w-4 h-4 text-gray-600" />
|
||||
@@ -2328,7 +2320,7 @@ const SettingsPage: React.FC = () => {
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Secret Key */}
|
||||
{}
|
||||
<div className="space-y-2">
|
||||
<label className="flex items-center gap-2 text-sm font-bold text-gray-900 tracking-wide">
|
||||
<Lock className="w-4 h-4 text-gray-600" />
|
||||
@@ -2369,7 +2361,7 @@ const SettingsPage: React.FC = () => {
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Info Box */}
|
||||
{}
|
||||
<div className="bg-blue-50 border border-blue-200 rounded-lg p-4">
|
||||
<div className="flex items-start gap-3">
|
||||
<Info className="w-5 h-5 text-blue-600 flex-shrink-0 mt-0.5" />
|
||||
@@ -2383,7 +2375,7 @@ const SettingsPage: React.FC = () => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Save Button */}
|
||||
{}
|
||||
<div className="flex justify-end pt-4 border-t border-gray-200">
|
||||
<button
|
||||
onClick={handleSaveRecaptcha}
|
||||
|
||||
Reference in New Issue
Block a user