init: scripts diversos (crawlers, conversores, scrapers)

This commit is contained in:
2026-03-05 20:38:36 +00:00
commit 6ac6f4be2a
925 changed files with 850330 additions and 0 deletions

View File

@@ -0,0 +1,127 @@
/**
* AddImapAccountForm.tsx
*
* @author Descomplicar® Crescimento Digital
* @link https://descomplicar.pt
* @copyright 2025 Descomplicar®
*/
import React, { useState } from 'react';
import Spinner from './Spinner'; // Certifique-se que este componente exista
interface AddImapAccountFormProps {
onConnect: (email: string, user: string, host: string, port: number, secure: boolean) => void;
onBack: () => void;
}
const AddImapAccountForm: React.FC<AddImapAccountFormProps> = ({ onConnect, onBack }) => {
const [email, setEmail] = useState('');
const [user, setUser] = useState('');
const [password, setPassword] = useState('');
const [host, setHost] = useState('');
const [port, setPort] = useState(993);
const [secure, setSecure] = useState(true);
const [testStatus, setTestStatus] = useState<'idle' | 'testing' | 'success' | 'error'>('idle');
const [testMessage, setTestMessage] = useState('');
const handleTestConnection = async () => {
setTestStatus('testing');
setTestMessage('');
// A API que criamos espera um corpo de requisição (body).
// Como estamos em um ambiente de desenvolvimento sem um servidor Node rodando,
// não podemos chamar a API diretamente. A lógica abaixo é como o frontend
// se comportaria se estivesse fazendo um fetch para /api/test-imap.
// Por enquanto, vamos simular a chamada e focar na UI.
try {
const response = await fetch('/api/test-imap', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ host, port, user, password, secure })
});
if (!response.ok) {
// Tenta extrair uma mensagem de erro amigável do corpo da resposta
const errorResult = await response.json().catch(() => null);
throw new Error(errorResult?.message || `Erro no servidor: ${response.statusText}`);
}
const result = await response.json();
if (result.success) {
setTestStatus('success');
setTestMessage(result.message);
} else {
setTestStatus('error');
setTestMessage(result.message || 'Ocorreu um erro desconhecido.');
}
} catch (error) {
setTestStatus('error');
setTestMessage(error instanceof Error ? error.message : 'Falha ao se comunicar com o servidor de teste.');
}
};
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
if (testStatus === 'success') {
onConnect(email, user, host, port, secure);
} else {
alert('Por favor, teste a conexão com sucesso antes de adicionar a conta.');
}
};
return (
<form onSubmit={handleSubmit} className="space-y-4">
{/* Campos do formulário... */}
<div>
<label htmlFor="email" className="block text-sm font-medium text-slate-700 dark:text-slate-300">Endereço de E-mail (para exibição)</label>
<input type="email" id="email" value={email} onChange={(e) => setEmail(e.target.value)} required className="mt-1 block w-full input" placeholder="seunome@dominio.com" />
</div>
<div>
<label htmlFor="user" className="block text-sm font-medium text-slate-700 dark:text-slate-300">Nome de Usuário (para login)</label>
<input type="text" id="user" value={user} onChange={(e) => setUser(e.target.value)} required className="mt-1 block w-full input" placeholder="geralmente o mesmo que o e-mail" />
</div>
<div>
<label htmlFor="password" className="block text-sm font-medium text-slate-700 dark:text-slate-300">Senha</label>
<input type="password" id="password" value={password} onChange={(e) => setPassword(e.target.value)} required className="mt-1 block w-full input" />
</div>
<div className="grid grid-cols-3 gap-4">
<div className="col-span-2">
<label htmlFor="host" className="block text-sm font-medium text-slate-700 dark:text-slate-300">Servidor IMAP</label>
<input type="text" id="host" value={host} onChange={(e) => setHost(e.target.value)} required className="mt-1 block w-full input" placeholder="imap.dominio.com" />
</div>
<div>
<label htmlFor="port" className="block text-sm font-medium text-slate-700 dark:text-slate-300">Porta</label>
<input type="number" id="port" value={port} onChange={(e) => setPort(parseInt(e.target.value))} required className="mt-1 block w-full input" />
</div>
</div>
<div className="flex items-center">
<input type="checkbox" id="secure" checked={secure} onChange={(e) => setSecure(e.target.checked)} className="h-4 w-4 rounded border-slate-300 text-sky-600 focus:ring-sky-500" />
<label htmlFor="secure" className="ml-2 block text-sm text-slate-900 dark:text-slate-300">Usar conexão segura (SSL/TLS)</label>
</div>
{testMessage && (
<div className={`text-sm p-3 rounded-md ${testStatus === 'success' ? 'bg-green-100 text-green-800' : 'bg-red-100 text-red-800'}`}>
{testMessage}
</div>
)}
<div className="flex items-center justify-between gap-3 pt-2">
<button type="button" onClick={onBack} className="btn-secondary">Voltar</button>
<div className="flex items-center gap-3">
<button type="button" onClick={handleTestConnection} disabled={testStatus === 'testing'} className="btn-secondary flex items-center gap-2">
{testStatus === 'testing' && <Spinner className="w-4 h-4" />}
{testStatus === 'testing' ? 'Testando...' : 'Testar Conexão'}
</button>
<button type="submit" disabled={testStatus !== 'success'} className="btn-primary disabled:opacity-50 disabled:cursor-not-allowed">
Adicionar Conta
</button>
</div>
</div>
</form>
);
};
export default AddImapAccountForm;