/** * Authentication Settings Page * * Configure OAuth providers, social login, and custom credentials. */ import React, { useState, useEffect } from 'react'; import { useTranslation } from 'react-i18next'; import { useOutletContext } from 'react-router-dom'; import { Lock, Users, Key, Save, Check, AlertCircle, Eye, EyeOff } from 'lucide-react'; import { Business, User } from '../../types'; import { useBusinessOAuthSettings, useUpdateBusinessOAuthSettings } from '../../hooks/useBusinessOAuth'; import { useBusinessOAuthCredentials, useUpdateBusinessOAuthCredentials } from '../../hooks/useBusinessOAuthCredentials'; // Provider display names and icons const providerInfo: Record = { google: { name: 'Google', icon: '🔍' }, apple: { name: 'Apple', icon: '🍎' }, facebook: { name: 'Facebook', icon: '📘' }, linkedin: { name: 'LinkedIn', icon: '💼' }, microsoft: { name: 'Microsoft', icon: '🪟' }, twitter: { name: 'X (Twitter)', icon: '🐦' }, twitch: { name: 'Twitch', icon: '🎮' }, }; const AuthenticationSettings: React.FC = () => { const { t } = useTranslation(); const { business, user } = useOutletContext<{ business: Business; user: User; }>(); // OAuth Settings hooks const { data: oauthData, isLoading: oauthLoading } = useBusinessOAuthSettings(); const updateOAuthMutation = useUpdateBusinessOAuthSettings(); const [oauthSettings, setOAuthSettings] = useState({ enabledProviders: [] as string[], allowRegistration: false, autoLinkByEmail: true, useCustomCredentials: false, }); // OAuth Credentials hooks const { data: oauthCredentials, isLoading: credentialsLoading } = useBusinessOAuthCredentials(); const updateCredentialsMutation = useUpdateBusinessOAuthCredentials(); const [useCustomCredentials, setUseCustomCredentials] = useState(false); const [credentials, setCredentials] = useState({ google: { client_id: '', client_secret: '' }, apple: { client_id: '', client_secret: '', team_id: '', key_id: '' }, facebook: { client_id: '', client_secret: '' }, linkedin: { client_id: '', client_secret: '' }, microsoft: { client_id: '', client_secret: '', tenant_id: '' }, twitter: { client_id: '', client_secret: '' }, twitch: { client_id: '', client_secret: '' }, }); const [showSecrets, setShowSecrets] = useState<{ [key: string]: boolean }>({}); const [showToast, setShowToast] = useState(false); const isOwner = user.role === 'owner'; // Update OAuth settings when data loads useEffect(() => { if (oauthData?.settings) { setOAuthSettings(oauthData.settings); } }, [oauthData]); // Update OAuth credentials when data loads useEffect(() => { if (oauthCredentials) { setUseCustomCredentials(oauthCredentials.useCustomCredentials || false); const creds = oauthCredentials.credentials || {}; setCredentials({ google: creds.google || { client_id: '', client_secret: '' }, apple: creds.apple || { client_id: '', client_secret: '', team_id: '', key_id: '' }, facebook: creds.facebook || { client_id: '', client_secret: '' }, linkedin: creds.linkedin || { client_id: '', client_secret: '' }, microsoft: creds.microsoft || { client_id: '', client_secret: '', tenant_id: '' }, twitter: creds.twitter || { client_id: '', client_secret: '' }, twitch: creds.twitch || { client_id: '', client_secret: '' }, }); } }, [oauthCredentials]); // Auto-hide toast useEffect(() => { if (showToast) { const timer = setTimeout(() => setShowToast(false), 3000); return () => clearTimeout(timer); } }, [showToast]); const handleOAuthSave = () => { updateOAuthMutation.mutate(oauthSettings, { onSuccess: () => { setShowToast(true); }, }); }; const toggleProvider = (provider: string) => { setOAuthSettings((prev) => { const isEnabled = prev.enabledProviders.includes(provider); return { ...prev, enabledProviders: isEnabled ? prev.enabledProviders.filter((p) => p !== provider) : [...prev.enabledProviders, provider], }; }); }; const handleCredentialsSave = () => { const updateData: any = { use_custom_credentials: useCustomCredentials, }; if (useCustomCredentials) { Object.entries(credentials).forEach(([provider, creds]: [string, any]) => { if (creds.client_id || creds.client_secret) { updateData[provider] = creds; } }); } updateCredentialsMutation.mutate(updateData, { onSuccess: () => { setShowToast(true); }, }); }; const updateCredential = (provider: string, field: string, value: string) => { setCredentials((prev: any) => ({ ...prev, [provider]: { ...prev[provider], [field]: value, }, })); }; const toggleShowSecret = (key: string) => { setShowSecrets((prev) => ({ ...prev, [key]: !prev[key] })); }; if (!isOwner) { return (

Only the business owner can access these settings.

); } return (
{/* Header */}

{t('settings.authentication.title', 'Authentication')}

Configure social login and OAuth providers for customer sign-in.

{/* OAuth & Social Login */}

Social Login

Choose which providers customers can use to sign in

{oauthLoading ? (
) : oauthData?.availableProviders && oauthData.availableProviders.length > 0 ? (
{oauthData.availableProviders.map((provider: any) => { const isEnabled = oauthSettings.enabledProviders.includes(provider.id); const info = providerInfo[provider.id] || { name: provider.name, icon: '🔐' }; return ( ); })}

Allow OAuth Registration

New customers can create accounts via OAuth

Auto-link by Email

Link OAuth accounts to existing accounts by email

) : (

No OAuth Providers Available

Contact your platform administrator to enable OAuth providers.

)}
{/* Custom OAuth Credentials - Only shown if platform has enabled this permission */} {business.canManageOAuthCredentials && (

Custom OAuth Credentials

Use your own OAuth app credentials for complete branding control

{credentialsLoading ? (
) : (
{/* Toggle Custom Credentials */}

Use Custom Credentials

{useCustomCredentials ? 'Using your custom OAuth credentials' : 'Using platform shared credentials'}

{useCustomCredentials && (
{(['google', 'apple', 'facebook', 'linkedin', 'microsoft', 'twitter', 'twitch'] as const).map((provider) => { const info = providerInfo[provider]; const providerCreds = credentials[provider]; const hasCredentials = providerCreds.client_id || providerCreds.client_secret; return (
{info.icon} {info.name} {hasCredentials && ( Configured )}
updateCredential(provider, 'client_id', e.target.value)} placeholder={`Enter ${info.name} Client ID`} className="w-full px-3 py-1.5 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-500 text-sm" />
updateCredential(provider, 'client_secret', e.target.value)} placeholder={`Enter ${info.name} Client Secret`} className="w-full px-3 py-1.5 pr-8 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-500 text-sm" />
{/* Provider-specific fields */} {provider === 'apple' && ( <>
updateCredential(provider, 'team_id', e.target.value)} placeholder="Enter Apple Team ID" className="w-full px-3 py-1.5 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-500 text-sm" />
updateCredential(provider, 'key_id', e.target.value)} placeholder="Enter Apple Key ID" className="w-full px-3 py-1.5 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-500 text-sm" />
)} {provider === 'microsoft' && (
updateCredential(provider, 'tenant_id', e.target.value)} placeholder="Enter Microsoft Tenant ID (or 'common')" className="w-full px-3 py-1.5 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-500 text-sm" />
)}
); })}
)}
)}
)} {/* Toast */} {showToast && (
Changes saved successfully
)}
); }; export default AuthenticationSettings;