From c4af3c053b2e838ff37e11c8445b5ff1fe746ae2 Mon Sep 17 00:00:00 2001 From: Sidney Gomes Date: Mon, 20 Jul 2026 21:08:08 -0300 Subject: [PATCH] fix: settings save button contrast, modal confirmation, Asaas status test, and prominent activity question creation buttons --- server.ts | 9 +++ src/components/AdminContentManager.tsx | 29 +++++++-- src/components/AdminDashboard.tsx | 84 +++++++++++++++++++++++++- src/services/asaas.ts | 45 ++++++++++++++ 4 files changed, 159 insertions(+), 8 deletions(-) diff --git a/server.ts b/server.ts index a10c3af..d4e9f53 100644 --- a/server.ts +++ b/server.ts @@ -637,6 +637,15 @@ app.post('/api/admin/settings', authenticateToken, requireAdmin, (req: Authentic res.json({ success: true, settings: db.settings }); }); +app.get('/api/admin/test-asaas', authenticateToken, requireAdmin, async (req: AuthenticatedRequest, res: Response) => { + try { + const result = await AsaasService.testConnection(); + res.json(result); + } catch (err: any) { + res.status(500).json({ success: false, message: err.message || 'Erro ao testar conexão Asaas' }); + } +}); + // Admin manually unlock or lock a course for a student app.post('/api/admin/students/:id/unlock-course', authenticateToken, requireAdmin, (req: AuthenticatedRequest, res: Response) => { const { courseId, unlocked } = req.body; diff --git a/src/components/AdminContentManager.tsx b/src/components/AdminContentManager.tsx index bffde60..ef07b79 100644 --- a/src/components/AdminContentManager.tsx +++ b/src/components/AdminContentManager.tsx @@ -392,6 +392,21 @@ export default function AdminContentManager({ token }: AdminContentManagerProps) )} + {/* Helper Banner for Questionnaires / Activities */} + {!selectedCourse && !showCourseForm && ( +
+
+ +
+
+

Como Criar as Questões e Atividades dos Alunos?

+

+ Escolha um curso abaixo clicando no botão Gerenciar Módulos & Questões. Em seguida, em cada módulo, clique no botão verde 📝 Criar / Editar Questões para adicionar perguntas e respostas! +

+
+
+ )} + {/* --- RENDER COURSE FORM --- */} {showCourseForm && (
@@ -698,13 +713,14 @@ export default function AdminContentManager({ token }: AdminContentManagerProps) Nova Aula - {/* Manage Activity */} + {/* Manage Activity / Questions */} {/* Edit Module */} @@ -803,9 +819,10 @@ export default function AdminContentManager({ token }: AdminContentManagerProps)
diff --git a/src/components/AdminDashboard.tsx b/src/components/AdminDashboard.tsx index 40771d8..f58e3f1 100644 --- a/src/components/AdminDashboard.tsx +++ b/src/components/AdminDashboard.tsx @@ -71,6 +71,8 @@ export default function AdminDashboard({ token }: AdminDashboardProps) { // Settings State const [settings, setSettings] = useState(null); const [isSavingSettings, setIsSavingSettings] = useState(false); + const [showSaveSuccessModal, setShowSaveSuccessModal] = useState(false); + const [asaasTestResult, setAsaasTestResult] = useState<{ loading: boolean; success: boolean | null; message: string } | null>(null); useEffect(() => { fetchDashboardData(); @@ -106,17 +108,39 @@ export default function AdminDashboard({ token }: AdminDashboardProps) { body: JSON.stringify(settings) }); if (res.ok) { - alert('Configurações salvas com sucesso!'); + setShowSaveSuccessModal(true); } else { alert('Erro ao salvar configurações.'); } } catch (err) { console.error('Error saving settings:', err); + alert('Erro de conexão ao salvar configurações.'); } finally { setIsSavingSettings(false); } }; + const handleTestAsaasConnection = async () => { + setAsaasTestResult({ loading: true, success: null, message: 'Testando conexão com Asaas...' }); + try { + const res = await fetch('/api/admin/test-asaas', { + headers: { 'Authorization': `Bearer ${token}` } + }); + const data = await res.json(); + setAsaasTestResult({ + loading: false, + success: data.success, + message: data.message || (data.success ? 'Conexão estabelecida com sucesso!' : 'Falha na conexão.') + }); + } catch (err: any) { + setAsaasTestResult({ + loading: false, + success: false, + message: `Erro de rede: ${err.message}` + }); + } + }; + const fetchCourses = async () => { try { const res = await fetch('/api/courses', { @@ -826,6 +850,37 @@ export default function AdminDashboard({ token }: AdminDashboardProps) { />
+ {/* Test Connection Button & Status */} +
+
+ Status da Conexão Asaas + +
+ + {asaasTestResult && ( +
+ {asaasTestResult.success ? ( + + ) : ( + + )} + {asaasTestResult.message} +
+ )} +
+
@@ -833,7 +888,7 @@ export default function AdminDashboard({ token }: AdminDashboardProps) { + + + )} ); } diff --git a/src/services/asaas.ts b/src/services/asaas.ts index cf38e07..a98e458 100644 --- a/src/services/asaas.ts +++ b/src/services/asaas.ts @@ -21,6 +21,51 @@ export class AsaasService { }; } + /** + * Test the connection to Asaas API + */ + public static async testConnection(): Promise<{ success: boolean; message: string; environment: string }> { + const apiKey = this.getApiKey(); + const env = loadDb().settings?.asaasEnvironment || 'sandbox'; + + if (!apiKey) { + return { + success: false, + message: 'Chave de API (API Key) não foi configurada.', + environment: env + }; + } + + try { + const response = await fetch(`${this.getApiUrl()}/customers?limit=1`, { + method: 'GET', + headers: this.getHeaders() + }); + + if (response.ok) { + return { + success: true, + message: `Conexão estabelecida com sucesso no ambiente ${env.toUpperCase()}!`, + environment: env + }; + } else { + const errData = await response.json().catch(() => ({})); + const desc = errData.errors?.[0]?.description || `HTTP ${response.status}`; + return { + success: false, + message: `Falha na autenticação Asaas: ${desc}`, + environment: env + }; + } + } catch (err: any) { + return { + success: false, + message: `Erro de conexão de rede: ${err.message || 'Servidor inalcançável'}`, + environment: env + }; + } + } + /** * Create a customer in Asaas */