'use client'; import { useState } from 'react'; import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import { AuthGuard } from '@/components/AuthGuard'; import { DashboardLayout } from '@/components/DashboardLayout'; import { userApi, gmailApi, smtpApi } from '@/lib/api'; import { useAuthStore } from '@/store/authStore'; import { CheckCircle, Loader2, User, Mail, Shield, Server, AlertTriangle, XCircle, } from 'lucide-react'; export default function SettingsPage() { return ( ); } function SettingsContent() { const queryClient = useQueryClient(); const { user, setUser } = useAuthStore(); const [profileForm, setProfileForm] = useState({ full_name: user?.full_name || '', email: user?.email || '', }); const [profileSaved, setProfileSaved] = useState(false); // SMTP form state const [smtpForm, setSmtpForm] = useState({ host: 'smtp.gmail.com', port: 587, username: '', password: '', use_tls: true, }); const [smtpSaved, setSmtpSaved] = useState(false); // Refresh user data from the server const { data: currentUser } = useQuery({ queryKey: ['current-user'], queryFn: userApi.getCurrentUser, initialData: user ?? undefined, }); // Gmail credential status const { data: gmailCredential, isLoading: gmailLoading, error: gmailError, } = useQuery({ queryKey: ['gmail-credential'], queryFn: gmailApi.getCredential, retry: false, }); // SMTP config const { data: smtpConfig, isLoading: smtpLoading } = useQuery({ queryKey: ['smtp-config'], queryFn: smtpApi.get, retry: false, }); // Pre-populate SMTP form when data loads const [smtpFormPopulated, setSmtpFormPopulated] = useState(false); if (smtpConfig && !smtpFormPopulated) { setSmtpFormPopulated(true); setSmtpForm((prev) => ({ ...prev, host: smtpConfig.host, port: smtpConfig.port, username: smtpConfig.username, use_tls: smtpConfig.use_tls, password: '', // never pre-fill password })); } const updateProfileMutation = useMutation({ mutationFn: (data: { full_name: string; email: string }) => userApi.updateProfile(data), onSuccess: (updatedUser) => { setUser(updatedUser); queryClient.invalidateQueries({ queryKey: ['current-user'] }); setProfileSaved(true); setTimeout(() => setProfileSaved(false), 3000); }, }); const disconnectGmailMutation = useMutation({ mutationFn: gmailApi.disconnect, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['gmail-credential'] }); }, }); const saveSmtpMutation = useMutation({ mutationFn: smtpApi.save, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['smtp-config'] }); setSmtpSaved(true); setTimeout(() => setSmtpSaved(false), 3000); }, }); const deleteSmtpMutation = useMutation({ mutationFn: smtpApi.remove, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['smtp-config'] }); setSmtpForm({ host: 'smtp.gmail.com', port: 587, username: '', password: '', use_tls: true }); }, }); const handleProfileChange = (e: React.ChangeEvent) => { const { name, value } = e.target; setProfileForm((prev) => ({ ...prev, [name]: value })); }; const handleSmtpChange = (e: React.ChangeEvent) => { const { name, value, type } = e.target; setSmtpForm((prev) => ({ ...prev, [name]: type === 'checkbox' ? (e.target as HTMLInputElement).checked : name === 'port' ? Number(value) : value, })); }; const handleProfileSubmit = async (e: React.FormEvent) => { e.preventDefault(); try { await updateProfileMutation.mutateAsync({ full_name: profileForm.full_name, email: profileForm.email, }); } catch (error) { const errorMessage = error instanceof Error && 'response' in error ? (error as { response?: { data?: { detail?: string } } }).response?.data ?.detail : null; alert(errorMessage || 'Failed to update profile'); } }; const handleSmtpSubmit = async (e: React.FormEvent) => { e.preventDefault(); try { await saveSmtpMutation.mutateAsync({ host: smtpForm.host, port: smtpForm.port, username: smtpForm.username, password: smtpForm.password || undefined, use_tls: smtpForm.use_tls, }); } catch (error) { const errorMessage = error instanceof Error && 'response' in error ? (error as { response?: { data?: { detail?: string } } }).response?.data ?.detail : null; alert(errorMessage || 'Failed to save SMTP settings'); } }; const handleConnectGmail = async () => { try { const redirectUri = `${window.location.origin}/auth/gmail-callback`; const url = await gmailApi.getAuthorizeUrl(redirectUri); window.location.href = url; } catch (error) { const errorMessage = error instanceof Error && 'response' in error ? (error as { response?: { data?: { detail?: string } } }).response?.data ?.detail : null; alert(errorMessage || 'Failed to start Gmail authorization'); } }; const handleDisconnectGmail = async () => { if (confirm('Disconnect Gmail? Mail accounts using Gmail API delivery will fall back to SMTP.')) { try { await disconnectGmailMutation.mutateAsync(); } catch { alert('Failed to disconnect Gmail'); } } }; const displayUser = currentUser ?? user; const gmailConnected = gmailCredential?.is_valid === true; // gmail 404 just means "not connected yet" — not a real error const gmailNotConnected = !gmailCredential && !gmailLoading; return (

Settings

{/* Profile Section */}

Profile

{profileSaved && ( Saved successfully )}
{/* Gmail API Section */}

Gmail API Delivery

Grant this app permission to inject emails directly into your Gmail inbox. This is the preferred delivery method — emails arrive with original headers intact, bypassing SMTP entirely.

Token lifetime: Access tokens expire after 1 hour and are refreshed automatically. Refresh tokens do not expire unless you revoke access via your{' '} Google Account permissions . If revoked, click “Connect Gmail” again to re-authorise.

{gmailLoading && (
Checking Gmail connection…
)} {!gmailLoading && gmailConnected && (

Connected as {gmailCredential.gmail_email}

{gmailCredential.last_verified_at && (

Last verified: {new Date(gmailCredential.last_verified_at).toLocaleString()}

)}
)} {!gmailLoading && gmailCredential && !gmailCredential.is_valid && (
Gmail access was revoked. Click “Re-authorise” below to restore Gmail API delivery.
)} {!gmailLoading && (gmailNotConnected || (gmailCredential && !gmailCredential.is_valid)) && ( )} {!gmailLoading && gmailNotConnected && (
No Gmail account connected yet.
)}
{/* SMTP Fallback Section */}

SMTP Fallback

Used when Gmail API is not connected or when a mail account is configured to use SMTP delivery. Your credentials are stored encrypted.

{smtpLoading ? (
Loading SMTP settings…
) : (
{smtpConfig && ( )} {smtpSaved && ( Saved )}
)}
{/* Account Information */}

Account Information

Subscription tier: {displayUser?.subscription_tier ?? '—'}
Subscription status: {displayUser?.subscription_status ?? '—'}
Member since: {displayUser?.created_at ? new Date(displayUser.created_at).toLocaleDateString(undefined, { year: 'numeric', month: 'long', day: 'numeric', }) : '—'}
{displayUser?.oauth_provider && (
Linked account: {displayUser.oauth_provider}
)} {displayUser?.last_login_at && (
Last login: {new Date(displayUser.last_login_at).toLocaleString()}
)}
{/* Security Section */}

Security

Password change and two-factor authentication settings are coming soon.

{displayUser?.oauth_provider === 'google' && (

Your account is authenticated via Google OAuth — password management is handled by Google.

)}
); }