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 */}
handleManageActivity(mod.id)}
- className="bg-zinc-800 text-zinc-300 hover:text-white hover:bg-zinc-700 text-[10px] font-bold px-2 py-1 rounded flex items-center space-x-1 border border-zinc-700 transition-colors"
+ className="bg-emerald-600 hover:bg-emerald-500 text-white text-xs font-extrabold px-3 py-1.5 rounded-lg flex items-center space-x-1.5 border border-emerald-400/40 transition-all shadow-[0_0_12px_rgba(16,185,129,0.35)] cursor-pointer"
+ title="Criar ou editar o questionário deste módulo"
>
-
- Gerenciar Atividade
+
+ 📝 Criar / Editar Questões
{/* Edit Module */}
@@ -803,9 +819,10 @@ export default function AdminContentManager({ token }: AdminContentManagerProps)
handleSelectCourse(course)}
- className="glass-btn-secondary text-white text-xs font-bold px-3 py-2 rounded flex items-center space-x-1 cursor-pointer"
+ className="glass-btn-primary text-white text-xs font-bold px-3.5 py-2 rounded-lg flex items-center space-x-1.5 cursor-pointer shadow-md hover:scale-105 transition-all"
>
- Grade Curricular
+
+ Gerenciar Módulos & Questões
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?.loading ? (
+
+ ) : (
+
+ )}
+ {asaasTestResult?.loading ? 'Verificando...' : 'Testar Conexão Asaas'}
+
+
+
+ {asaasTestResult && (
+
+ {asaasTestResult.success ? (
+
+ ) : (
+
+ )}
+
{asaasTestResult.message}
+
+ )}
+
+
@@ -833,7 +888,7 @@ export default function AdminDashboard({ token }: AdminDashboardProps) {
{isSavingSettings ? (
@@ -847,6 +902,31 @@ export default function AdminDashboard({ token }: AdminDashboardProps) {
)}
+
+ {/* SAVE SUCCESS MODAL */}
+ {showSaveSuccessModal && (
+
+
+
+
+
+
+
+
Configurações Salvas!
+
+ As configurações globais do sistema e as credenciais do Asaas foram atualizadas com sucesso no banco de dados.
+
+
+
+
setShowSaveSuccessModal(false)}
+ className="w-full glass-btn-primary text-white text-xs font-bold py-3 px-4 rounded-xl cursor-pointer hover:scale-105 transition-all"
+ >
+ Fechar Janela
+
+
+
+ )}
);
}
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
*/