mockup da tela de mudança de senha
This commit is contained in:
parent
d984a5311f
commit
66a2aa41ad
|
|
@ -1,218 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="pt-BR">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>MVP - Minha Conta</title>
|
||||
<style>
|
||||
body { font-family: Arial, Helvetica, sans-serif; background-color: #f4f4f9; color: #333; margin: 0; padding: 20px; display: flex; justify-content: center; align-items: center; flex-direction: column; }
|
||||
.container { background-color: #ffffff; padding: 30px; border-radius: 8px; box-shadow: 0 4px 8px rgba(0,0,0,0.1); max-width: 500px; width: 100%; margin-top: 20px;}
|
||||
h1 { color: #2c3e50; text-align: center; border-bottom: 2px solid #ecf0f1; padding-bottom: 10px; margin-bottom: 30px; }
|
||||
.form-group { margin-bottom: 20px; }
|
||||
label { display: block; margin-bottom: 8px; font-weight: bold; color: #555; }
|
||||
input[type="email"], input[type="password"] {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
button {
|
||||
width: 100%;
|
||||
padding: 12px;
|
||||
background-color: #3498db; /* Cor principal azul */
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
margin-top: 20px;
|
||||
position: relative;
|
||||
transition: background-color 0.3s;
|
||||
overflow: hidden; /* Garante que os elementos internos não ultrapassem as bordas arredondadas */
|
||||
}
|
||||
button:hover:not(:disabled) { background-color: #2980b9; }
|
||||
button:disabled { cursor: wait; }
|
||||
|
||||
/* Estilos para o preview da imagem */
|
||||
.photo-upload-container { text-align: center; margin-bottom: 30px; }
|
||||
#image_preview {
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
border: 3px solid #ecf0f1;
|
||||
border-radius: 50%;
|
||||
object-fit: cover;
|
||||
cursor: pointer;
|
||||
transition: transform 0.2s;
|
||||
}
|
||||
#image_preview:hover { transform: scale(1.05); }
|
||||
#profile_image_input { display: none; }
|
||||
|
||||
/* Estilos para os estados do botão */
|
||||
.button-content { display: flex; justify-content: center; align-items: center; }
|
||||
.button-text, .button-loader, .button-success-icon { transition: opacity 0.3s ease-in-out, transform 0.3s ease-in-out; }
|
||||
|
||||
.button-loader {
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border: 2px solid rgba(255, 255, 255, 0.5);
|
||||
border-top-color: #ffffff;
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
.button-success-icon {
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
font-size: 24px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
button.sending { background-color: #95a5a6; }
|
||||
button.sending .button-text { opacity: 0; transform: translateY(-10px); }
|
||||
button.sending .button-loader { opacity: 1; }
|
||||
|
||||
button.success { background-color: #27ae60; }
|
||||
button.success .button-loader { opacity: 0; }
|
||||
button.success .button-success-icon { opacity: 1; transform: scale(1.2); }
|
||||
|
||||
@keyframes spin {
|
||||
to { transform: rotate(360deg); }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<form id="profile-form">
|
||||
<h1>Minha Conta</h1>
|
||||
|
||||
<div class="form-group photo-upload-container">
|
||||
<img id="image_preview" src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='150' height='150' viewBox='0 0 24 24' fill='%23f0f0f1' stroke='%23ccc' stroke-width='1' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2'%3E%3C/path%3E%3Ccircle cx='12' cy='7' r='4'%3E%3C/circle%3E%3C/svg%3E" alt="Preview da foto de perfil" title="Clique para selecionar uma nova foto de perfil">
|
||||
<input type="file" id="profile_image_input" name="ImagePath" accept="image/png, image/jpeg">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="user_email">E-mail</label>
|
||||
<input type="email" id="user_email" name="UserEmail" placeholder="seu.usuario@dominio.com" required title="Seu e-mail de login. Não pode ser alterado.">
|
||||
</div>
|
||||
|
||||
<hr style="border: 1px solid #f0f0f0; margin: 30px 0;">
|
||||
|
||||
<div class="form-group">
|
||||
<label for="old_password">Senha Atual</label>
|
||||
<input type="password" id="old_password" name="OldPassword" placeholder="Necessária para salvar" required title="Sua senha atual é necessária para confirmar qualquer alteração.">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="new_password">Nova Senha</label>
|
||||
<input type="password" id="new_password" name="NewPassword" placeholder="Deixe em branco para não alterar" title="Insira sua nova senha. Mínimo de 8 caracteres.">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="confirm_password">Confirmar Nova Senha</label>
|
||||
<input type="password" id="confirm_password" name="ConfirmNewPassword" placeholder="Repita a nova senha" title="As senhas devem ser idênticas.">
|
||||
</div>
|
||||
|
||||
<button type="submit" id="submit-button">
|
||||
<span class="button-content">
|
||||
<span class="button-text">Salvar Alterações</span>
|
||||
<span class="button-loader"></span>
|
||||
<span class="button-success-icon">✓</span>
|
||||
</span>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const profileForm = document.getElementById('profile-form');
|
||||
const imagePreview = document.getElementById('image_preview');
|
||||
const imageInput = document.getElementById('profile_image_input');
|
||||
const submitButton = document.getElementById('submit-button');
|
||||
// A constante agora guarda o SVG embutido para poder restaurá-lo após o refresh.
|
||||
const placeholderImage = "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='150' height='150' viewBox='0 0 24 24' fill='%23f0f0f1' stroke='%23ccc' stroke-width='1' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2'%3E%3C/path%3E%3Ccircle cx='12' cy='7' r='4'%3E%3C/circle%3E%3C/svg%3E";
|
||||
|
||||
// --- Lógica para o Preview da Imagem ---
|
||||
imagePreview.addEventListener('click', () => imageInput.click());
|
||||
|
||||
imageInput.addEventListener('change', (event) => {
|
||||
const file = event.target.files[0];
|
||||
if (file) {
|
||||
const reader = new FileReader();
|
||||
reader.onload = (e) => { imagePreview.src = e.target.result; };
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
});
|
||||
|
||||
// --- Lógica Unificada de Submissão do Formulário ---
|
||||
profileForm.addEventListener('submit', (event) => {
|
||||
event.preventDefault();
|
||||
|
||||
// Coleta de dados
|
||||
const email = document.getElementById('user_email').value;
|
||||
const oldPassword = document.getElementById('old_password').value;
|
||||
const newPassword = document.getElementById('new_password').value;
|
||||
const confirmPassword = document.getElementById('confirm_password').value;
|
||||
const fileSelected = imageInput.files.length > 0;
|
||||
|
||||
// Validações
|
||||
if (!email || !oldPassword) {
|
||||
console.warn('VALIDAÇÃO FALHOU: E-mail e Senha Atual são obrigatórios.');
|
||||
return;
|
||||
}
|
||||
if (newPassword && newPassword !== confirmPassword) {
|
||||
console.warn('VALIDAÇÃO FALHOU: A nova senha e a confirmação não são idênticas.');
|
||||
return;
|
||||
}
|
||||
if (!fileSelected && !newPassword) {
|
||||
console.info('INFO: Nenhuma alteração detectada (foto ou senha). O envio foi cancelado.');
|
||||
return;
|
||||
}
|
||||
|
||||
// 1. Inicia a animação de envio
|
||||
submitButton.classList.add('sending');
|
||||
submitButton.disabled = true;
|
||||
console.log(`%c[${new Date().toLocaleTimeString()}] INICIANDO ENVIO...`, 'color: #3498db; font-weight: bold;');
|
||||
|
||||
// 2. Simula um delay de rede de 2 segundos
|
||||
setTimeout(() => {
|
||||
// Log de simulação no console
|
||||
const samAccountName = email.split('@')[0];
|
||||
let actions = [];
|
||||
if (fileSelected) actions.push({ action: "Atualização de Foto de Perfil", file: imageInput.files[0].name, script: "muda-imagem-perfil.ps1" });
|
||||
if (newPassword) actions.push({ action: "Alteração de Senha", validation: "SUCESSO (simulado)", script: "muda-senha-usuario.ps1" });
|
||||
|
||||
console.group(`%c[${new Date().toLocaleTimeString()}] RESPOSTA DA SIMULAÇÃO DE BACKEND`, 'color: #27ae60; font-weight: bold;');
|
||||
console.log("DESTINO: API de Atualização de Perfil");
|
||||
console.log("USUÁRIO:", samAccountName);
|
||||
console.log("AÇÕES EXECUTADAS:");
|
||||
console.table(actions);
|
||||
console.groupEnd();
|
||||
|
||||
// 3. Transição para o estado de "sucesso"
|
||||
submitButton.classList.remove('sending');
|
||||
submitButton.classList.add('success');
|
||||
|
||||
// 4. Aguarda 1.5s no estado de "sucesso" e depois faz o refresh
|
||||
setTimeout(() => {
|
||||
submitButton.classList.remove('success');
|
||||
submitButton.disabled = false;
|
||||
|
||||
// Limpa os campos do formulário (refresh)
|
||||
document.getElementById('new_password').value = '';
|
||||
document.getElementById('confirm_password').value = '';
|
||||
document.getElementById('old_password').value = '';
|
||||
imageInput.value = ''; // Limpa a seleção do arquivo
|
||||
imagePreview.src = placeholderImage; // Restaura a imagem padrão
|
||||
|
||||
console.log(`%c[${new Date().toLocaleTimeString()}] INTERFACE ATUALIZADA E PRONTA.`, 'color: #9b59b6;');
|
||||
}, 1500);
|
||||
|
||||
}, 2000);
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,288 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="pt-BR">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>MVP - Minha Conta</title>
|
||||
|
||||
<link href="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.12/cropper.min.css" rel="stylesheet">
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.12/cropper.min.js"></script>
|
||||
|
||||
<style>
|
||||
/* Estilos gerais */
|
||||
body { font-family: Arial, Helvetica, sans-serif; background-color: #f4f4f9; color: #333; margin: 0; padding: 20px; display: flex; justify-content: center; align-items: center; flex-direction: column; }
|
||||
.container { background-color: #ffffff; padding: 30px; border-radius: 8px; box-shadow: 0 4px 8px rgba(0,0,0,0.1); max-width: 500px; width: 100%; margin-top: 20px;}
|
||||
h1 { color: #2c3e50; text-align: center; border-bottom: 2px solid #ecf0f1; padding-bottom: 10px; margin-bottom: 30px; }
|
||||
.form-group { margin-bottom: 20px; position: relative; }
|
||||
label { display: block; margin-bottom: 8px; font-weight: bold; color: #555; }
|
||||
input[type="email"], input[type="password"], input[type="text"] { width: 100%; padding: 10px; border: 1px solid #ccc; border-radius: 4px; box-sizing: border-box; transition: border-color 0.3s; }
|
||||
input.error { border-color: #e74c3c; } /* Estilo para erro de validação */
|
||||
button { width: 100%; padding: 12px; background-color: #3498db; color: white; border: none; border-radius: 4px; cursor: pointer; font-size: 16px; font-weight: bold; margin-top: 20px; position: relative; transition: background-color 0.2s, transform 0.15s, box-shadow 0.15s; overflow: hidden; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
|
||||
button:hover:not(:disabled) { background-color: #2980b9; transform: translateY(-2px); box-shadow: 0 4px 8px rgba(0,0,0,0.15); }
|
||||
button:active:not(:disabled) { transform: translateY(1px); box-shadow: 0 1px 2px rgba(0,0,0,0.1); }
|
||||
button:disabled { cursor: wait; }
|
||||
.photo-upload-container { text-align: center; margin-bottom: 30px; }
|
||||
#image_preview { width: 150px; height: 150px; border: 3px solid #ecf0f1; border-radius: 50%; object-fit: cover; cursor: pointer; transition: transform 0.2s, filter 0.2s; }
|
||||
#image_preview:hover { transform: scale(1.05); } #image_preview:active { transform: scale(1.02); filter: brightness(0.9); }
|
||||
#profile_image_input { display: none; }
|
||||
.button-content { display: flex; justify-content: center; align-items: center; } .button-text, .button-loader, .button-success-icon { transition: opacity 0.3s ease-in-out, transform 0.3s ease-in-out; }
|
||||
.button-loader { position: absolute; opacity: 0; width: 20px; height: 20px; border: 2px solid rgba(255, 255, 255, 0.5); border-top-color: #ffffff; border-radius: 50%; animation: spin 1s linear infinite; }
|
||||
.button-success-icon { position: absolute; opacity: 0; font-size: 24px; line-height: 1; }
|
||||
button.sending { background-color: #95a5a6; } button.sending .button-text { opacity: 0; transform: translateY(-10px); } button.sending .button-loader { opacity: 1; }
|
||||
button.success { background-color: #27ae60; } button.success .button-loader { opacity: 0; }
|
||||
button.success .button-text { opacity: 0; }
|
||||
button.success .button-success-icon { opacity: 1; transform: scale(1.2); }
|
||||
@keyframes spin { to { transform: rotate(360deg); } }
|
||||
.modal-overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.6); display: none; justify-content: center; align-items: center; z-index: 1000; }
|
||||
.modal-content { background: #fff; padding: 20px; border-radius: 8px; width: 90%; max-width: 500px; }
|
||||
.modal-cropper-container { height: 300px; margin-bottom: 15px; }
|
||||
.modal-controls { display: flex; justify-content: center; align-items: center; gap: 15px; margin-bottom: 15px; }
|
||||
.modal-actions { display: flex; justify-content: flex-end; gap: 10px; }
|
||||
.modal-btn { padding: 8px 16px; border-radius: 4px; border: 1px solid #ccc; cursor: pointer; }
|
||||
.btn-confirm { background-color: #27ae60; color: white; border-color: #27ae60; }
|
||||
#zoom-slider { width: 60%; }
|
||||
.password-toggle { position: absolute; top: 38px; right: 10px; cursor: pointer; width: 20px; height: 20px; }
|
||||
.password-toggle svg { width:100%; height:100%; fill: none; stroke: #aaa; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
|
||||
.strength-meter { height: 5px; background: #eee; border-radius: 5px; margin-top: 5px; }
|
||||
.strength-meter-fill { height: 100%; width: 0; border-radius: 5px; transition: width 0.3s, background-color 0.3s; }
|
||||
.strength-text { font-size: 0.8em; text-align: right; margin-top: 2px; height: 1em; }
|
||||
.error-message { color: #e74c3c; font-size: 0.85em; margin-top: 8px; min-height: 1.2em; display: none; opacity: 0; transition: opacity 0.3s ease-in-out; }
|
||||
.error-message.visible { display: block; opacity: 1; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<form id="profile-form">
|
||||
<h1>Minha Conta</h1>
|
||||
<div class="form-group photo-upload-container">
|
||||
<img id="image_preview" src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='150' height='150' viewBox='0 0 24 24' fill='%23f0f0f1' stroke='%23ccc' stroke-width='1' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='8' r='4'%3E%3C/circle%3E%3Cpath d='M19 20v-1a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v1'%3E%3C/path%3E%3C/svg%3E" alt="Preview da foto de perfil" title="Clique para selecionar uma nova foto de perfil">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="user_email">E-mail</label>
|
||||
<input type="email" id="user_email" name="UserEmail" placeholder="seu.usuario@dominio.com" required title="Seu e-mail de login. Não pode ser alterado.">
|
||||
</div>
|
||||
<hr style="border: 1px solid #f0f0f0; margin: 30px 0;">
|
||||
<div class="form-group">
|
||||
<label for="old_password">Senha Atual</label>
|
||||
<input type="password" id="old_password" name="OldPassword" placeholder="Necessária para salvar" required title="Sua senha atual é necessária para confirmar qualquer alteração.">
|
||||
<span class="password-toggle" title="Exibir/Ocultar Senha">
|
||||
<svg class="eye-visible" style="display:none;" viewBox="0 0 24 24"><path d="M1,12 C1,12 5,4 12,4 C19,4 23,12 23,12 C23,12 19,20 12,20 C5,20 1,12 1,12 Z"></path><circle cx="12" cy="12" r="3"></circle></svg>
|
||||
<svg class="eye-hidden" viewBox="0 0 24 24"><path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24"></path><line x1="1" y1="1" x2="23" y2="23"></line></svg>
|
||||
</span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="new_password">Nova Senha</label>
|
||||
<input type="password" id="new_password" name="NewPassword" placeholder="Deixe em branco para não alterar" title="Insira sua nova senha. Mínimo de 8 caracteres.">
|
||||
<span class="password-toggle" title="Exibir/Ocultar Senha">
|
||||
<svg class="eye-visible" style="display:none;" viewBox="0 0 24 24"><path d="M1,12 C1,12 5,4 12,4 C19,4 23,12 23,12 C23,12 19,20 12,20 C5,20 1,12 1,12 Z"></path><circle cx="12" cy="12" r="3"></circle></svg>
|
||||
<svg class="eye-hidden" viewBox="0 0 24 24"><path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24"></path><line x1="1" y1="1" x2="23" y2="23"></line></svg>
|
||||
</span>
|
||||
<div id="password-error-message" class="error-message"></div>
|
||||
<div class="strength-meter"><div id="strength-fill" class="strength-meter-fill"></div></div>
|
||||
<div id="strength-text" class="strength-text"></div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="confirm_password">Confirmar Nova Senha</label>
|
||||
<input type="password" id="confirm_password" name="ConfirmNewPassword" placeholder="Repita a nova senha" title="As senhas devem ser idênticas.">
|
||||
<span class="password-toggle" title="Exibir/Ocultar Senha">
|
||||
<svg class="eye-visible" style="display:none;" viewBox="0 0 24 24"><path d="M1,12 C1,12 5,4 12,4 C19,4 23,12 23,12 C23,12 19,20 12,20 C5,20 1,12 1,12 Z"></path><circle cx="12" cy="12" r="3"></circle></svg>
|
||||
<svg class="eye-hidden" viewBox="0 0 24 24"><path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24"></path><line x1="1" y1="1" x2="23" y2="23"></line></svg>
|
||||
</span>
|
||||
</div>
|
||||
<button type="submit" id="submit-button">
|
||||
<span class="button-content">
|
||||
<span class="button-text">Salvar Alterações</span>
|
||||
<span class="button-loader"></span>
|
||||
<span class="button-success-icon">✓</span>
|
||||
</span>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div id="modal" class="modal-overlay"><div class="modal-content"><h3>Editar Foto de Perfil</h3><div class="modal-cropper-container"><img id="image_to_crop"></div><div class="modal-controls"><span>Zoom</span><input type="range" id="zoom-slider"></div><div class="modal-actions"><button type="button" id="cancel-crop" class="modal-btn">Cancelar</button><button type="button" id="confirm-crop" class="modal-btn btn-confirm">Confirmar</button></div></div></div>
|
||||
<input type="file" id="profile_image_input" accept="image/png, image/jpeg" style="display: none;">
|
||||
|
||||
<script>
|
||||
const profileForm = document.getElementById('profile-form');
|
||||
const imagePreview = document.getElementById('image_preview');
|
||||
const imageInput = document.getElementById('profile_image_input');
|
||||
const submitButton = document.getElementById('submit-button');
|
||||
const placeholderImage = imagePreview.src;
|
||||
let croppedImageData = null;
|
||||
const modal = document.getElementById('modal');
|
||||
const imageToCrop = document.getElementById('image_to_crop');
|
||||
const zoomSlider = document.getElementById('zoom-slider');
|
||||
let cropper, minZoomRatio;
|
||||
|
||||
imagePreview.addEventListener('click', () => imageInput.click());
|
||||
imageInput.addEventListener('change', (e) => {
|
||||
if (e.target.files && e.target.files[0]) {
|
||||
const reader = new FileReader();
|
||||
reader.onload = (e) => {
|
||||
imageToCrop.src = e.target.result;
|
||||
modal.style.display = 'flex';
|
||||
if(cropper) cropper.destroy();
|
||||
cropper = new Cropper(imageToCrop, {
|
||||
aspectRatio: 1,
|
||||
viewMode: 1,
|
||||
dragMode: 'move', // Permite mover a imagem de fundo
|
||||
autoCropArea: 1,
|
||||
cropBoxMovable: false, // Trava a caixa de seleção
|
||||
cropBoxResizable: false, // Impede o redimensionamento da caixa
|
||||
background: false,
|
||||
ready: function() {
|
||||
const canvasData = cropper.getCanvasData(); minZoomRatio = canvasData.width / canvasData.naturalWidth;
|
||||
zoomSlider.min = minZoomRatio; zoomSlider.max = minZoomRatio * 3; zoomSlider.step = (zoomSlider.max - zoomSlider.min) / 100;
|
||||
zoomSlider.value = minZoomRatio; cropper.zoomTo(minZoomRatio);
|
||||
}
|
||||
});
|
||||
};
|
||||
reader.readAsDataURL(e.target.files[0]);
|
||||
}
|
||||
});
|
||||
|
||||
zoomSlider.addEventListener('input', (e) => cropper.zoomTo(e.target.value));
|
||||
document.getElementById('cancel-crop').addEventListener('click', () => { modal.style.display = 'none'; imageInput.value = ''; });
|
||||
document.getElementById('confirm-crop').addEventListener('click', () => {
|
||||
const canvas = cropper.getCroppedCanvas({ width: 256, height: 256 });
|
||||
imagePreview.src = canvas.toDataURL('image/jpeg');
|
||||
canvas.toBlob(blob => { croppedImageData = blob; }, 'image/jpeg');
|
||||
modal.style.display = 'none';
|
||||
});
|
||||
|
||||
document.querySelectorAll('.password-toggle').forEach(toggle => {
|
||||
toggle.addEventListener('click', () => {
|
||||
const passwordField = toggle.previousElementSibling;
|
||||
const eyeVisible = toggle.querySelector('.eye-visible');
|
||||
const eyeHidden = toggle.querySelector('.eye-hidden');
|
||||
if (passwordField.type === 'password') {
|
||||
passwordField.type = 'text';
|
||||
eyeVisible.style.display = 'block';
|
||||
eyeHidden.style.display = 'none';
|
||||
} else {
|
||||
passwordField.type = 'password';
|
||||
eyeVisible.style.display = 'none';
|
||||
eyeHidden.style.display = 'block';
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
const newPasswordInput = document.getElementById('new_password');
|
||||
const confirmPasswordInput = document.getElementById('confirm_password');
|
||||
const strengthFill = document.getElementById('strength-fill');
|
||||
const strengthText = document.getElementById('strength-text');
|
||||
const passwordErrorMessage = document.getElementById('password-error-message');
|
||||
|
||||
newPasswordInput.addEventListener('input', () => {
|
||||
newPasswordInput.classList.remove('error');
|
||||
passwordErrorMessage.classList.remove('visible');
|
||||
confirmPasswordInput.value = '';
|
||||
|
||||
const pass = newPasswordInput.value; let score = 0; let text = ''; let color = '';
|
||||
if (pass.length < 8) { score = 0; text = pass.length > 0 ? 'Muito Fraca' : ''; color = '#e74c3c'; }
|
||||
else {
|
||||
score = 1; if (/[a-z]/.test(pass) && /[A-Z]/.test(pass)) score++; if (/\d]/.test(pass)) score++; if (/[!@#$%*]/.test(pass)) score++;
|
||||
switch(score) {
|
||||
case 1: text = 'Fraca'; color = '#e74c3c'; break;
|
||||
case 2: text = 'Média'; color = '#f39c12'; break;
|
||||
case 3: text = 'Forte'; color = '#2ecc71'; break;
|
||||
case 4: text = 'Muito Forte'; color = '#27ae60'; break;
|
||||
}
|
||||
}
|
||||
strengthFill.style.width = (score / 4) * 100 + '%'; strengthFill.style.backgroundColor = color; strengthText.textContent = text;
|
||||
});
|
||||
|
||||
const mockCheckPwnedPassword = (password) => {
|
||||
return new Promise(resolve => {
|
||||
console.log(`%c[${new Date().toLocaleTimeString()}] VERIFICANDO SENHA EM BANCO DE DADOS DE VAZAMENTOS...`, 'color: #f39c12;');
|
||||
setTimeout(() => {
|
||||
const pwnedPasswords = ['123mudar', 'senha@123'];
|
||||
if (pwnedPasswords.includes(password.toLowerCase())) {
|
||||
resolve({ pwned: true, count: Math.floor(Math.random() * (10000 - 500) + 500) });
|
||||
} else {
|
||||
resolve({ pwned: false });
|
||||
}
|
||||
}, 1500);
|
||||
});
|
||||
};
|
||||
|
||||
const handlePasswordError = (message) => {
|
||||
console.error(`VALIDAÇÃO FALHOU: ${message}`);
|
||||
newPasswordInput.classList.add('error');
|
||||
passwordErrorMessage.textContent = message;
|
||||
passwordErrorMessage.classList.add('visible');
|
||||
newPasswordInput.value = '';
|
||||
confirmPasswordInput.value = '';
|
||||
strengthFill.style.width = '0';
|
||||
strengthText.textContent = '';
|
||||
submitButton.classList.remove('sending');
|
||||
submitButton.disabled = false;
|
||||
};
|
||||
|
||||
profileForm.addEventListener('submit', async (event) => {
|
||||
event.preventDefault();
|
||||
|
||||
newPasswordInput.classList.remove('error');
|
||||
passwordErrorMessage.classList.remove('visible');
|
||||
|
||||
const email = document.getElementById('user_email').value;
|
||||
const oldPassword = document.getElementById('old_password').value;
|
||||
const newPassword = newPasswordInput.value;
|
||||
const confirmPassword = confirmPasswordInput.value;
|
||||
const fileSelected = croppedImageData !== null;
|
||||
|
||||
if (!email || !oldPassword) { console.warn('VALIDAÇÃO FALHOU: E-mail e Senha Atual são obrigatórios.'); return; }
|
||||
if (!fileSelected && !newPassword) { console.info('INFO: Nenhuma alteração detectada (foto ou senha). O envio foi cancelado.'); return; }
|
||||
|
||||
if (newPassword) {
|
||||
if (newPassword !== confirmPassword) {
|
||||
handlePasswordError("A nova senha e a confirmação não são idênticas.");
|
||||
return;
|
||||
}
|
||||
if (newPassword === oldPassword) {
|
||||
handlePasswordError("A nova senha não pode ser igual à senha atual.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
submitButton.classList.add('sending'); submitButton.disabled = true;
|
||||
|
||||
if (newPassword) {
|
||||
const pwnedResult = await mockCheckPwnedPassword(newPassword);
|
||||
if (pwnedResult.pwned) {
|
||||
handlePasswordError(`Esta senha é insegura, pois foi encontrada em ${pwnedResult.count.toLocaleString('pt-BR')} vazamentos de dados. Por favor, escolha outra.`);
|
||||
return;
|
||||
}
|
||||
console.info(`[SUCESSO] Verificação de segurança concluída. A senha não foi encontrada em vazamentos de dados conhecidos.`);
|
||||
}
|
||||
|
||||
console.log(`%c[${new Date().toLocaleTimeString()}] INICIANDO ENVIO PARA O BACKEND...`, 'color: #3498db; font-weight: bold;');
|
||||
|
||||
setTimeout(() => {
|
||||
const samAccountName = email.split('@')[0];
|
||||
let actions = [];
|
||||
if (fileSelected) actions.push({ action: "Atualização de Foto de Perfil", file: `cropped_image.jpeg (${Math.round(croppedImageData.size / 1024)} KB)`, script: "muda-imagem-perfil.ps1" });
|
||||
if (newPassword) actions.push({ action: "Alteração de Senha", validation: "SUCESSO (simulado)", script: "muda-senha-usuario.ps1" });
|
||||
|
||||
console.group(`%c[${new Date().toLocaleTimeString()}] RESPOSTA DO BACKEND`, 'color: #27ae60; font-weight: bold;');
|
||||
console.log("DESTINO: API de Atualização de Perfil"); console.log("USUÁRIO:", samAccountName);
|
||||
console.log("AÇÕES EXECUTADAS:"); console.table(actions); console.groupEnd();
|
||||
|
||||
submitButton.classList.remove('sending'); submitButton.classList.add('success');
|
||||
|
||||
setTimeout(() => {
|
||||
submitButton.classList.remove('success'); submitButton.disabled = false;
|
||||
|
||||
profileForm.reset();
|
||||
strengthFill.style.width = '0'; strengthText.textContent = '';
|
||||
imagePreview.src = placeholderImage;
|
||||
croppedImageData = null;
|
||||
|
||||
console.log(`%c[${new Date().toLocaleTimeString()}] INTERFACE ATUALIZADA E PRONTA.`, 'color: #9b59b6;');
|
||||
}, 1500);
|
||||
}, 1000);
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Reference in New Issue