docs: adiciona estrutura de governança por contexto (AGENT, DOMAIN, DESIGN_SYSTEM, TASKS)
This commit is contained in:
parent
722d7bf82a
commit
ebbbda5328
2 changed files with 102 additions and 74 deletions
28
frontend/DESIGN_SYSTEM.md
Normal file
28
frontend/DESIGN_SYSTEM.md
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
# SaveInMed - Design System
|
||||||
|
|
||||||
|
Diretrizes visuais para o frontend do SaveInMed.
|
||||||
|
|
||||||
|
## 🎨 Paleta de Cores
|
||||||
|
- **Primária**: `blue-600` (#2563EB) - Botões principais, links ativos.
|
||||||
|
- **Sucesso**: `green-600` (#16A34A) - Confirmações, status "Entregue".
|
||||||
|
- **Aviso**: `yellow-500` (#EAB308) - Alertas, status "Pendente".
|
||||||
|
- **Erro**: `red-600` (#DC2626) - Botões de deletar, mensagens de erro.
|
||||||
|
- **Fundo**: `gray-50` (#F9FAFB) - Background das páginas.
|
||||||
|
|
||||||
|
## 🔡 Tipografia
|
||||||
|
- **Títulos**: Inter ou Sans-serif, font-bold, text-gray-900.
|
||||||
|
- **Corpo**: Inter, text-gray-600.
|
||||||
|
|
||||||
|
## 🧩 Componentes Padrão
|
||||||
|
- **Botões**:
|
||||||
|
- `bg-blue-600 hover:bg-blue-700 text-white rounded-lg px-4 py-2 transition-colors`
|
||||||
|
- **Inputs**:
|
||||||
|
- `border border-gray-300 focus:ring-2 focus:ring-blue-500 rounded-lg`
|
||||||
|
- **Cards**:
|
||||||
|
- `bg-white shadow-sm border border-gray-100 rounded-xl p-6`
|
||||||
|
|
||||||
|
## 📦 Ícones
|
||||||
|
- **Biblioteca**: `Heroicons 24/outline`
|
||||||
|
- **Home**: `HomeIcon`
|
||||||
|
- **Carrinho**: `ShoppingCartIcon`
|
||||||
|
- **Usuário**: `UserIcon`
|
||||||
|
|
@ -15,21 +15,21 @@ const LoginPageContent = () => {
|
||||||
const { setEmpresaId } = useEmpresa();
|
const { setEmpresaId } = useEmpresa();
|
||||||
const searchParams = useSearchParams();
|
const searchParams = useSearchParams();
|
||||||
|
|
||||||
// Estados do formulÃÆ’ƒÂ¡rio
|
// Estados do formulário
|
||||||
const [email, setEmail] = useState<string>(""); // Email do usuÃÆ’ƒÂ¡rio
|
const [email, setEmail] = useState<string>(""); // Email do usuário
|
||||||
const [password, setPassword] = useState<string>(""); // Senha do usuÃÆ’ƒÂ¡rio
|
const [password, setPassword] = useState<string>(""); // Senha do usuário
|
||||||
const [name, setName] = useState<string>(""); // Nome completo (apenas para registro)
|
const [name, setName] = useState<string>(""); // Nome completo (apenas para registro)
|
||||||
const [loading, setLoading] = useState<boolean>(false); // Estado de carregamento
|
const [loading, setLoading] = useState<boolean>(false); // Estado de carregamento
|
||||||
const [error, setError] = useState<string>(""); // Mensagens de erro
|
const [error, setError] = useState<string>(""); // Mensagens de erro
|
||||||
const [isLogin, setIsLogin] = useState<boolean>(true); // Alterna entre login e registro
|
const [isLogin, setIsLogin] = useState<boolean>(true); // Alterna entre login e registro
|
||||||
const [checkingAuth, setCheckingAuth] = useState<boolean>(true); // VerificaÃÆ’ƒÂÂÂ§ÃÆ’ƒÂ£o inicial de autenticaÃÆ’ƒÂÂÂ§ÃÆ’ƒÂ£o
|
const [checkingAuth, setCheckingAuth] = useState<boolean>(true); // Verificação inicial de autenticação
|
||||||
const [showPassword, setShowPassword] = useState<boolean>(false); // Controla visibilidade da senha
|
const [showPassword, setShowPassword] = useState<boolean>(false); // Controla visibilidade da senha
|
||||||
const [accessToken, setAccessToken] = useState<string>(""); // Token de acesso da API
|
const [accessToken, setAccessToken] = useState<string>(""); // Token de acesso da API
|
||||||
const [showSuccessModal, setShowSuccessModal] = useState<boolean>(false); // Modal de sucesso do cadastro
|
const [showSuccessModal, setShowSuccessModal] = useState<boolean>(false); // Modal de sucesso do cadastro
|
||||||
const [showPendingModal, setShowPendingModal] = useState<boolean>(false); // Modal de cadastro pendente
|
const [showPendingModal, setShowPendingModal] = useState<boolean>(false); // Modal de cadastro pendente
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verifica parÃÆ’ƒÂ¢metros da URL para definir aba inicial
|
* Verifica par¢metros da URL para definir aba inicial
|
||||||
*/
|
*/
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const tab = searchParams.get('tab');
|
const tab = searchParams.get('tab');
|
||||||
|
|
@ -39,13 +39,13 @@ const LoginPageContent = () => {
|
||||||
}, [searchParams]);
|
}, [searchParams]);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verifica se o usuÃÆ’ƒÂ¡rio jÃÆ’ƒÂ¡ estÃÆ’ƒÂ¡ autenticado ao carregar a pÃÆ’ƒÂ¡gina
|
* Verifica se o usuário já está autenticado ao carregar a página
|
||||||
* Se estiver autenticado, redireciona para o dashboard
|
* Se estiver autenticado, redireciona para o dashboard
|
||||||
*/
|
*/
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const checkAuth = async () => {
|
const checkAuth = async () => {
|
||||||
try {
|
try {
|
||||||
// Verificar se hÃÆ’ƒÂ¡ token armazenado
|
// Verificar se há token armazenado
|
||||||
const storedToken = localStorage.getItem('access_token');
|
const storedToken = localStorage.getItem('access_token');
|
||||||
|
|
||||||
if (!storedToken) {
|
if (!storedToken) {
|
||||||
|
|
@ -53,14 +53,14 @@ const LoginPageContent = () => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verificar autenticaÃÆ’ÂÂ§ÃÆ’£o usando API com o token no header Authorization
|
// Verificar autenticação usando API com o token no header Authorization
|
||||||
const response = await fetch(
|
const response = await fetch(
|
||||||
`${API_V1_BASE_URL}/auth/me`,
|
`${API_V1_BASE_URL}/auth/me`,
|
||||||
{
|
{
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: {
|
headers: {
|
||||||
"accept": "application/json",
|
"accept": "application/json",
|
||||||
"Authorization": `Bearer ${storedToken}`, // Usar Authorization ao invÃÆ’ƒÂ©s de Cookie
|
"Authorization": `Bearer ${storedToken}`, // Usar Authorization ao invés de Cookie
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
@ -71,7 +71,7 @@ const LoginPageContent = () => {
|
||||||
router.push("/dashboard");
|
router.push("/dashboard");
|
||||||
} else {
|
} else {
|
||||||
const errorText = await response.text();
|
const errorText = await response.text();
|
||||||
// Limpar token invÃÆ’ƒÂ¡lido
|
// Limpar token inválido
|
||||||
localStorage.removeItem('access_token');
|
localStorage.removeItem('access_token');
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
@ -83,9 +83,9 @@ const LoginPageContent = () => {
|
||||||
}, [router]);
|
}, [router]);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* FunÃÆ’ÂÂ§ÃÆ’£o para realizar login do usuÃÆ’¡rio usando API
|
* Função para realizar login do usuário usando API
|
||||||
* @param email - Email do usuÃÆ’ƒÂ¡rio (usado como identificador)
|
* @param email - Email do usuário (usado como identificador)
|
||||||
* @param password - Senha do usuÃÆ’ƒÂ¡rio
|
* @param password - Senha do usuário
|
||||||
*/
|
*/
|
||||||
const login = async (email: string, password: string) => {
|
const login = async (email: string, password: string) => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
|
@ -108,32 +108,32 @@ const LoginPageContent = () => {
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
// Ler e logar o corpo da resposta (usando clone para nÃÆ’ƒÂ£o consumir o body original)
|
// Ler e logar o corpo da resposta (usando clone para não consumir o body original)
|
||||||
const respClone = response.clone();
|
const respClone = response.clone();
|
||||||
const respText = await respClone.text();
|
const respText = await respClone.text();
|
||||||
let respBody: any = respText;
|
let respBody: any = respText;
|
||||||
try {
|
try {
|
||||||
respBody = JSON.parse(respText);
|
respBody = JSON.parse(respText);
|
||||||
} catch {
|
} catch {
|
||||||
// corpo nÃÆ’ƒÂ£o ÃÆ’ƒÂ© JSON, manter como texto
|
// corpo não é JSON, manter como texto
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
// Extrair mensagem de erro do backend
|
// Extrair mensagem de erro do backend
|
||||||
let errorMessage = respBody?.message || respBody?.error || respBody?.detail || respText;
|
let errorMessage = respBody?.message || respBody?.error || respBody?.detail || respText;
|
||||||
|
|
||||||
// Tratar cÃÆ’ƒÂ³digos de status especÃÆ’ƒÂÂÂficos
|
// Tratar códigos de status específicos
|
||||||
if (response.status === 401) {
|
if (response.status === 401) {
|
||||||
errorMessage = "Email ou senha incorretos. Verifique suas credenciais.";
|
errorMessage = "Email ou senha incorretos. Verifique suas credenciais.";
|
||||||
} else if (response.status === 403) {
|
} else if (response.status === 403) {
|
||||||
errorMessage = "Acesso negado. Sua conta pode estar inativa.";
|
errorMessage = "Acesso negado. Sua conta pode estar inativa.";
|
||||||
} else if (response.status === 404) {
|
} else if (response.status === 404) {
|
||||||
errorMessage = "UsuÃÆ’ƒÂ¡rio nÃÆ’ƒÂ£o encontrado. Verifique o email informado.";
|
errorMessage = "Usuário não encontrado. Verifique o email informado.";
|
||||||
} else if (response.status >= 500) {
|
} else if (response.status >= 500) {
|
||||||
errorMessage = "Erro interno do servidor. Tente novamente em alguns minutos.";
|
errorMessage = "Erro interno do servidor. Tente novamente em alguns minutos.";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Aplicar traduÃÆ’ƒÂÂÂ§ÃÆ’ƒÂ£o se disponÃÆ’ƒÂÂÂvel
|
// Aplicar tradução se disponível
|
||||||
const translatedError = translateError(errorMessage);
|
const translatedError = translateError(errorMessage);
|
||||||
throw new Error(translatedError);
|
throw new Error(translatedError);
|
||||||
}
|
}
|
||||||
|
|
@ -158,24 +158,24 @@ const LoginPageContent = () => {
|
||||||
if (meResponse.ok) {
|
if (meResponse.ok) {
|
||||||
const userData = await meResponse.json();
|
const userData = await meResponse.json();
|
||||||
} else {
|
} else {
|
||||||
console.log("ÃÆ’¢ÂÂÂÃɉ۪ Falha no /me:", await meResponse.text());
|
console.log("¢Ãɉ۪ Falha no /me:", await meResponse.text());
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
throw new Error("Token nÃÆ’ƒÂ£o recebido do servidor");
|
throw new Error("Token não recebido do servidor");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. Armazenar informaÃÆ’ƒÂÂÂ§ÃÆ’ƒÂµes do usuÃÆ’ƒÂ¡rio no localStorage
|
// 4. Armazenar informaçµes do usuário no localStorage
|
||||||
if (loginData.user) {
|
if (loginData.user) {
|
||||||
localStorage.setItem('user', JSON.stringify(loginData.user));
|
localStorage.setItem('user', JSON.stringify(loginData.user));
|
||||||
|
|
||||||
// Verificar se o registro estÃÆ’ƒÂ¡ completo
|
// Verificar se o registro está completo
|
||||||
if (loginData.user["registro-completo"] === false) {
|
if (loginData.user["registro-completo"] === false) {
|
||||||
setShowPendingModal(true);
|
setShowPendingModal(true);
|
||||||
return; // NÃÆ’ƒÂ£o continuar com o redirecionamento
|
return; // Não continuar com o redirecionamento
|
||||||
}
|
}
|
||||||
|
|
||||||
// Armazenar ID do endereÃÆ’ƒÂ§o se disponÃÆ’ƒÂÂÂvel
|
// Armazenar ID do endereço se disponível
|
||||||
// Backend pode retornar "endereco" (singular) ou "enderecos" (plural array)
|
// Backend pode retornar "endereco" (singular) ou "enderecos" (plural array)
|
||||||
let enderecoId = loginData.user.endereco;
|
let enderecoId = loginData.user.endereco;
|
||||||
|
|
||||||
|
|
@ -189,7 +189,7 @@ const LoginPageContent = () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 5. Verificar e armazenar empresa ID se disponÃÆ’ƒÂÂÂvel
|
// 5. Verificar e armazenar empresa ID se disponível
|
||||||
if (loginData.user?.empresaId) {
|
if (loginData.user?.empresaId) {
|
||||||
setEmpresaId(loginData.user.empresaId);
|
setEmpresaId(loginData.user.empresaId);
|
||||||
}
|
}
|
||||||
|
|
@ -198,16 +198,16 @@ const LoginPageContent = () => {
|
||||||
router.push("/dashboard");
|
router.push("/dashboard");
|
||||||
|
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
console.error("ÃÆ’¢ÂÂÂÃɉ۪ Erro no login:", error);
|
console.error("¢Ãɉ۪ Erro no login:", error);
|
||||||
|
|
||||||
// Definir mensagem de erro amigÃÆ’ƒÂ¡vel
|
// Definir mensagem de erro amigável
|
||||||
let friendlyMessage = error.message;
|
let friendlyMessage = error.message;
|
||||||
|
|
||||||
// Se for um erro de rede
|
// Se for um erro de rede
|
||||||
if (error.name === 'TypeError' || error.message.includes('fetch')) {
|
if (error.name === 'TypeError' || error.message.includes('fetch')) {
|
||||||
friendlyMessage = "Erro de conexÃÆ’ƒÂ£o. Verifique sua internet e tente novamente.";
|
friendlyMessage = "Erro de conexão. Verifique sua internet e tente novamente.";
|
||||||
}
|
}
|
||||||
// Se for um erro genÃÆ’ƒÂ©rico sem mensagem clara
|
// Se for um erro genérico sem mensagem clara
|
||||||
else if (!error.message || error.message.length < 5) {
|
else if (!error.message || error.message.length < 5) {
|
||||||
friendlyMessage = "Erro inesperado. Verifique suas credenciais e tente novamente.";
|
friendlyMessage = "Erro inesperado. Verifique suas credenciais e tente novamente.";
|
||||||
}
|
}
|
||||||
|
|
@ -219,7 +219,7 @@ const LoginPageContent = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* FunÃÆ’ÂÂ§ÃÆ’£o para registrar novo usuÃÆ’¡rio usando API
|
* Função para registrar novo usuário usando API
|
||||||
* Cria conta e mostra mensagem de sucesso
|
* Cria conta e mostra mensagem de sucesso
|
||||||
*/
|
*/
|
||||||
const register = async () => {
|
const register = async () => {
|
||||||
|
|
@ -235,12 +235,12 @@ const LoginPageContent = () => {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
identificador: email, // identificador = email do usuÃÆ’ƒÂ¡rio (usado no login)
|
identificador: email, // identificador = email do usuário (usado no login)
|
||||||
email: email,
|
email: email,
|
||||||
nome: name, // nome = nome completo do usuÃÆ’ƒÂ¡rio
|
nome: name, // nome = nome completo do usuário
|
||||||
senha: password,
|
senha: password,
|
||||||
nivel: "owner", // valor estÃÆ’ƒÂ¡tico
|
nivel: "owner", // valor estático
|
||||||
"registro-completo": false // valor estÃÆ’ƒÂ¡tico - registro incompleto por padrÃÆ’ƒÂ£o
|
"registro-completo": false // valor estático - registro incompleto por padrão
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -248,25 +248,25 @@ const LoginPageContent = () => {
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
const errorData = await response.json().catch(() => ({}));
|
const errorData = await response.json().catch(() => ({}));
|
||||||
|
|
||||||
// Tratar cÃÆ’ƒÂ³digos de status especÃÆ’ƒÂÂÂficos
|
// Tratar códigos de status específicos
|
||||||
let errorMessage = errorData.message || 'Falha no registro';
|
let errorMessage = errorData.message || 'Falha no registro';
|
||||||
|
|
||||||
if (response.status === 409 || errorMessage.includes('already exists') || errorMessage.includes('jÃÆ’ƒÂ¡ existe')) {
|
if (response.status === 409 || errorMessage.includes('already exists') || errorMessage.includes('já existe')) {
|
||||||
errorMessage = 'Este email jÃÆ’ƒÂ¡ estÃÆ’ƒÂ¡ cadastrado. Tente fazer login ou use outro email.';
|
errorMessage = 'Este email já está cadastrado. Tente fazer login ou use outro email.';
|
||||||
} else if (response.status === 400) {
|
} else if (response.status === 400) {
|
||||||
errorMessage = 'Dados invÃÆ’ƒÂ¡lidos. Verifique se todos os campos estÃÆ’ƒÂ£o preenchidos corretamente.';
|
errorMessage = 'Dados inválidos. Verifique se todos os campos estão preenchidos corretamente.';
|
||||||
} else if (response.status >= 500) {
|
} else if (response.status >= 500) {
|
||||||
errorMessage = 'Erro interno do servidor. Tente novamente em alguns minutos.';
|
errorMessage = 'Erro interno do servidor. Tente novamente em alguns minutos.';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Aplicar traduÃÆ’ƒÂÂÂ§ÃÆ’ƒÂ£o se disponÃÆ’ƒÂÂÂvel
|
// Aplicar tradução se disponível
|
||||||
const translatedError = translateError(errorMessage);
|
const translatedError = translateError(errorMessage);
|
||||||
throw new Error(translatedError);
|
throw new Error(translatedError);
|
||||||
}
|
}
|
||||||
|
|
||||||
const registerData = await response.json();
|
const registerData = await response.json();
|
||||||
|
|
||||||
// 2. Fazer login automÃÆ’ƒÂ¡tico apÃÆ’ƒÂ³s registro para obter token
|
// 2. Fazer login automático após registro para obter token
|
||||||
const loginResponse = await fetch(`${baseUrl}/auth/login`, {
|
const loginResponse = await fetch(`${baseUrl}/auth/login`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
|
|
@ -282,13 +282,13 @@ const LoginPageContent = () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!loginResponse.ok) {
|
if (!loginResponse.ok) {
|
||||||
console.error("ÃÆ’¢ÂÂÂÃɉ۪ Erro no login automÃÆ’ƒÂ¡tico:", loginResponse.status);
|
console.error("¢Ãɉ۪ Erro no login automático:", loginResponse.status);
|
||||||
throw new Error('Erro ao fazer login automÃÆ’ƒÂ¡tico apÃÆ’ƒÂ³s registro');
|
throw new Error('Erro ao fazer login automático após registro');
|
||||||
}
|
}
|
||||||
|
|
||||||
const loginData = await loginResponse.json();
|
const loginData = await loginResponse.json();
|
||||||
|
|
||||||
// 3. Armazenar token e dados do usuÃÆ’ƒÂ¡rio
|
// 3. Armazenar token e dados do usuário
|
||||||
if (loginData.access_token) {
|
if (loginData.access_token) {
|
||||||
localStorage.setItem('access_token', loginData.access_token);
|
localStorage.setItem('access_token', loginData.access_token);
|
||||||
}
|
}
|
||||||
|
|
@ -297,20 +297,20 @@ const LoginPageContent = () => {
|
||||||
localStorage.setItem('user', JSON.stringify(loginData.user));
|
localStorage.setItem('user', JSON.stringify(loginData.user));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. Redirecionar para completar registro com token vÃÆ’ƒÂ¡lido
|
// 4. Redirecionar para completar registro com token válido
|
||||||
router.push(`/completar-registro?nome=${encodeURIComponent(name)}&email=${encodeURIComponent(email)}`);
|
router.push(`/completar-registro?nome=${encodeURIComponent(name)}&email=${encodeURIComponent(email)}`);
|
||||||
|
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
console.error("ÃÆ’¢ÂÂÂÃɉ۪ Erro no registro:", error);
|
console.error("¢Ãɉ۪ Erro no registro:", error);
|
||||||
|
|
||||||
// Definir mensagem de erro amigÃÆ’ƒÂ¡vel
|
// Definir mensagem de erro amigável
|
||||||
let friendlyMessage = error.message;
|
let friendlyMessage = error.message;
|
||||||
|
|
||||||
// Se for um erro de rede
|
// Se for um erro de rede
|
||||||
if (error.name === 'TypeError' || error.message.includes('fetch')) {
|
if (error.name === 'TypeError' || error.message.includes('fetch')) {
|
||||||
friendlyMessage = "Erro de conexÃÆ’ƒÂ£o. Verifique sua internet e tente novamente.";
|
friendlyMessage = "Erro de conexão. Verifique sua internet e tente novamente.";
|
||||||
}
|
}
|
||||||
// Se for um erro genÃÆ’ƒÂ©rico sem mensagem clara
|
// Se for um erro genérico sem mensagem clara
|
||||||
else if (!error.message || error.message.length < 5) {
|
else if (!error.message || error.message.length < 5) {
|
||||||
friendlyMessage = "Erro inesperado durante o cadastro. Tente novamente.";
|
friendlyMessage = "Erro inesperado durante o cadastro. Tente novamente.";
|
||||||
}
|
}
|
||||||
|
|
@ -322,11 +322,11 @@ const LoginPageContent = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* FunÃÆ’ƒÂÂÂ§ÃÆ’ƒÂ£o para notificar administrador sobre novo cadastro
|
* Função para notificar administrador sobre novo cadastro
|
||||||
*/
|
*/
|
||||||
const notifyAdmin = async (userData: { nome: string, email: string, identificador: string }) => {
|
const notifyAdmin = async (userData: { nome: string, email: string, identificador: string }) => {
|
||||||
try {
|
try {
|
||||||
// Enviar notificaÃÆ’ƒÂÂÂ§ÃÆ’ƒÂµes via API (usando Resend para emails reais)
|
// Enviar notificaçµes via API (usando Resend para emails reais)
|
||||||
await fetch('/api/notify-admin-resend', {
|
await fetch('/api/notify-admin-resend', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
|
|
@ -335,13 +335,13 @@ const LoginPageContent = () => {
|
||||||
body: JSON.stringify(userData)
|
body: JSON.stringify(userData)
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Erro ao enviar notificaÃÆ’ƒÂÂÂ§ÃÆ’ƒÂµes:", error);
|
console.error("Erro ao enviar notificaçµes:", error);
|
||||||
// NÃÆ’ƒÂ£o bloquear o cadastro por erro de notificaÃÆ’ƒÂÂÂ§ÃÆ’ƒÂ£o
|
// Não bloquear o cadastro por erro de notificação
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* FunÃÆ’ƒÂÂÂ§ÃÆ’ƒÂ£o para fechar modal de sucesso e redirecionar
|
* Função para fechar modal de sucesso e redirecionar
|
||||||
*/
|
*/
|
||||||
const handleSuccessModalClose = () => {
|
const handleSuccessModalClose = () => {
|
||||||
setShowSuccessModal(false);
|
setShowSuccessModal(false);
|
||||||
|
|
@ -349,25 +349,25 @@ const LoginPageContent = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* FunÃÆ’ƒÂÂÂ§ÃÆ’ƒÂ£o para fechar modal de cadastro pendente
|
* Função para fechar modal de cadastro pendente
|
||||||
*/
|
*/
|
||||||
const handlePendingModalClose = () => {
|
const handlePendingModalClose = () => {
|
||||||
setShowPendingModal(false);
|
setShowPendingModal(false);
|
||||||
// Fazer logout para limpar dados do usuÃÆ’ƒÂ¡rio
|
// Fazer logout para limpar dados do usuário
|
||||||
localStorage.removeItem('access_token');
|
localStorage.removeItem('access_token');
|
||||||
localStorage.removeItem('user');
|
localStorage.removeItem('user');
|
||||||
setAccessToken("");
|
setAccessToken("");
|
||||||
// Redirecionar para pÃÆ’ƒÂ¡gina inicial
|
// Redirecionar para página inicial
|
||||||
router.push('/');
|
router.push('/');
|
||||||
};
|
};
|
||||||
|
|
||||||
// Tela de carregamento durante verificaÃÆ’ƒÂÂÂ§ÃÆ’ƒÂ£o de autenticaÃÆ’ƒÂÂÂ§ÃÆ’ƒÂ£o
|
// Tela de carregamento durante verificação de autenticação
|
||||||
if (checkingAuth) {
|
if (checkingAuth) {
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-gray-50 flex items-center justify-center">
|
<div className="min-h-screen bg-gray-50 flex items-center justify-center">
|
||||||
<div className="text-center">
|
<div className="text-center">
|
||||||
<div className="w-16 h-16 border-4 border-blue-600 border-t-transparent rounded-full animate-spin mx-auto mb-4"></div>
|
<div className="w-16 h-16 border-4 border-blue-600 border-t-transparent rounded-full animate-spin mx-auto mb-4"></div>
|
||||||
<p className="text-gray-600">Verificando autenticaÃÆ’ƒÂÂÂ§ÃÆ’ƒÂ£o...</p>
|
<p className="text-gray-600">Verificando autenticação...</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
@ -376,7 +376,7 @@ const LoginPageContent = () => {
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-gray-50 flex items-center justify-center p-4">
|
<div className="min-h-screen bg-gray-50 flex items-center justify-center p-4">
|
||||||
<div className="bg-white rounded-2xl shadow-xl overflow-hidden w-full max-w-md">
|
<div className="bg-white rounded-2xl shadow-xl overflow-hidden w-full max-w-md">
|
||||||
{/* CabeÃÆ’ƒÂ§alho com logo e slogan */}
|
{/* Cabeçalho com logo e slogan */}
|
||||||
<div className="bg-gradient-to-r from-blue-600 to-blue-700 p-1 text-center">
|
<div className="bg-gradient-to-r from-blue-600 to-blue-700 p-1 text-center">
|
||||||
<div className="mx-auto -mb-2 flex items-center justify-center">
|
<div className="mx-auto -mb-2 flex items-center justify-center">
|
||||||
<Image
|
<Image
|
||||||
|
|
@ -392,9 +392,9 @@ const LoginPageContent = () => {
|
||||||
<p className="text-gray-300">Plataforma B2B de Medicamentos</p>
|
<p className="text-gray-300">Plataforma B2B de Medicamentos</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* FormulÃÆ’ƒÂ¡rio de login/registro */}
|
{/* Formulário de login/registro */}
|
||||||
<div className="p-6">
|
<div className="p-6">
|
||||||
{/* BotÃÆ’ƒÂµes de alternÃÆ’ƒÂ¢ncia entre Login e Cadastro */}
|
{/* Botµes de altern¢ncia entre Login e Cadastro */}
|
||||||
<div className="flex bg-gray-100 rounded-lg p-1 mb-6">
|
<div className="flex bg-gray-100 rounded-lg p-1 mb-6">
|
||||||
<button
|
<button
|
||||||
onClick={() => setIsLogin(true)}
|
onClick={() => setIsLogin(true)}
|
||||||
|
|
@ -464,7 +464,7 @@ const LoginPageContent = () => {
|
||||||
</div>
|
</div>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="JoÃÆ’ƒÂ£o Silva"
|
placeholder="João Silva"
|
||||||
value={name}
|
value={name}
|
||||||
onChange={(e) => setName(e.target.value)}
|
onChange={(e) => setName(e.target.value)}
|
||||||
className="w-full pl-10 pr-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-colors text-gray-900 placeholder-gray-500"
|
className="w-full pl-10 pr-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-colors text-gray-900 placeholder-gray-500"
|
||||||
|
|
@ -527,7 +527,7 @@ const LoginPageContent = () => {
|
||||||
</div>
|
</div>
|
||||||
<input
|
<input
|
||||||
type={showPassword ? "text" : "password"}
|
type={showPassword ? "text" : "password"}
|
||||||
placeholder="ÃÆ’¢â‚¬ÂÂÂ¢ÃÆ’¢â‚¬ÂÂÂ¢ÃÆ’¢â‚¬ÂÂÂ¢ÃÆ’¢â‚¬ÂÂÂ¢ÃÆ’¢â‚¬ÂÂÂ¢ÃÆ’¢â‚¬ÂÂÂ¢ÃÆ’¢â‚¬ÂÂÂ¢ÃÆ’¢â‚¬Â¢"
|
placeholder="¢â‚¬¢Â¢Ã¢â€šÂ¬¢Â¢Ã¢â€šÂ¬¢Â¢Ã¢â€šÂ¬¢Â¢Ã¢â€šÂ¬¢Â¢Ã¢â€šÂ¬¢Â¢Ã¢â€šÂ¬¢Â¢Ã¢â€šÂ¬¢"
|
||||||
value={password}
|
value={password}
|
||||||
onChange={(e) => setPassword(e.target.value)}
|
onChange={(e) => setPassword(e.target.value)}
|
||||||
className="w-full pl-10 pr-12 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-colors text-gray-900 placeholder-gray-500"
|
className="w-full pl-10 pr-12 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-colors text-gray-900 placeholder-gray-500"
|
||||||
|
|
@ -576,7 +576,7 @@ const LoginPageContent = () => {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* BotÃÆ’ƒÂµes de Submit */}
|
{/* Botµes de Submit */}
|
||||||
<div className="space-y-3 pt-2">
|
<div className="space-y-3 pt-2">
|
||||||
{isLogin ? (
|
{isLogin ? (
|
||||||
<button
|
<button
|
||||||
|
|
@ -708,18 +708,18 @@ const LoginPageContent = () => {
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* ConteÃÆ’ƒÂºdo do Modal */}
|
{/* Conteúdo do Modal */}
|
||||||
<div className="p-6 text-center">
|
<div className="p-6 text-center">
|
||||||
<div className="mb-6">
|
<div className="mb-6">
|
||||||
<p className="text-gray-700 text-lg leading-relaxed">
|
<p className="text-gray-700 text-lg leading-relaxed">
|
||||||
Seu cadastro foi enviado com <strong>sucesso</strong>!
|
Seu cadastro foi enviado com <strong>sucesso</strong>!
|
||||||
</p>
|
</p>
|
||||||
<p className="text-gray-600 mt-3">
|
<p className="text-gray-600 mt-3">
|
||||||
Nossa equipe entrarÃÆ’ƒÂ¡ em contato em breve para finalizar seu acesso ÃÆ’ƒÂ plataforma.
|
Nossa equipe entrará em contato em breve para finalizar seu acesso plataforma.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* ÃÆ’ƒÂÂÂcone decorativo */}
|
{/* cone decorativo */}
|
||||||
<div className="flex justify-center mb-6">
|
<div className="flex justify-center mb-6">
|
||||||
<div className="flex space-x-2">
|
<div className="flex space-x-2">
|
||||||
<div className="w-3 h-3 bg-green-500 rounded-full animate-pulse"></div>
|
<div className="w-3 h-3 bg-green-500 rounded-full animate-pulse"></div>
|
||||||
|
|
@ -728,7 +728,7 @@ const LoginPageContent = () => {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* BotÃÆ’ƒÂ£o de OK */}
|
{/* Botão de OK */}
|
||||||
<button
|
<button
|
||||||
onClick={handleSuccessModalClose}
|
onClick={handleSuccessModalClose}
|
||||||
className="w-full bg-gradient-to-r from-green-500 to-green-600 hover:from-green-600 hover:to-green-700 text-white font-semibold py-4 px-6 rounded-xl transition-all duration-200 transform hover:scale-105 focus:outline-none focus:ring-4 focus:ring-green-200"
|
className="w-full bg-gradient-to-r from-green-500 to-green-600 hover:from-green-600 hover:to-green-700 text-white font-semibold py-4 px-6 rounded-xl transition-all duration-200 transform hover:scale-105 focus:outline-none focus:ring-4 focus:ring-green-200"
|
||||||
|
|
@ -766,21 +766,21 @@ const LoginPageContent = () => {
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* ConteÃÆ’ƒÂºdo do Modal */}
|
{/* Conteúdo do Modal */}
|
||||||
<div className="p-6 text-center">
|
<div className="p-6 text-center">
|
||||||
<div className="mb-6">
|
<div className="mb-6">
|
||||||
<p className="text-gray-700 text-lg leading-relaxed">
|
<p className="text-gray-700 text-lg leading-relaxed">
|
||||||
Seu cadastro estÃÆ’ƒÂ¡ <strong>pendente de validaÃÆ’ƒÂÂÂ§ÃÆ’ƒÂ£o</strong>!
|
Seu cadastro está <strong>pendente de validação</strong>!
|
||||||
</p>
|
</p>
|
||||||
<p className="text-gray-600 mt-3">
|
<p className="text-gray-600 mt-3">
|
||||||
Nossa equipe ainda estÃÆ’ƒÂ¡ analisando suas informaÃÆ’ƒÂÂÂ§ÃÆ’ƒÂµes. VocÃÆ’ƒÂª receberÃÆ’ƒÂ¡ uma confirmaÃÆ’ƒÂÂÂ§ÃÆ’ƒÂ£o em breve.
|
Nossa equipe ainda está analisando suas informaçµes. Você receberá uma confirmação em breve.
|
||||||
</p>
|
</p>
|
||||||
<p className="text-gray-600 mt-3">
|
<p className="text-gray-600 mt-3">
|
||||||
Qualquer dÃÆ’ƒÂºvida, entre em contato conosco.
|
Qualquer dúvida, entre em contato conosco.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* ÃÆ’ƒÂÂÂcone decorativo */}
|
{/* cone decorativo */}
|
||||||
<div className="flex justify-center mb-6">
|
<div className="flex justify-center mb-6">
|
||||||
<div className="flex space-x-2">
|
<div className="flex space-x-2">
|
||||||
<div className="w-3 h-3 bg-yellow-500 rounded-full animate-pulse"></div>
|
<div className="w-3 h-3 bg-yellow-500 rounded-full animate-pulse"></div>
|
||||||
|
|
@ -789,7 +789,7 @@ const LoginPageContent = () => {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* BotÃÆ’ƒÂ£o de OK */}
|
{/* Botão de OK */}
|
||||||
<button
|
<button
|
||||||
onClick={handlePendingModalClose}
|
onClick={handlePendingModalClose}
|
||||||
className="w-full bg-gradient-to-r from-yellow-500 to-orange-500 hover:from-yellow-600 hover:to-orange-600 text-white font-semibold py-4 px-6 rounded-xl transition-all duration-200 transform hover:scale-105 focus:outline-none focus:ring-4 focus:ring-yellow-200"
|
className="w-full bg-gradient-to-r from-yellow-500 to-orange-500 hover:from-yellow-600 hover:to-orange-600 text-white font-semibold py-4 px-6 rounded-xl transition-all duration-200 transform hover:scale-105 focus:outline-none focus:ring-4 focus:ring-yellow-200"
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue