Correção de vazamento de dados nas páginas de erro e nos logs
Três problemas de exposição, todos com o mesmo efeito: dado interno saindo para quem não deveria ver. 1. Painel de debug do Rails na tela do usuário O servidor sobe com RAILS_ENV=development (docker-compose.yml), e development tinha `consider_all_requests_local = true`. A página "Action Controller: Exception caught" mostra parâmetros, SESSÃO (session_id, _csrf_token, id do usuário logado), cookies, IP do cliente, caminho do servidor e o trace inteiro — para qualquer pessoa que provocasse um erro. Agora o detalhe depende de ERROS_DETALHADOS=true, que só é ligado na máquina de desenvolvimento. 2. Senha e PIN em texto puro no log Não existia filter_parameter_logging.rb neste projeto: toda senha do login, PIN de motorista e token do WhatsApp iam para log/ em texto puro — e log vai junto em backup e em suporte. Era o pior dos três, porque é permanente e não aparece na tela de ninguém. 3. Páginas de erro do usuário final Sem public/500.html, desligar o painel deixaria tela em branco. Criadas 500/404/422 em português, sem CSS externo (precisam funcionar com a aplicação fora do ar). Também sai do versionamento a pasta Erros/, com 16 páginas de debug salvas do navegador. Não há cookie de sessão assinado nelas — ninguém entra no sistema com o que está ali — mas há session_id, token CSRF, id de usuário e IPs, que não têm por que estar no repositório. Correção estrutural pendente: subir o servidor com RAILS_ENV=production (production.rb já tem consider_all_requests_local=false e force_ssl=true). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -87,3 +87,9 @@ WHATSAPP_TOKEN=troque_por_uma_string_aleatoria_longa
|
|||||||
# do serviço no docker-compose.yml).
|
# do serviço no docker-compose.yml).
|
||||||
# (o nome antigo `BAILEYS_URL` ainda é aceito, para .env já em produção)
|
# (o nome antigo `BAILEYS_URL` ainda é aceito, para .env já em produção)
|
||||||
WHATSAPP_URL=http://whatsapp:3001
|
WHATSAPP_URL=http://whatsapp:3001
|
||||||
|
|
||||||
|
# ── Erros na tela ────────────────────────────────────────────────────────
|
||||||
|
# Mostra a página de debug do Rails (parâmetros, SESSÃO, cookies, IP, trace).
|
||||||
|
# Deixe SEMPRE vazia/false em qualquer servidor: esse painel vai para a tela de
|
||||||
|
# quem provocou o erro. Ligue só na sua máquina, quando estiver depurando.
|
||||||
|
ERROS_DETALHADOS=false
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,276 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="pt-BR" class="dark">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<meta name="csrf-param" content="authenticity_token">
|
|
||||||
<meta name="csrf-token" content="G-9RRM76mXTElY86HJ18dlR93xoYQyO4uD1MzgEGhSZLg9p1i8wFt73pl0AHSNGSxXOBT0R5D0q_c_iovOAGZQ">
|
|
||||||
<title>Reem Logística</title>
|
|
||||||
|
|
||||||
<script src="https://cdn.tailwindcss.com"></script>
|
|
||||||
<script>
|
|
||||||
tailwind.config = {
|
|
||||||
darkMode: 'class',
|
|
||||||
theme: {
|
|
||||||
extend: {
|
|
||||||
colors: {
|
|
||||||
brand: {
|
|
||||||
preto: '#0a0a0a',
|
|
||||||
'preto-card': '#1a1a1a',
|
|
||||||
laranja: '#f97316',
|
|
||||||
'laranja-escuro': '#ea580c',
|
|
||||||
branco: '#ffffff',
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet">
|
|
||||||
|
|
||||||
<style>
|
|
||||||
body { font-family: 'Inter', sans-serif; }
|
|
||||||
/* Scrollbar tema escuro */
|
|
||||||
::-webkit-scrollbar { width: 6px; }
|
|
||||||
::-webkit-scrollbar-track { background: #0a0a0a; }
|
|
||||||
::-webkit-scrollbar-thumb { background: #f97316; border-radius: 3px; }
|
|
||||||
/* Loading spinner laranja */
|
|
||||||
.spinner {
|
|
||||||
border: 3px solid #1a1a1a;
|
|
||||||
border-top-color: #f97316;
|
|
||||||
border-radius: 50%;
|
|
||||||
animation: spin 0.8s linear infinite;
|
|
||||||
}
|
|
||||||
@keyframes spin { to { transform: rotate(360deg); } }
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<script type="importmap" data-turbo-track="reload">{
|
|
||||||
"imports": {
|
|
||||||
"application": "/assets/application-09caced1.js",
|
|
||||||
"@hotwired/turbo-rails": "/assets/turbo.min-86bf8853.js",
|
|
||||||
"@hotwired/stimulus": "/assets/stimulus.min-7ea3d58b.js",
|
|
||||||
"@hotwired/stimulus-loading": "/assets/stimulus-loading-25917588.js",
|
|
||||||
"controllers/application": "/assets/controllers/application-75a69c37.js",
|
|
||||||
"controllers": "/assets/controllers/index-dfefe98d.js",
|
|
||||||
"controllers/validacao_controller": "/assets/controllers/validacao_controller-3ce614b7.js"
|
|
||||||
}
|
|
||||||
}</script>
|
|
||||||
<link rel="modulepreload" href="/assets/application-09caced1.js">
|
|
||||||
<link rel="modulepreload" href="/assets/turbo.min-86bf8853.js">
|
|
||||||
<link rel="modulepreload" href="/assets/stimulus.min-7ea3d58b.js">
|
|
||||||
<link rel="modulepreload" href="/assets/stimulus-loading-25917588.js">
|
|
||||||
<link rel="modulepreload" href="/assets/controllers/application-75a69c37.js">
|
|
||||||
<link rel="modulepreload" href="/assets/controllers/index-dfefe98d.js">
|
|
||||||
<link rel="modulepreload" href="/assets/controllers/validacao_controller-3ce614b7.js">
|
|
||||||
<script type="module">import "application"</script>
|
|
||||||
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body class="bg-[#0a0a0a] text-white min-h-screen">
|
|
||||||
|
|
||||||
|
|
||||||
<div id="sidebar-overlay"
|
|
||||||
class="fixed inset-0 bg-black/70 z-30 hidden md:hidden"
|
|
||||||
onclick="toggleSidebar()"></div>
|
|
||||||
|
|
||||||
<aside id="sidebar"
|
|
||||||
class="fixed top-0 left-0 h-full w-64 bg-[#111111] border-r border-[#2a2a2a] z-40
|
|
||||||
transform -translate-x-full md:translate-x-0 transition-transform duration-300">
|
|
||||||
|
|
||||||
<div class="flex items-center gap-3 px-6 py-5 border-b border-[#2a2a2a]">
|
|
||||||
<div class="w-9 h-9 bg-orange-500 rounded-lg flex items-center justify-center font-black text-black text-lg">G</div>
|
|
||||||
<div>
|
|
||||||
<p class="font-bold text-white text-sm leading-tight">Reem Transporte</p>
|
|
||||||
<p class="text-orange-500 text-xs">Logística</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="px-6 py-4 border-b border-[#2a2a2a]">
|
|
||||||
<p class="text-xs text-gray-500 mb-1">Logado como</p>
|
|
||||||
<p class="text-white font-semibold text-sm truncate">Administrador Gade</p>
|
|
||||||
<span class="inline-block mt-1 px-2 py-0.5 text-xs rounded-full
|
|
||||||
bg-orange-500 text-black">
|
|
||||||
Administrador
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<nav class="px-3 py-4 space-y-1 flex-1 overflow-y-auto">
|
|
||||||
|
|
||||||
<a class="flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium transition-all min-h-[44px] text-gray-400 hover:bg-[#1a1a1a] hover:text-white" href="/dashboard">📊 Dashboard</a>
|
|
||||||
<a class="flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium transition-all min-h-[44px] text-gray-400 hover:bg-[#1a1a1a] hover:text-white" href="/consolidacoes">📦 Consolidações</a>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="pt-4 mt-4 border-t border-[#2a2a2a]">
|
|
||||||
<p class="px-3 text-xs text-gray-600 uppercase tracking-wider mb-2">Administração</p>
|
|
||||||
<a class="flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium transition-all min-h-[44px] text-gray-400 hover:bg-[#1a1a1a] hover:text-white" href="/admin/usuarios">👥 Usuários</a>
|
|
||||||
<a class="flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium transition-all min-h-[44px] text-gray-400 hover:bg-[#1a1a1a] hover:text-white" href="/admin/configuracoes">⚙️ Configurações</a>
|
|
||||||
<a class="flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium transition-all min-h-[44px] text-gray-400 hover:bg-[#1a1a1a] hover:text-white" href="/admin/auditoria_logs">🔍 Auditoria</a>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div class="px-6 py-4 border-t border-[#2a2a2a]">
|
|
||||||
<a data-turbo-method="delete" data-turbo-confirm="Deseja sair?" class="flex items-center gap-2 text-gray-400 hover:text-red-400 text-sm transition-colors" href="/auth/logout">
|
|
||||||
<span>🚪</span> Sair
|
|
||||||
</a> </div>
|
|
||||||
</aside>
|
|
||||||
|
|
||||||
<header class="md:hidden fixed top-0 left-0 right-0 z-30 bg-[#111111] border-b border-[#2a2a2a] px-4 py-3 flex items-center justify-between">
|
|
||||||
<button onclick="toggleSidebar()"
|
|
||||||
class="text-orange-500 text-2xl min-h-[48px] min-w-[48px] flex items-center justify-center">
|
|
||||||
☰
|
|
||||||
</button>
|
|
||||||
<div class="flex items-center gap-2">
|
|
||||||
<div class="w-7 h-7 bg-orange-500 rounded flex items-center justify-center font-black text-black text-sm">G</div>
|
|
||||||
<span class="font-bold text-white text-sm">Reem Logística</span>
|
|
||||||
</div>
|
|
||||||
<div class="w-12"></div>
|
|
||||||
</header>
|
|
||||||
<div class="h-14 md:hidden"></div>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
function toggleSidebar() {
|
|
||||||
const s = document.getElementById('sidebar');
|
|
||||||
const o = document.getElementById('sidebar-overlay');
|
|
||||||
s.classList.toggle('-translate-x-full');
|
|
||||||
o.classList.toggle('hidden');
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<main class="ml-0 md:ml-64 p-4 md:p-8 min-h-screen">
|
|
||||||
<div class="max-w-2xl mx-auto space-y-6">
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<h1 class="text-2xl font-bold text-white">
|
|
||||||
Novo Usuário
|
|
||||||
</h1>
|
|
||||||
<p class="text-gray-400 text-sm mt-0.5">
|
|
||||||
Preencha os dados para criar um novo acesso
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<form class="bg-[#1a1a1a] rounded-2xl border border-white/5 p-8 space-y-6" action="/admin/usuarios" accept-charset="UTF-8" method="post"><input type="hidden" name="authenticity_token" value="ENsNJddbt-MKLOBei4dMU8xI5qs3plOiQMzqfepJ4wk7d_oooUwVJUOzd7xxU_Kjqz8jnh7JOzPwpymLh0pwVQ" autocomplete="off" />
|
|
||||||
|
|
||||||
|
|
||||||
<div class="grid grid-cols-1 sm:grid-cols-2 gap-6">
|
|
||||||
<div class="sm:col-span-2">
|
|
||||||
<label class="block text-sm font-medium text-gray-300 mb-1.5" for="user_nome">Nome completo</label>
|
|
||||||
<input class="w-full px-4 py-3 bg-[#0a0a0a] border border-white/10 rounded-xl text-white
|
|
||||||
placeholder-gray-600 focus:outline-none focus:border-[#f97316] focus:ring-1
|
|
||||||
focus:ring-[#f97316] transition-colors" placeholder="João da Silva" type="text" name="user[nome]" id="user_nome" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<label class="block text-sm font-medium text-gray-300 mb-1.5" for="user_role">Perfil de acesso</label>
|
|
||||||
<select class="w-full px-4 py-3 bg-[#0a0a0a] border border-white/10 rounded-xl text-white
|
|
||||||
focus:outline-none focus:border-[#f97316] focus:ring-1 focus:ring-[#f97316]
|
|
||||||
transition-colors cursor-pointer" name="user[role]" id="user_role"><option value="admin">Administrador</option>
|
|
||||||
<option value="gerente">Gerente</option>
|
|
||||||
<option value="operador">Operador</option>
|
|
||||||
<option selected="selected" value="motorista">Motorista</option></select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex items-center">
|
|
||||||
<div class="flex-1">
|
|
||||||
<label class="block text-sm font-medium text-gray-300" for="user_ativo">Usuário ativo</label>
|
|
||||||
<p class="text-gray-500 text-xs mt-0.5">Usuários inativos não conseguem fazer login</p>
|
|
||||||
</div>
|
|
||||||
<label class="relative inline-flex items-center cursor-pointer ml-4">
|
|
||||||
<input name="user[ativo]" type="hidden" value="0" autocomplete="off" /><input class="sr-only peer" type="checkbox" value="1" checked="checked" name="user[ativo]" id="user_ativo" />
|
|
||||||
<div class="w-11 h-6 bg-gray-700 peer-focus:outline-none rounded-full peer
|
|
||||||
peer-checked:after:translate-x-full peer-checked:after:border-white
|
|
||||||
after:content-[''] after:absolute after:top-[2px] after:left-[2px]
|
|
||||||
after:bg-white after:border-gray-300 after:border after:rounded-full
|
|
||||||
after:h-5 after:w-5 after:transition-all peer-checked:bg-[#f97316]"></div>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="fields-email" class="space-y-6">
|
|
||||||
<div class="border-t border-white/5 pt-6">
|
|
||||||
<p class="text-sm font-medium text-gray-300 mb-4">Credenciais de acesso</p>
|
|
||||||
<div class="grid grid-cols-1 sm:grid-cols-2 gap-6">
|
|
||||||
<div class="sm:col-span-2">
|
|
||||||
<label class="block text-sm font-medium text-gray-300 mb-1.5" for="user_email">E-mail</label>
|
|
||||||
<input class="w-full px-4 py-3 bg-[#0a0a0a] border border-white/10 rounded-xl text-white
|
|
||||||
placeholder-gray-600 focus:outline-none focus:border-[#f97316] focus:ring-1
|
|
||||||
focus:ring-[#f97316] transition-colors" placeholder="usuario@gade.com" type="email" value="" name="user[email]" id="user_email" />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label class="block text-sm font-medium text-gray-300 mb-1.5" for="user_password">Senha</label>
|
|
||||||
<input class="w-full px-4 py-3 bg-[#0a0a0a] border border-white/10 rounded-xl text-white
|
|
||||||
placeholder-gray-600 focus:outline-none focus:border-[#f97316] focus:ring-1
|
|
||||||
focus:ring-[#f97316] transition-colors" placeholder="••••••••" type="password" name="user[password]" id="user_password" />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label class="block text-sm font-medium text-gray-300 mb-1.5" for="user_password_confirmation">Confirmar senha</label>
|
|
||||||
<input class="w-full px-4 py-3 bg-[#0a0a0a] border border-white/10 rounded-xl text-white
|
|
||||||
placeholder-gray-600 focus:outline-none focus:border-[#f97316] focus:ring-1
|
|
||||||
focus:ring-[#f97316] transition-colors" placeholder="••••••••" type="password" name="user[password_confirmation]" id="user_password_confirmation" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="fields-pin" class="hidden border-t border-white/5 pt-6">
|
|
||||||
<p class="text-sm font-medium text-gray-300 mb-4">PIN de acesso</p>
|
|
||||||
<div class="max-w-xs">
|
|
||||||
<label class="block text-sm font-medium text-gray-300 mb-1.5" for="user_pin_code">PIN (4 dígitos)</label>
|
|
||||||
<input maxlength="4" pattern="\d{4}" inputmode="numeric" class="w-full px-4 py-3 bg-[#0a0a0a] border border-white/10 rounded-xl text-white
|
|
||||||
placeholder-gray-600 focus:outline-none focus:border-[#f97316] focus:ring-1
|
|
||||||
focus:ring-[#f97316] transition-colors text-center text-2xl tracking-[0.5em] font-bold" placeholder="0000" size="4" type="text" name="user[pin_code]" id="user_pin_code" />
|
|
||||||
<p class="text-gray-500 text-xs mt-1.5">Deve ser único entre todos os motoristas</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex items-center justify-between pt-2 border-t border-white/5">
|
|
||||||
<a class="px-6 py-3 text-gray-400 hover:text-white border border-white/10
|
|
||||||
hover:border-white/20 rounded-xl transition-colors" href="/admin/usuarios">Cancelar</a>
|
|
||||||
<input type="submit" name="commit" value="Criar Usuário" class="px-8 py-3 bg-[#f97316] hover:bg-orange-500 text-white font-semibold
|
|
||||||
rounded-xl transition-colors cursor-pointer min-h-[48px]" data-disable-with="Criar Usuário" />
|
|
||||||
</div>
|
|
||||||
</form></div>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
// IIFE: evita "Identifier already declared" quando o Turbo re-executa o script
|
|
||||||
// ao navegar (o que antes abortava o toggle e escondia o campo de PIN).
|
|
||||||
(function () {
|
|
||||||
const roleSelect = document.querySelector('select[name="user[role]"]');
|
|
||||||
const fieldsEmail = document.getElementById('fields-email');
|
|
||||||
const fieldsPin = document.getElementById('fields-pin');
|
|
||||||
if (!roleSelect || !fieldsEmail || !fieldsPin) return;
|
|
||||||
|
|
||||||
function toggleFields() {
|
|
||||||
const motorista = roleSelect.value === 'motorista';
|
|
||||||
fieldsEmail.classList.toggle('hidden', motorista);
|
|
||||||
fieldsPin.classList.toggle('hidden', !motorista);
|
|
||||||
}
|
|
||||||
|
|
||||||
roleSelect.addEventListener('change', toggleFields);
|
|
||||||
toggleFields(); // estado inicial
|
|
||||||
})();
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
setTimeout(() => {
|
|
||||||
['flash-notice', 'flash-alert'].forEach(id => {
|
|
||||||
const el = document.getElementById(id);
|
|
||||||
if (el) el.style.transition = 'opacity 0.5s', el.style.opacity = '0',
|
|
||||||
setTimeout(() => el.remove(), 500);
|
|
||||||
});
|
|
||||||
}, 4000);
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<script async nonce="" type="text/javascript" id="mini-profiler" src="/mini-profiler-resources/includes.js?v=e0bcc9ce0ae3bb5d6b736b6f282f601f" data-css-url="/mini-profiler-resources/includes.css?v=e0bcc9ce0ae3bb5d6b736b6f282f601f" data-version="e0bcc9ce0ae3bb5d6b736b6f282f601f" data-path="/mini-profiler-resources/" data-current-id="1ahgpnmdas9x6acftfbr" data-ids="1ahgpnmdas9x6acftfbr,ho1l1mkabtvdcaskpjm7" data-horizontal-position="left" data-vertical-position="top" data-trivial="false" data-children="false" data-max-traces="20" data-controls="false" data-total-sql-count="false" data-authorized="true" data-toggle-shortcut="alt+p" data-start-hidden="false" data-collapse-results="true" data-html-container="body" data-hidden-custom-fields="" data-turbo-permanent="false"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 132 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 92 KiB |
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,252 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="pt-BR" class="dark">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<meta name="csrf-param" content="authenticity_token">
|
|
||||||
<meta name="csrf-token" content="V0huiUnnR6iuZZliHnfydw0_28pJd5ho66yiE1jO186V5ffx6xm7oL5TuqTEwVv9v-9pxKKkTDbXwLQRAdLL3w">
|
|
||||||
<title>teste | Reem Logística</title>
|
|
||||||
|
|
||||||
<script src="https://cdn.tailwindcss.com"></script>
|
|
||||||
<script>
|
|
||||||
tailwind.config = {
|
|
||||||
darkMode: 'class',
|
|
||||||
theme: {
|
|
||||||
extend: {
|
|
||||||
colors: {
|
|
||||||
brand: {
|
|
||||||
preto: '#0a0a0a',
|
|
||||||
'preto-card': '#1a1a1a',
|
|
||||||
laranja: '#f97316',
|
|
||||||
'laranja-escuro': '#ea580c',
|
|
||||||
branco: '#ffffff',
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet">
|
|
||||||
|
|
||||||
<style>
|
|
||||||
body { font-family: 'Inter', sans-serif; }
|
|
||||||
/* Scrollbar tema escuro */
|
|
||||||
::-webkit-scrollbar { width: 6px; }
|
|
||||||
::-webkit-scrollbar-track { background: #0a0a0a; }
|
|
||||||
::-webkit-scrollbar-thumb { background: #f97316; border-radius: 3px; }
|
|
||||||
/* Loading spinner laranja */
|
|
||||||
.spinner {
|
|
||||||
border: 3px solid #1a1a1a;
|
|
||||||
border-top-color: #f97316;
|
|
||||||
border-radius: 50%;
|
|
||||||
animation: spin 0.8s linear infinite;
|
|
||||||
}
|
|
||||||
@keyframes spin { to { transform: rotate(360deg); } }
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<script type="importmap" data-turbo-track="reload">{
|
|
||||||
"imports": {
|
|
||||||
"application": "/assets/application-09caced1.js",
|
|
||||||
"@hotwired/turbo-rails": "/assets/turbo.min-86bf8853.js",
|
|
||||||
"@hotwired/stimulus": "/assets/stimulus.min-7ea3d58b.js",
|
|
||||||
"@hotwired/stimulus-loading": "/assets/stimulus-loading-25917588.js",
|
|
||||||
"controllers/application": "/assets/controllers/application-75a69c37.js",
|
|
||||||
"controllers": "/assets/controllers/index-dfefe98d.js",
|
|
||||||
"controllers/validacao_controller": "/assets/controllers/validacao_controller-3ce614b7.js"
|
|
||||||
}
|
|
||||||
}</script>
|
|
||||||
<link rel="modulepreload" href="/assets/application-09caced1.js">
|
|
||||||
<link rel="modulepreload" href="/assets/turbo.min-86bf8853.js">
|
|
||||||
<link rel="modulepreload" href="/assets/stimulus.min-7ea3d58b.js">
|
|
||||||
<link rel="modulepreload" href="/assets/stimulus-loading-25917588.js">
|
|
||||||
<link rel="modulepreload" href="/assets/controllers/application-75a69c37.js">
|
|
||||||
<link rel="modulepreload" href="/assets/controllers/index-dfefe98d.js">
|
|
||||||
<link rel="modulepreload" href="/assets/controllers/validacao_controller-3ce614b7.js">
|
|
||||||
<script type="module">import "application"</script>
|
|
||||||
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body class="bg-[#0a0a0a] text-white min-h-screen">
|
|
||||||
|
|
||||||
|
|
||||||
<div id="sidebar-overlay"
|
|
||||||
class="fixed inset-0 bg-black/70 z-30 hidden md:hidden"
|
|
||||||
onclick="toggleSidebar()"></div>
|
|
||||||
|
|
||||||
<aside id="sidebar"
|
|
||||||
class="fixed top-0 left-0 h-full w-64 bg-[#111111] border-r border-[#2a2a2a] z-40
|
|
||||||
transform -translate-x-full md:translate-x-0 transition-transform duration-300">
|
|
||||||
|
|
||||||
<div class="flex items-center gap-3 px-6 py-5 border-b border-[#2a2a2a]">
|
|
||||||
<div class="w-9 h-9 bg-orange-500 rounded-lg flex items-center justify-center font-black text-black text-lg">G</div>
|
|
||||||
<div>
|
|
||||||
<p class="font-bold text-white text-sm leading-tight">Reem Transporte</p>
|
|
||||||
<p class="text-orange-500 text-xs">Logística</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="px-6 py-4 border-b border-[#2a2a2a]">
|
|
||||||
<p class="text-xs text-gray-500 mb-1">Logado como</p>
|
|
||||||
<p class="text-white font-semibold text-sm truncate">Administrador Gade</p>
|
|
||||||
<span class="inline-block mt-1 px-2 py-0.5 text-xs rounded-full
|
|
||||||
bg-orange-500 text-black">
|
|
||||||
Administrador
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<nav class="px-3 py-4 space-y-1 flex-1 overflow-y-auto">
|
|
||||||
|
|
||||||
<a class="flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium transition-all min-h-[44px] text-gray-400 hover:bg-[#1a1a1a] hover:text-white" href="/dashboard">📊 Dashboard</a>
|
|
||||||
<a class="flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium transition-all min-h-[44px] text-gray-400 hover:bg-[#1a1a1a] hover:text-white" href="/consolidacoes">📦 Consolidações</a>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="pt-4 mt-4 border-t border-[#2a2a2a]">
|
|
||||||
<p class="px-3 text-xs text-gray-600 uppercase tracking-wider mb-2">Administração</p>
|
|
||||||
<a class="flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium transition-all min-h-[44px] text-gray-400 hover:bg-[#1a1a1a] hover:text-white" href="/admin/usuarios">👥 Usuários</a>
|
|
||||||
<a class="flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium transition-all min-h-[44px] text-gray-400 hover:bg-[#1a1a1a] hover:text-white" href="/admin/configuracoes">⚙️ Configurações</a>
|
|
||||||
<a class="flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium transition-all min-h-[44px] text-gray-400 hover:bg-[#1a1a1a] hover:text-white" href="/admin/auditoria_logs">🔍 Auditoria</a>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div class="px-6 py-4 border-t border-[#2a2a2a]">
|
|
||||||
<a data-turbo-method="delete" data-turbo-confirm="Deseja sair?" class="flex items-center gap-2 text-gray-400 hover:text-red-400 text-sm transition-colors" href="/auth/logout">
|
|
||||||
<span>🚪</span> Sair
|
|
||||||
</a> </div>
|
|
||||||
</aside>
|
|
||||||
|
|
||||||
<header class="md:hidden fixed top-0 left-0 right-0 z-30 bg-[#111111] border-b border-[#2a2a2a] px-4 py-3 flex items-center justify-between">
|
|
||||||
<button onclick="toggleSidebar()"
|
|
||||||
class="text-orange-500 text-2xl min-h-[48px] min-w-[48px] flex items-center justify-center">
|
|
||||||
☰
|
|
||||||
</button>
|
|
||||||
<div class="flex items-center gap-2">
|
|
||||||
<div class="w-7 h-7 bg-orange-500 rounded flex items-center justify-center font-black text-black text-sm">G</div>
|
|
||||||
<span class="font-bold text-white text-sm">Reem Logística</span>
|
|
||||||
</div>
|
|
||||||
<div class="w-12"></div>
|
|
||||||
</header>
|
|
||||||
<div class="h-14 md:hidden"></div>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
function toggleSidebar() {
|
|
||||||
const s = document.getElementById('sidebar');
|
|
||||||
const o = document.getElementById('sidebar-overlay');
|
|
||||||
s.classList.toggle('-translate-x-full');
|
|
||||||
o.classList.toggle('hidden');
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<main class="ml-0 md:ml-64 p-4 md:p-8 min-h-screen">
|
|
||||||
|
|
||||||
<div class="max-w-4xl mx-auto">
|
|
||||||
|
|
||||||
<div class="mb-6">
|
|
||||||
<a class="text-gray-500 hover:text-orange-500 text-sm" href="/consolidacoes">← Consolidações</a>
|
|
||||||
<div class="flex flex-col md:flex-row md:items-center md:justify-between gap-3 mt-2">
|
|
||||||
<div>
|
|
||||||
<div class="flex items-center gap-3">
|
|
||||||
<h1 class="text-2xl font-bold text-white">teste</h1>
|
|
||||||
<span class="inline-flex items-center gap-1 px-2.5 py-1 rounded-full text-xs font-bold bg-yellow-500 text-black">📝 Rascunho</span>
|
|
||||||
</div>
|
|
||||||
<p class="text-gray-400 text-sm mt-1">
|
|
||||||
📅 01/02/2026 → 28/02/2026
|
|
||||||
· Criada por Administrador Gade
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div class="flex gap-2">
|
|
||||||
<a class="bg-orange-500 hover:bg-orange-600 text-black font-bold px-5 py-3 rounded-lg min-h-[48px] flex items-center" href="/consolidacoes/3/wizard">✏️ Continuar validação</a>
|
|
||||||
<form class="button_to" method="post" action="/consolidacoes/3/arquivar"><button data-turbo-confirm="Arquivar esta consolidação? Ela não será excluída, apenas movida para o arquivo." class="text-gray-400 hover:text-white border border-[#2a2a2a] px-4 py-3 rounded-lg min-h-[48px]" type="submit">📁 Arquivar</button><input type="hidden" name="authenticity_token" value="bFgW-DhUfHVabQb6YBBZhcI6kTfr6RY-m2AcIg74Too_85JbSI2x1yKmq7VymjoA3QnfDb2v-F5VSGRHh8Q_DQ" autocomplete="off" /></form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="bg-[#1a1a1a] border border-orange-500 rounded-xl p-6 mb-6 text-center">
|
|
||||||
<p class="text-gray-400 text-sm">Valor total da consolidação</p>
|
|
||||||
<p class="text-orange-500 font-black text-4xl">R$ 5265,00</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h2 class="text-white font-bold text-lg mb-3">👥 Motoristas</h2>
|
|
||||||
<div class="space-y-3">
|
|
||||||
<div class="bg-[#1a1a1a] border border-[#2a2a2a] rounded-xl p-5">
|
|
||||||
<div class="flex flex-col md:flex-row md:items-center md:justify-between gap-4">
|
|
||||||
<div>
|
|
||||||
<p class="text-white font-bold text-lg">Bruno Corgozinho</p>
|
|
||||||
<p class="text-orange-500 font-black text-xl">R$ 5265,00</p>
|
|
||||||
</div>
|
|
||||||
<div class="flex flex-wrap gap-2">
|
|
||||||
<button onclick="abrirPreview('/consolidacoes/3/preview_holerite?motorista=Bruno+Corgozinho')"
|
|
||||||
class="bg-[#0a0a0a] hover:bg-[#2a2a2a] text-white border border-orange-500 font-semibold px-4 py-3 rounded-lg text-sm min-h-[48px]">
|
|
||||||
👁️ Ver antes de gerar
|
|
||||||
</button>
|
|
||||||
<a class="bg-orange-800 hover:bg-orange-700 text-white font-semibold px-4 py-3 rounded-lg text-sm min-h-[48px] flex items-center" href="/consolidacoes/3/gerar_pdf_relatorio?motorista=Bruno+Corgozinho">📄 Relatório Individual</a>
|
|
||||||
<a class="bg-orange-500 hover:bg-orange-600 text-black font-bold px-4 py-3 rounded-lg text-sm min-h-[48px] flex items-center" href="/consolidacoes/3/gerar_pdf_holerite?motorista=Bruno+Corgozinho">🧾 Gerar Holerite</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="modal-preview" class="fixed inset-0 bg-black/80 z-50 hidden items-center justify-center p-4">
|
|
||||||
<div class="bg-[#1a1a1a] border border-[#2a2a2a] rounded-2xl max-w-2xl w-full max-h-[85vh] flex flex-col">
|
|
||||||
<div class="flex items-center justify-between px-6 py-4 border-b border-[#2a2a2a]">
|
|
||||||
<h3 class="text-white font-bold">👁️ Pré-visualização do Holerite</h3>
|
|
||||||
<button onclick="fecharPreview()" class="text-gray-400 hover:text-white text-2xl min-w-[44px] min-h-[44px]">✕</button>
|
|
||||||
</div>
|
|
||||||
<div id="modal-preview-conteudo" class="overflow-y-auto p-6 flex-1">
|
|
||||||
<div class="flex justify-center py-10"><div class="spinner w-10 h-10"></div></div>
|
|
||||||
</div>
|
|
||||||
<div class="flex gap-3 px-6 py-4 border-t border-[#2a2a2a]">
|
|
||||||
<a id="modal-confirmar" href="#"
|
|
||||||
class="flex-1 bg-orange-500 hover:bg-orange-600 text-black font-bold py-3 rounded-lg text-center min-h-[48px] flex items-center justify-center">
|
|
||||||
✓ Confirmar e baixar PDF
|
|
||||||
</a>
|
|
||||||
<button onclick="fecharPreview()"
|
|
||||||
class="px-6 py-3 text-gray-400 hover:text-white border border-[#2a2a2a] rounded-lg min-h-[48px]">
|
|
||||||
← Voltar
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
async function abrirPreview(url) {
|
|
||||||
const modal = document.getElementById('modal-preview');
|
|
||||||
const conteudo = document.getElementById('modal-preview-conteudo');
|
|
||||||
modal.classList.remove('hidden');
|
|
||||||
modal.classList.add('flex');
|
|
||||||
conteudo.innerHTML = '<div class="flex justify-center py-10"><div class="spinner w-10 h-10"></div></div>';
|
|
||||||
|
|
||||||
const resp = await fetch(url);
|
|
||||||
conteudo.innerHTML = await resp.text();
|
|
||||||
|
|
||||||
// O link de confirmar aponta para o PDF do mesmo motorista
|
|
||||||
document.getElementById('modal-confirmar').href =
|
|
||||||
url.replace('preview_holerite', 'gerar_pdf_holerite');
|
|
||||||
}
|
|
||||||
function fecharPreview() {
|
|
||||||
const modal = document.getElementById('modal-preview');
|
|
||||||
modal.classList.add('hidden');
|
|
||||||
modal.classList.remove('flex');
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
setTimeout(() => {
|
|
||||||
['flash-notice', 'flash-alert'].forEach(id => {
|
|
||||||
const el = document.getElementById(id);
|
|
||||||
if (el) el.style.transition = 'opacity 0.5s', el.style.opacity = '0',
|
|
||||||
setTimeout(() => el.remove(), 500);
|
|
||||||
});
|
|
||||||
}, 4000);
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<script async nonce="" type="text/javascript" id="mini-profiler" src="/mini-profiler-resources/includes.js?v=e0bcc9ce0ae3bb5d6b736b6f282f601f" data-css-url="/mini-profiler-resources/includes.css?v=e0bcc9ce0ae3bb5d6b736b6f282f601f" data-version="e0bcc9ce0ae3bb5d6b736b6f282f601f" data-path="/mini-profiler-resources/" data-current-id="5vfdctp5mnyu0tdtx94a" data-ids="5vfdctp5mnyu0tdtx94a,md2esz0jc4j57ce236e8" data-horizontal-position="left" data-vertical-position="top" data-trivial="false" data-children="false" data-max-traces="20" data-controls="false" data-total-sql-count="false" data-authorized="true" data-toggle-shortcut="alt+p" data-start-hidden="false" data-collapse-results="true" data-html-container="body" data-hidden-custom-fields="" data-turbo-permanent="false"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -3,7 +3,21 @@ require "active_support/core_ext/integer/time"
|
|||||||
Rails.application.configure do
|
Rails.application.configure do
|
||||||
config.enable_reloading = true
|
config.enable_reloading = true
|
||||||
config.eager_load = false
|
config.eager_load = false
|
||||||
config.consider_all_requests_local = true
|
# ⚠️ SEGURANÇA — a página de debug do Rails ("Action Controller: Exception
|
||||||
|
# caught") mostra parâmetros, SESSÃO, cookies, IP do cliente, caminho do
|
||||||
|
# servidor e o trace inteiro. O servidor de teste/produção sobe com
|
||||||
|
# RAILS_ENV=development (docker-compose.yml), então esse painel estava indo
|
||||||
|
# para a tela de qualquer pessoa que provocasse um erro.
|
||||||
|
#
|
||||||
|
# Agora o detalhe só aparece quando ALGUÉM PEDE explicitamente, na máquina de
|
||||||
|
# desenvolvimento: `ERROS_DETALHADOS=true` no .env local. Sem a variável, o
|
||||||
|
# visitante recebe a página estática de public/500.html.
|
||||||
|
config.consider_all_requests_local = ENV['ERROS_DETALHADOS'] == 'true'
|
||||||
|
|
||||||
|
# Sem isso, com consider_all_requests_local=false o Rails ainda tentaria
|
||||||
|
# renderizar o painel para requisições vindas de localhost.
|
||||||
|
config.action_dispatch.show_exceptions = :all
|
||||||
|
|
||||||
config.server_timing = true
|
config.server_timing = true
|
||||||
|
|
||||||
config.cache_store = :memory_store
|
config.cache_store = :memory_store
|
||||||
|
|||||||
19
config/initializers/filter_parameter_logging.rb
Normal file
19
config/initializers/filter_parameter_logging.rb
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# config/initializers/filter_parameter_logging.rb
|
||||||
|
#
|
||||||
|
# ⚠️ SEGURANÇA — sem esta lista, TODO parâmetro entra no log em texto puro:
|
||||||
|
# senha digitada no login, PIN do motorista, token de acesso do WhatsApp, cookie
|
||||||
|
# de sessão. O arquivo de log é lido por quem tem acesso ao servidor e costuma
|
||||||
|
# ser copiado junto em backup e em suporte.
|
||||||
|
#
|
||||||
|
# Os nomes são casados por SUBSTRING (`:senha` filtra `senha_confirmation`), e a
|
||||||
|
# lista é em português e inglês porque o projeto tem os dois (Devise usa
|
||||||
|
# `password`, o resto do sistema usa `senha`/`pin`).
|
||||||
|
Rails.application.config.filter_parameters += %i[
|
||||||
|
passw password password_confirmation
|
||||||
|
senha senha_confirmation
|
||||||
|
pin pin_code pin_acesso
|
||||||
|
secret token _key crypt salt certificate otp ssn
|
||||||
|
authorization cookie session
|
||||||
|
auth_token access_token api_key
|
||||||
|
whatsapp_token twilio_auth_token smtp_senha smtp_password
|
||||||
|
]
|
||||||
29
public/404.html
Normal file
29
public/404.html
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="pt-BR">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||||
|
<title>Página não encontrada · Reem Transporte</title>
|
||||||
|
<style>
|
||||||
|
/* Sem CSS externo de propósito: esta página precisa funcionar mesmo quando
|
||||||
|
a aplicação está fora do ar (é o único caso em que ela aparece). */
|
||||||
|
body { margin:0; min-height:100vh; display:flex; align-items:center; justify-content:center;
|
||||||
|
background:#0a0a0a; color:#fff; font-family:Arial,Helvetica,sans-serif; padding:24px; }
|
||||||
|
.caixa { max-width:520px; text-align:center; }
|
||||||
|
.marca { color:#f97316; font-weight:bold; letter-spacing:.08em; font-size:14px; text-transform:uppercase; }
|
||||||
|
h1 { font-size:24px; margin:12px 0 8px; }
|
||||||
|
p { color:#9ca3af; font-size:16px; line-height:1.6; margin:0 0 8px; }
|
||||||
|
a { display:inline-block; margin-top:24px; background:#f97316; color:#000; font-weight:bold;
|
||||||
|
text-decoration:none; padding:14px 24px; border-radius:12px; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="caixa">
|
||||||
|
<p class="marca">Reem Transporte</p>
|
||||||
|
<h1>Página não encontrada</h1>
|
||||||
|
<p>O endereço que você abriu não existe ou foi movido.</p>
|
||||||
|
<p>Confira o link ou use o menu para chegar onde precisa.</p>
|
||||||
|
<a href="/">Voltar ao início</a>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
29
public/422.html
Normal file
29
public/422.html
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="pt-BR">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||||
|
<title>Não foi possível concluir · Reem Transporte</title>
|
||||||
|
<style>
|
||||||
|
/* Sem CSS externo de propósito: esta página precisa funcionar mesmo quando
|
||||||
|
a aplicação está fora do ar (é o único caso em que ela aparece). */
|
||||||
|
body { margin:0; min-height:100vh; display:flex; align-items:center; justify-content:center;
|
||||||
|
background:#0a0a0a; color:#fff; font-family:Arial,Helvetica,sans-serif; padding:24px; }
|
||||||
|
.caixa { max-width:520px; text-align:center; }
|
||||||
|
.marca { color:#f97316; font-weight:bold; letter-spacing:.08em; font-size:14px; text-transform:uppercase; }
|
||||||
|
h1 { font-size:24px; margin:12px 0 8px; }
|
||||||
|
p { color:#9ca3af; font-size:16px; line-height:1.6; margin:0 0 8px; }
|
||||||
|
a { display:inline-block; margin-top:24px; background:#f97316; color:#000; font-weight:bold;
|
||||||
|
text-decoration:none; padding:14px 24px; border-radius:12px; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="caixa">
|
||||||
|
<p class="marca">Reem Transporte</p>
|
||||||
|
<h1>Não foi possível concluir</h1>
|
||||||
|
<p>A ação foi recusada por uma verificação de segurança.</p>
|
||||||
|
<p>Normalmente isso acontece quando a página ficou aberta tempo demais — recarregue e tente de novo.</p>
|
||||||
|
<a href="/">Voltar ao início</a>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
29
public/500.html
Normal file
29
public/500.html
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="pt-BR">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||||
|
<title>Algo deu errado do nosso lado · Reem Transporte</title>
|
||||||
|
<style>
|
||||||
|
/* Sem CSS externo de propósito: esta página precisa funcionar mesmo quando
|
||||||
|
a aplicação está fora do ar (é o único caso em que ela aparece). */
|
||||||
|
body { margin:0; min-height:100vh; display:flex; align-items:center; justify-content:center;
|
||||||
|
background:#0a0a0a; color:#fff; font-family:Arial,Helvetica,sans-serif; padding:24px; }
|
||||||
|
.caixa { max-width:520px; text-align:center; }
|
||||||
|
.marca { color:#f97316; font-weight:bold; letter-spacing:.08em; font-size:14px; text-transform:uppercase; }
|
||||||
|
h1 { font-size:24px; margin:12px 0 8px; }
|
||||||
|
p { color:#9ca3af; font-size:16px; line-height:1.6; margin:0 0 8px; }
|
||||||
|
a { display:inline-block; margin-top:24px; background:#f97316; color:#000; font-weight:bold;
|
||||||
|
text-decoration:none; padding:14px 24px; border-radius:12px; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="caixa">
|
||||||
|
<p class="marca">Reem Transporte</p>
|
||||||
|
<h1>Algo deu errado do nosso lado</h1>
|
||||||
|
<p>Registramos o problema e a equipe já consegue ver o que aconteceu.</p>
|
||||||
|
<p>Tente de novo em alguns instantes. Se continuar, avise o administrador do sistema informando o que você estava fazendo.</p>
|
||||||
|
<a href="/">Voltar ao início</a>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Reference in New Issue
Block a user