diff --git a/server.ts b/server.ts
index c9b8085..29c3389 100644
--- a/server.ts
+++ b/server.ts
@@ -1235,7 +1235,9 @@ app.get('/api/settings', async (req: Request, res: Response) => {
brandName: settings?.brandName || 'MICROTEC',
brandSlogan: settings?.brandSlogan || 'Acelere seus estudos em informática e pacote Office no estilo Netflix.',
cnpj: settings?.cnpj || '',
- address: settings?.address || ''
+ address: settings?.address || '',
+ termsOfUse: settings?.termsOfUse || '',
+ privacyPolicy: settings?.privacyPolicy || ''
});
});
@@ -1263,7 +1265,9 @@ app.get('/api/admin/settings', authenticateToken, requireAdmin, async (req: Auth
smtpUser: settings?.smtpUser || '',
smtpPass: settings?.smtpPass || '',
smtpFrom: settings?.smtpFrom || 'no-reply@microtecinformaticacurso.com.br',
- smtpSecure: settings?.smtpSecure || false
+ smtpSecure: settings?.smtpSecure || false,
+ termsOfUse: settings?.termsOfUse || '',
+ privacyPolicy: settings?.privacyPolicy || ''
});
});
diff --git a/src/App.tsx b/src/App.tsx
index 63078f9..4447947 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -12,6 +12,7 @@ import CourseUnlockModal from './components/CourseUnlockModal';
import CertificatesTab from './components/CertificatesTab';
import ProfileView from './components/ProfileView';
import HelpView from './components/HelpView';
+import CustomModal from './components/CustomModal';
import { User as UserType, Course as CourseType, SubscriptionStatus } from './types';
export default function App() {
@@ -51,7 +52,8 @@ export default function App() {
// Course catalogue
const [courses, setCourses] = useState<(CourseType & { progress?: number; totalLessons?: number; completedLessons?: number })[]>([]);
const [isLoadingCourses, setIsLoadingCourses] = useState(false);
- const [settings, setSettings] = useState<{ brandName?: string; brandSlogan?: string; cnpj?: string; address?: string } | null>(null);
+ const [settings, setSettings] = useState<{ brandName?: string; brandSlogan?: string; cnpj?: string; address?: string; termsOfUse?: string; privacyPolicy?: string } | null>(null);
+ const [infoModal, setInfoModal] = useState<{isOpen: boolean, title: string, content: string}>({isOpen: false, title: '', content: ''});
useEffect(() => {
const urlParams = new URLSearchParams(window.location.search);
@@ -461,8 +463,34 @@ export default function App() {
{settings?.cnpj && (
CNPJ: {settings.cnpj} • Endereço: {settings.address}
)}
- © 2026 {(settings?.brandName || 'Plataforma')}FLIX Inc. Todos os direitos reservados. Integrado oficialmente com a API Asaas.
+
+
+
+
+ © 2026 {(settings?.brandName || 'Plataforma')}FLIX Inc. Todos os direitos reservados. Integrado oficialmente com a API Asaas.
+
+ {/* Info Modal for Terms and Privacy */}
+ setInfoModal({...infoModal, isOpen: false})}
+ title={infoModal.title}
+ isGlass={true}
+ >
+
+ {infoModal.content}
+
+
>
) : (
/* --- UNAUTHENTICATED PORTAL (LOGIN / REGISTER) --- */
diff --git a/src/components/AdminDashboard.tsx b/src/components/AdminDashboard.tsx
index 9b5d1d1..515b2fb 100644
--- a/src/components/AdminDashboard.tsx
+++ b/src/components/AdminDashboard.tsx
@@ -1346,6 +1346,28 @@ export default function AdminDashboard({ token, adminUser, onLogout }: AdminDash
Exibido no rodapé do portal.
+
+
+
+
+
+
diff --git a/src/components/AdminMessagesView.tsx b/src/components/AdminMessagesView.tsx
index f8d6767..c5ecd2c 100644
--- a/src/components/AdminMessagesView.tsx
+++ b/src/components/AdminMessagesView.tsx
@@ -1,5 +1,6 @@
import React, { useState, useEffect } from 'react';
-import { Mail, MessageSquare, BookOpen, Send, User, Reply } from 'lucide-react';
+import { Mail, MessageSquare, BookOpen, Send, User, Reply, CheckCircle2, AlertCircle } from 'lucide-react';
+import CustomModal from './CustomModal';
interface SupportTicket {
id: string;
@@ -44,6 +45,7 @@ export default function AdminMessagesView() {
const [replyText, setReplyText] = useState('');
const [replyingTo, setReplyingTo] = useState(null);
const [isSending, setIsSending] = useState(false);
+ const [alertModal, setAlertModal] = useState<{isOpen: boolean, title: string, message: string, isError?: boolean}>({isOpen: false, title: '', message: ''});
useEffect(() => {
fetchMessages();
@@ -85,13 +87,13 @@ export default function AdminMessagesView() {
setReplyText('');
setReplyingTo(null);
fetchMessages();
- alert('Resposta enviada com sucesso!');
+ setAlertModal({isOpen: true, title: 'Sucesso', message: 'Resposta enviada com sucesso!'});
} else {
- alert('Erro ao enviar resposta.');
+ setAlertModal({isOpen: true, title: 'Erro', message: 'Erro ao enviar resposta.', isError: true});
}
} catch (error) {
console.error('Error replying:', error);
- alert('Erro interno ao enviar resposta.');
+ setAlertModal({isOpen: true, title: 'Erro', message: 'Erro interno ao enviar resposta.', isError: true});
} finally {
setIsSending(false);
}
@@ -286,6 +288,36 @@ export default function AdminMessagesView() {
)}
)}
+
+ setAlertModal({...alertModal, isOpen: false})}
+ title={alertModal.title}
+ isGlass={true}
+ >
+
+ {alertModal.isError ? (
+
+ ) : (
+
+
+
+ )}
+
+
{alertModal.message}
+
+
+
+
+
+
);
}
diff --git a/src/components/CustomModal.tsx b/src/components/CustomModal.tsx
new file mode 100644
index 0000000..6ca28ea
--- /dev/null
+++ b/src/components/CustomModal.tsx
@@ -0,0 +1,43 @@
+import React from 'react';
+import { X } from 'lucide-react';
+
+interface CustomModalProps {
+ isOpen: boolean;
+ onClose: () => void;
+ title: string;
+ children: React.ReactNode;
+ isGlass?: boolean;
+}
+
+export default function CustomModal({ isOpen, onClose, title, children, isGlass = false }: CustomModalProps) {
+ if (!isOpen) return null;
+
+ return (
+
+
+
+
+
{title}
+
+
+
+
+ {children}
+
+
+
+ );
+}