GrantForge Bot
Deploy to Hugging Face
afd56bc
import React, { useState } from 'react';
import { User, Building2, CreditCard, Shield, Sliders, Lock, Settings as SettingsIcon, LogOut, Download, AlertTriangle } from 'lucide-react';
import { useUser, UserProfile, SignOutButton, useClerk } from '@clerk/clerk-react';
import { deleteUserAccount, getAccountExport, getSubscriptionStatus, updateAccountSettings, lookupCompany } from '../api/client';
import toast from 'react-hot-toast';
import { useQuery, useMutation } from '@tanstack/react-query';
import PricingModal from '../components/dashboard/PricingModal';
const Settings: React.FC = () => {
const [activeTab, setActiveTab] = useState('profile');
const { signOut } = useClerk();
const [showDeleteModal, setShowDeleteModal] = useState(false);
const [deleteInput, setDeleteInput] = useState('');
const [isDeleting, setIsDeleting] = useState(false);
const [deleteSuccess, setDeleteSuccess] = useState(false);
const [isExporting, setIsExporting] = useState(false);
// States for Pricing Modal and Companies
const [showPricing, setShowPricing] = useState(false);
const [companies, setCompanies] = useState(() => {
const saved = localStorage.getItem('grantforge_companies');
if (saved) {
try {
return JSON.parse(saved);
} catch (e) {
console.error("Błąd parsowania firm z LocalStorage", e);
}
}
return [
{ nip: '1234567890', name: 'GrantForge sp. z o.o.', city: 'Warszawa', status: 'Zatwierdzone' }
];
});
const [showCompanyModal, setShowCompanyModal] = useState(false);
const [newNip, setNewNip] = useState('');
const [isLookingUp, setIsLookingUp] = useState(false);
const [fetchedCompany, setFetchedCompany] = useState<any>(null);
const { data: subData, isLoading: subLoading, refetch: refetchSub } = useQuery({
queryKey: ['subscription-status'],
queryFn: getSubscriptionStatus
});
const updateSettingsMutation = useMutation({
mutationFn: updateAccountSettings,
onSuccess: () => {
toast.success("Ustawienia zostały zapisane.");
refetchSub();
},
onError: () => {
toast.error("Wystąpił błąd podczas zapisywania ustawień.");
}
});
const handleAddCompany = async () => {
if (!newNip || newNip.length < 10) {
toast.error("Wprowadź prawidłowy NIP (min. 10 cyfr).");
return;
}
setIsLookingUp(true);
try {
const data = await lookupCompany(newNip);
setFetchedCompany({
nip: data.nip,
name: data.name,
city: data.voivodeship,
address: `PKD: ${data.pkd ? data.pkd.join(', ') : 'Brak'}`,
legalForm: `Przychody: ${data.revenue || 'Brak danych'} PLN`
});
toast.success("Pobrano dane z bazy GUS.");
} catch (err: any) {
toast.error(err.response?.data?.detail || "Nie udało się pobrać danych z GUS.");
} finally {
setIsLookingUp(false);
}
};
const handleSaveFetchedCompany = () => {
if (!fetchedCompany) return;
const newCompany = {
nip: fetchedCompany.nip,
name: fetchedCompany.name,
city: fetchedCompany.city,
status: 'Zatwierdzone'
};
const updatedCompanies = [...companies, newCompany];
setCompanies(updatedCompanies);
localStorage.setItem('grantforge_companies', JSON.stringify(updatedCompanies));
setShowCompanyModal(false);
setNewNip('');
setFetchedCompany(null);
toast.success("Podmiot dodany pomyślnie.");
};
const handleRemoveCompany = (nipToRemove: string) => {
const updatedCompanies = companies.filter((c: any) => c.nip !== nipToRemove);
setCompanies(updatedCompanies);
localStorage.setItem('grantforge_companies', JSON.stringify(updatedCompanies));
toast.success("Podmiot został usunięty.");
};
const handleExportData = async () => {
setIsExporting(true);
try {
const data = await getAccountExport();
const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' });
const url = window.URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', `dotacje_ai_export_${new Date().toISOString().split('T')[0]}.json`);
document.body.appendChild(link);
link.click();
link.remove();
toast.success("Dane zostały wyeksportowane.");
} catch (error) {
toast.error("Wystąpił błąd podczas eksportu.");
} finally {
setIsExporting(false);
}
};
const handleDeleteAccount = async () => {
if (deleteInput !== 'USUŃ') return;
setIsDeleting(true);
try {
await deleteUserAccount();
setDeleteSuccess(true);
setShowDeleteModal(false);
toast.success(
"Twoje dane w Dotacje AI zostały trwale usunięte. Za chwilę zostaniesz wylogowany.",
{ duration: 8000 }
);
// Sign out after a short delay so they can read the toast or internal message
setTimeout(() => {
signOut();
}, 6000);
} catch (error) {
toast.error("Wystąpił błąd podczas usuwania danych.");
} finally {
setIsDeleting(false);
}
};
const tabs = [
{ id: 'profile', label: 'Profil i Konto', icon: <User size={18} /> },
{ id: 'companies', label: 'Moje Firmy', icon: <Building2 size={18} /> },
{ id: 'billing', label: 'Subskrypcja', icon: <CreditCard size={18} /> },
{ id: 'security', label: 'Bezpieczeństwo', icon: <Shield size={18} /> },
{ id: 'preferences', label: 'Preferencje', icon: <Sliders size={18} /> },
{ id: 'privacy', label: 'Dane i Prywatność', icon: <Lock size={18} /> },
];
const renderContent = () => {
switch (activeTab) {
case 'profile':
return (
<div style={{ animation: 'fadeIn 0.3s ease' }}>
<h2 style={{ fontSize: '1.4rem', borderBottom: '1px solid rgba(255,255,255,0.1)', paddingBottom: '1rem', marginBottom: '1.5rem', color: '#fff' }}>Twój Profil</h2>
<div style={{ background: 'var(--bg-elevated)', border: '1px solid rgba(255,255,255,0.05)', borderRadius: '12px', padding: '1rem', overflow: 'hidden' }}>
{/* We use Clerk's pre-built profile component embedded here */}
<UserProfile
appearance={{
elements: {
rootBox: { width: '100%', maxWidth: '100%' },
card: { boxShadow: 'none', background: 'transparent', padding: 0 }
}
}}
/>
</div>
</div>
);
case 'companies':
return (
<div style={{ animation: 'fadeIn 0.3s ease' }}>
<h2 style={{ fontSize: '1.4rem', borderBottom: '1px solid rgba(255,255,255,0.1)', paddingBottom: '1rem', marginBottom: '1.5rem', color: '#fff' }}>Zarządzanie podmiotami (Moje Firmy)</h2>
{companies.map((c, i) => (
<div key={i} className="glass-card" style={{ marginBottom: '1rem' }}>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<div>
<h4 style={{ margin: '0 0 0.3rem 0', fontSize: '1.1rem' }}>{c.name}</h4>
<p style={{ margin: 0, color: 'var(--text-muted)', fontSize: '0.9rem' }}>NIP: {c.nip} • {c.city} • {c.status}</p>
</div>
<button className="btn btn-secondary" style={{ color: '#ef4444', borderColor: 'rgba(239, 68, 68, 0.3)' }} onClick={() => handleRemoveCompany(c.nip)}>Usuń</button>
</div>
</div>
))}
<button
className="btn btn-primary"
style={{ marginTop: '1rem', display: 'flex', alignItems: 'center', gap: '0.5rem' }}
onClick={() => setShowCompanyModal(true)}
>
+ Dodaj nową firmę z GUS
</button>
</div>
);
case 'billing':
return (
<div style={{ animation: 'fadeIn 0.3s ease' }}>
<h2 style={{ fontSize: '1.4rem', borderBottom: '1px solid rgba(255,255,255,0.1)', paddingBottom: '1rem', marginBottom: '1.5rem', color: '#fff' }}>Subskrypcja i Rozliczenia</h2>
<div style={{ background: 'linear-gradient(135deg, rgba(16,185,129,0.1), rgba(59,130,246,0.1))', border: '1px solid rgba(16,185,129,0.3)', padding: '2rem', borderRadius: '12px', marginBottom: '2rem' }}>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<div>
<div style={{ color: 'var(--accent-green)', fontWeight: 800, textTransform: 'uppercase', marginBottom: '0.5rem', letterSpacing: '2px' }}>Aktywny Plan</div>
<h3 style={{ fontSize: '1.8rem', margin: 0, color: '#fff' }}>
{subLoading ? '...' : (subData?.tier || 'FREE').toUpperCase()}
</h3>
<p style={{ color: 'var(--text-muted)', margin: '0.5rem 0 0 0' }}>Dostęp do wszystkich sekcji i nielimitowane analizy RAG.</p>
</div>
<button className="btn btn-primary" style={{ background: 'var(--accent-blue)', color: '#fff' }} onClick={() => setShowPricing(true)}>Zmień Plan</button>
</div>
</div>
<div className="glass-card">
<h4 style={{ margin: '0 0 1rem 0' }}>Historia Płatności</h4>
<p style={{ color: 'var(--text-muted)', fontSize: '0.9rem' }}>Nie posiadasz jeszcze historii faktur dla tego konta.</p>
</div>
</div>
);
case 'security':
return (
<div style={{ animation: 'fadeIn 0.3s ease' }}>
<h2 style={{ fontSize: '1.4rem', borderBottom: '1px solid rgba(255,255,255,0.1)', paddingBottom: '1rem', marginBottom: '1.5rem', color: '#fff' }}>Bezpieczeństwo</h2>
<div className="glass-card" style={{ display: 'flex', flexDirection: 'column', gap: '1rem' }}>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', paddingBottom: '1rem', borderBottom: '1px solid rgba(255,255,255,0.05)' }}>
<div>
<h4 style={{ margin: '0 0 0.3rem 0' }}>Weryfikacja dwuetapowa (2FA)</h4>
<p style={{ margin: 0, color: 'var(--text-muted)', fontSize: '0.9rem' }}>Zarządzaj zabezpieczeniami w panelu Profilu (Clerk).</p>
</div>
<button className="btn btn-secondary" onClick={() => setActiveTab('profile')}>Skonfiguruj w Profilu</button>
</div>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', paddingBottom: '1rem', borderBottom: '1px solid rgba(255,255,255,0.05)' }}>
<div>
<h4 style={{ margin: '0 0 0.3rem 0' }}>Aktywne Sesje</h4>
<p style={{ margin: 0, color: 'var(--text-muted)', fontSize: '0.9rem' }}>Windows 11 / Chrome • Aktualna sesja</p>
</div>
<button className="btn hover-bg" style={{ color: 'var(--text-primary)', border: '1px solid var(--border-strong)', background: 'var(--bg-surface)' }}>Wyloguj inne urządzenia</button>
</div>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<div>
<h4 style={{ margin: '0 0 0.3rem 0' }}>Konto i dostęp</h4>
</div>
<SignOutButton>
<button className="btn hover-bg" style={{ background: '#ef4444', border: 'none', color: '#fff', display: 'flex', alignItems: 'center', gap: '0.5rem', fontWeight: 600, padding: '0.5rem 1rem', borderRadius: '6px' }}>
<LogOut size={16} /> Wyloguj się
</button>
</SignOutButton>
</div>
</div>
</div>
);
case 'preferences':
const aiDisclaimer = subData?.settings?.ai_disclaimer_enabled ?? true;
const gdprConsent = subData?.settings?.gdpr_consent_accepted ?? false;
return (
<div style={{ animation: 'fadeIn 0.3s ease' }}>
<h2 style={{ fontSize: '1.4rem', borderBottom: '1px solid rgba(255,255,255,0.1)', paddingBottom: '1rem', marginBottom: '1.5rem', color: '#fff' }}>Preferencje Aplikacji</h2>
<div className="glass-card" style={{ display: 'flex', flexDirection: 'column', gap: '1.5rem' }}>
<div>
<label style={{ display: 'block', fontSize: '0.9rem', color: 'var(--text-secondary)', marginBottom: '0.5rem' }}>Język interfejsu</label>
<select className="form-input" style={{ width: '100%', maxWidth: '300px' }}>
<option>Polski</option>
<option>English</option>
</select>
</div>
<div>
<label style={{ display: 'block', fontSize: '0.9rem', color: 'var(--text-secondary)', marginBottom: '0.5rem' }}>Powiadomienia E-mail</label>
<div style={{ display: 'flex', alignItems: 'center', gap: '0.8rem', marginBottom: '0.5rem' }}>
<input type="checkbox" id="n1" defaultChecked /> <label htmlFor="n1" style={{ color: '#fff' }}>Powiadomienia o nowych naborach ze statusem "Wkrótce"</label>
</div>
<div style={{ display: 'flex', alignItems: 'center', gap: '0.8rem' }}>
<input type="checkbox" id="n2" defaultChecked /> <label htmlFor="n2" style={{ color: '#fff' }}>Cotygodniowe podsumowanie wniosków</label>
</div>
</div>
<div>
<label style={{ display: 'block', fontSize: '0.9rem', color: 'var(--text-secondary)', marginBottom: '0.5rem' }}>Prywatność i ostrzeżenia</label>
<div style={{ display: 'flex', alignItems: 'center', gap: '0.8rem', marginBottom: '0.5rem' }}>
<input
type="checkbox"
id="p1"
checked={gdprConsent}
onChange={(e) => updateSettingsMutation.mutate({ gdpr_consent_accepted: e.target.checked })}
disabled={updateSettingsMutation.isPending}
/>
<label htmlFor="p1" style={{ color: '#fff' }}>Zgoda na przetwarzanie danych profilowych (RODO)</label>
</div>
<div style={{ display: 'flex', alignItems: 'center', gap: '0.8rem' }}>
<input
type="checkbox"
id="p2"
checked={aiDisclaimer}
onChange={(e) => updateSettingsMutation.mutate({ ai_disclaimer_enabled: e.target.checked })}
disabled={updateSettingsMutation.isPending}
/>
<label htmlFor="p2" style={{ color: '#fff' }}>Wyświetlaj ostrzeżenia AI (Disclaimer)</label>
</div>
</div>
</div>
</div>
);
case 'privacy':
return (
<div style={{ animation: 'fadeIn 0.3s ease' }}>
<h2 style={{ fontSize: '1.4rem', borderBottom: '1px solid rgba(255,255,255,0.1)', paddingBottom: '1rem', marginBottom: '1.5rem', color: '#fff' }}>Dane i Prywatność</h2>
<div className="glass-card" style={{ display: 'flex', flexDirection: 'column', gap: '1.5rem' }}>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start' }}>
<div>
<h4 style={{ margin: '0 0 0.3rem 0', display: 'flex', alignItems: 'center', gap: '0.5rem' }}><Download size={18} color="var(--accent-blue)" /> Pobierz moje dane</h4>
<p style={{ margin: 0, color: 'var(--text-muted)', fontSize: '0.9rem', maxWidth: '400px' }}>
Weksportuj paczkę ze wszystkimi Twoimi wnioskami i projektami w czytelnym formacie maszynowym (JSON).
</p>
</div>
<button className="btn btn-secondary" onClick={handleExportData} disabled={isExporting}>
{isExporting ? 'Przygotowywanie...' : 'Zażądaj archiwum JSON'}
</button>
</div>
<hr style={{ border: 'none', borderTop: '1px solid rgba(255,255,255,0.05)', margin: '0' }} />
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start' }}>
<div>
<h4 style={{ margin: '0 0 0.3rem 0', color: 'var(--accent-red)', display: 'flex', alignItems: 'center', gap: '0.5rem' }}><AlertTriangle size={18} /> Usuń konto</h4>
<p style={{ margin: 0, color: 'var(--text-muted)', fontSize: '0.9rem', maxWidth: '400px' }}>
Usunięcie konta jest nieodwracalne i obejmuje wszystkie Twoje projekty oraz dane w systemie.
</p>
</div>
<button className="btn" onClick={() => setShowDeleteModal(true)} style={{ background: 'rgba(239, 68, 68, 0.1)', border: '1px solid var(--accent-red)', color: 'var(--accent-red)' }}>Usuń moje konto i wszystkie dane</button>
</div>
</div>
{deleteSuccess && (
<div style={{ marginTop: '2rem', padding: '1.5rem', background: 'rgba(34, 197, 94, 0.1)', border: '1px solid #22c55e', borderRadius: '12px' }}>
<h3 style={{ color: '#22c55e', marginTop: 0 }}>Twoje dane w Dotacje AI zostały trwale usunięte.</h3>
<p style={{ color: 'var(--text-primary)', marginBottom: 0 }}>
Jeśli chcesz całkowicie usunąć konto logowania, przejdź do swojego profilu w Clerk → Manage Account → Delete Account.
</p>
</div>
)}
{showDeleteModal && (
<div style={{
position: 'fixed', top: 0, left: 0, right: 0, bottom: 0,
background: 'rgba(0,0,0,0.8)', zIndex: 9999,
display: 'flex', alignItems: 'center', justifyContent: 'center'
}}>
<div style={{
background: 'var(--bg-elevated)', padding: '2rem',
borderRadius: '12px', width: '100%', maxWidth: '400px',
border: '1px solid rgba(255,255,255,0.1)'
}}>
<h3 style={{ marginTop: 0, color: 'var(--accent-red)', display: 'flex', alignItems: 'center', gap: '0.5rem' }}>
<AlertTriangle /> Potwierdź usunięcie
</h3>
<p style={{ color: 'var(--text-secondary)', fontSize: '0.9rem', lineHeight: 1.5 }}>
Ta operacja jest niemożliwa do cofnięcia. Kasujemy wszystkie projekty, logi i dane o zużyciu.
<br/><br/>
Aby potwierdzić, wpisz słowo <strong>USUŃ</strong> poniżej:
</p>
<input
type="text"
className="form-input"
value={deleteInput}
onChange={(e) => setDeleteInput(e.target.value)}
placeholder="Wpisz USUŃ"
style={{ width: '100%', marginBottom: '1.5rem', marginTop: '0.5rem', boxSizing: 'border-box' }}
/>
<div style={{ display: 'flex', gap: '1rem', justifyContent: 'flex-end' }}>
<button className="btn btn-secondary" onClick={() => { setShowDeleteModal(false); setDeleteInput(''); }} disabled={isDeleting}>Anuluj</button>
<button
className="btn"
disabled={deleteInput !== 'USUŃ' || isDeleting}
onClick={handleDeleteAccount}
style={{ background: 'var(--accent-red)', color: 'white', opacity: deleteInput !== 'USUŃ' ? 0.5 : 1 }}
>
{isDeleting ? 'Usuwanie...' : 'Skasuj bezpowrotnie'}
</button>
</div>
</div>
</div>
)}
</div>
);
default:
return null;
}
};
return (
<div style={{ padding: '2rem', maxWidth: '1200px', width: '100%', margin: '0 auto', display: 'flex', gap: '3rem', minHeight: 'calc(100vh - 4rem)', alignItems: 'flex-start' }}>
{/* Lewy nawigator */}
<div style={{ width: '280px', flexShrink: 0 }}>
<h1 style={{ fontSize: '1.8rem', fontWeight: 800, margin: '0 0 2rem 0', display: 'flex', alignItems: 'center', gap: '0.8rem' }}>
<SettingsIcon color="var(--accent-blue)" /> Ustawienia
</h1>
<div style={{ display: 'flex', flexDirection: 'column', gap: '0.5rem' }}>
{tabs.map((tab) => (
<button
key={tab.id}
onClick={() => setActiveTab(tab.id)}
style={{
display: 'flex', alignItems: 'center', gap: '0.8rem',
padding: '1rem', borderRadius: '8px', border: 'none',
background: activeTab === tab.id ? 'var(--bg-elevated)' : 'transparent',
color: activeTab === tab.id ? 'var(--text-primary)' : 'var(--text-secondary)',
fontWeight: activeTab === tab.id ? 600 : 500,
cursor: 'pointer',
transition: 'all 0.2s',
textAlign: 'left'
}}
className="hover-bg"
>
<span style={{ color: activeTab === tab.id ? 'var(--accent-blue)' : 'inherit' }}>{tab.icon}</span>
{tab.label}
</button>
))}
</div>
</div>
{/* Prawy panel zwartości */}
<div style={{ flex: 1, paddingRight: '2rem' }}>
{renderContent()}
</div>
{showPricing && <PricingModal onClose={() => setShowPricing(false)} />}
{showCompanyModal && (
<div style={{
position: 'fixed', top: 0, left: 0, right: 0, bottom: 0,
background: 'rgba(0,0,0,0.8)', zIndex: 9999,
display: 'flex', alignItems: 'center', justifyContent: 'center'
}}>
<div style={{
background: 'var(--bg-elevated)', padding: '2rem',
borderRadius: '12px', width: '100%', maxWidth: '500px',
border: '1px solid rgba(255,255,255,0.1)'
}}>
<h3 style={{ marginTop: 0, color: 'var(--text-primary)' }}>Dodaj firmę z GUS</h3>
{!fetchedCompany ? (
<>
<p style={{ color: 'var(--text-secondary)', fontSize: '0.9rem', marginBottom: '1.5rem' }}>
Podaj NIP podmiotu. System pobierze dane z Głównego Urzędu Statystycznego i zweryfikuje powiązania KRS.
</p>
<input
type="text"
className="form-input"
value={newNip}
onChange={(e) => setNewNip(e.target.value)}
placeholder="Wpisz 10-cyfrowy NIP"
style={{ width: '100%', marginBottom: '1.5rem', boxSizing: 'border-box' }}
/>
<div style={{ display: 'flex', gap: '1rem', justifyContent: 'flex-end' }}>
<button className="btn btn-secondary" onClick={() => { setShowCompanyModal(false); setNewNip(''); }} disabled={isLookingUp}>Anuluj</button>
<button
className="btn btn-primary"
disabled={!newNip || newNip.length < 10 || isLookingUp}
onClick={handleAddCompany}
>
{isLookingUp ? 'Pobieranie danych...' : 'Pobierz dane'}
</button>
</div>
</>
) : (
<>
<div style={{ background: 'rgba(255,255,255,0.03)', padding: '1.5rem', borderRadius: '8px', marginBottom: '1.5rem' }}>
<h4 style={{ margin: '0 0 1rem 0', color: 'var(--accent-green)' }}>Znaleziono podmiot</h4>
<div style={{ display: 'grid', gridTemplateColumns: '120px 1fr', gap: '0.8rem', fontSize: '0.9rem' }}>
<div style={{ color: 'var(--text-muted)' }}>Nazwa:</div>
<div style={{ fontWeight: 600 }}>{fetchedCompany.name}</div>
<div style={{ color: 'var(--text-muted)' }}>NIP:</div>
<div>{fetchedCompany.nip}</div>
<div style={{ color: 'var(--text-muted)' }}>Adres:</div>
<div>{fetchedCompany.address}</div>
<div style={{ color: 'var(--text-muted)' }}>Miejscowość:</div>
<div>{fetchedCompany.city}</div>
<div style={{ color: 'var(--text-muted)' }}>Forma prawna:</div>
<div>{fetchedCompany.legalForm}</div>
</div>
<div style={{ marginTop: '1rem', padding: '0.8rem', background: 'rgba(34, 197, 94, 0.1)', border: '1px solid rgba(34, 197, 94, 0.3)', borderRadius: '6px', fontSize: '0.85rem', color: 'var(--accent-green)' }}>
✓ Zweryfikowano w bazie REGON
<br/>✓ Brak powiązań kapitałowych wykluczających MŚP
</div>
</div>
<div style={{ display: 'flex', gap: '1rem', justifyContent: 'flex-end' }}>
<button className="btn btn-secondary" onClick={() => setFetchedCompany(null)}>Wróć</button>
<button className="btn btn-primary" onClick={handleSaveFetchedCompany}>Dodaj do konta</button>
</div>
</>
)}
</div>
</div>
)}
<style>{`
@keyframes fadeIn { from { opacity: 0; transform: translateY(5px); } to { opacity: 1; transform: translateY(0); } }
.hover-bg:hover { background: rgba(255,255,255,0.03) !important; color: #fff !important; }
.form-input { background: var(--bg-deep); border: 1px solid rgba(255,255,255,0.1); color: #fff; padding: 0.8rem 1rem; border-radius: 8px; outline: none; transition: 0.2s; }
.form-input:focus { border-color: var(--accent-blue); box-shadow: 0 0 0 2px rgba(59,130,246,0.2); }
`}</style>
</div>
);
};
export default Settings;