feat: Add OAuth email integration and production deployment config

- Add OAuthCredential model for storing Google/Microsoft OAuth tokens
- Add email provider auto-detection endpoint (Gmail, Outlook, Yahoo, etc.)
- Add EmailConfigWizard frontend component with step-by-step setup
- Add OAuth flow endpoints for Google and Microsoft XOAUTH2
- Update production settings to make AWS, Sentry, Mailgun optional
- Update Traefik config for wildcard subdomain routing
- Add logo resize utility script

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
poduck
2025-11-29 21:26:17 -05:00
parent cfc1b36ada
commit 7b0cf62019
22 changed files with 3075 additions and 96 deletions

View File

@@ -55,7 +55,8 @@ import {
useTestSmtpConnection,
useFetchEmailsNow,
} from '../../hooks/useTicketEmailSettings';
import { Send } from 'lucide-react';
import { Send, Wand2 } from 'lucide-react';
import EmailConfigWizard from '../../components/EmailConfigWizard';
type TabType = 'general' | 'stripe' | 'tiers' | 'oauth';
@@ -119,12 +120,14 @@ const PlatformSettings: React.FC = () => {
const GeneralSettingsTab: React.FC = () => {
const { t } = useTranslation();
const { data: emailSettings, isLoading, error } = useTicketEmailSettings();
const { data: emailSettings, isLoading, error, refetch } = useTicketEmailSettings();
const updateMutation = useUpdateTicketEmailSettings();
const testImapMutation = useTestImapConnection();
const testSmtpMutation = useTestSmtpConnection();
const fetchNowMutation = useFetchEmailsNow();
const [showWizard, setShowWizard] = useState(false);
const [formData, setFormData] = useState({
// IMAP settings
imap_host: '',
@@ -228,14 +231,39 @@ const GeneralSettingsTab: React.FC = () => {
);
}
// Show wizard if requested
if (showWizard) {
return (
<div className="space-y-6">
<EmailConfigWizard
onComplete={() => {
setShowWizard(false);
refetch();
}}
onCancel={() => setShowWizard(false)}
initialEmail={emailSettings?.imap_username || ''}
/>
</div>
);
}
return (
<div className="space-y-6">
{/* Email Processing Status */}
<div className="bg-white dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-gray-700 p-6">
<h2 className="text-lg font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<Mail className="w-5 h-5" />
{t('platform.settings.emailProcessing', 'Support Email Processing')}
</h2>
<div className="flex items-center justify-between mb-4">
<h2 className="text-lg font-semibold text-gray-900 dark:text-white flex items-center gap-2">
<Mail className="w-5 h-5" />
{t('platform.settings.emailProcessing', 'Support Email Processing')}
</h2>
<button
onClick={() => setShowWizard(true)}
className="inline-flex items-center gap-2 px-4 py-2 text-sm font-medium text-blue-600 dark:text-blue-400 bg-blue-50 dark:bg-blue-900/20 rounded-lg hover:bg-blue-100 dark:hover:bg-blue-900/30 transition-colors"
>
<Wand2 className="w-4 h-4" />
{t('platform.settings.setupWizard', 'Setup Wizard')}
</button>
</div>
<div className="grid grid-cols-1 md:grid-cols-3 gap-4 mb-6">
<div className="flex items-center gap-3 p-3 bg-gray-50 dark:bg-gray-700/50 rounded-lg">