sge / static /reset.html
vsmdvic's picture
Upload 15 files
28170cc verified
<!DOCTYPE html>
<html lang="ro">
<head>
<link rel="icon" type="image/svg+xml" href="favicon.svg">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
<title>SGE | Resetare Parolă</title>
<link rel="stylesheet" href="style.css">
<script src="errors.js"></script>
<style>
body { display:flex; flex-direction:column; align-items:center; justify-content:center; min-height:100dvh; padding:20px 14px; }
.wrap { width:100%; max-width:360px; }
.phone-wrap { display:flex; border:1px solid rgba(255,255,255,0.12); }
.phone-prefix { background:rgba(255,255,255,0.06); border:none; border-right:1px solid rgba(255,255,255,0.1); color:var(--white); padding:10px 12px; font-family:'DM Mono',monospace; font-size:12px; flex-shrink:0; display:flex; align-items:center; }
.phone-input { flex:1; background:transparent; border:none; color:var(--white); padding:10px 12px; font-family:'DM Mono',monospace; font-size:13px; letter-spacing:2px; outline:none; }
.phone-input::placeholder { color:var(--white-faint); font-size:11px; }
.phase { display:none; animation:fadeSlideIn 0.3s ease forwards; }
.phase.active { display:block; }
@keyframes fadeSlideIn { from{opacity:0;transform:translateY(6px);}to{opacity:1;transform:translateY(0);} }
.sms-box { text-align:center; padding:20px 16px; background:var(--glass); border:1px solid var(--glass-border); margin-bottom:14px; }
.sms-box .sb-title { font-family:'Cormorant Garamond',serif; font-size:17px; letter-spacing:2px; margin-bottom:6px; }
.sms-box .sb-num { font-family:'DM Mono',monospace; font-size:14px; letter-spacing:2px; margin-top:8px; }
.waiting-indicator { display:flex; align-items:center; gap:10px; padding:12px 14px; background:var(--glass); border:1px solid var(--glass-border); margin-bottom:14px; }
.pulse-dot { width:8px; height:8px; border-radius:50%; background:rgba(255,255,255,0.4); animation:pulse 2s ease-in-out infinite; flex-shrink:0; }
@keyframes pulse { 0%,100%{opacity:0.3;transform:scale(0.8);}50%{opacity:1;transform:scale(1.2);} }
</style>
<script>if(localStorage.getItem('sge_maintenance')==='1'){window.location.replace('503.html');}</script>
</head>
<body>
<div class="wrap">
<div style="text-align:center;margin-bottom:22px;" class="fade-in">
<img src="logo.svg" style="width:34px;height:34px;margin:0 auto 10px;display:block;">
<div style="font-family:'Cormorant Garamond',serif;font-size:22px;letter-spacing:3px;">SGE</div>
<div style="font-size:9px;letter-spacing:2px;color:var(--white-dim);margin-top:3px;">RESETARE PAROLĂ</div>
</div>
<!-- STEPS -->
<div class="steps fade-in-2">
<div class="step"><div class="step-dot active" id="s1-dot">1</div><div class="step-label active">IDENTIFICARE</div></div>
<div class="step-line"></div>
<div class="step"><div class="step-dot" id="s2-dot">2</div><div class="step-label" id="s2-lbl">SMS</div></div>
<div class="step-line"></div>
<div class="step"><div class="step-dot" id="s3-dot">3</div><div class="step-label" id="s3-lbl">PAROLĂ NOUĂ</div></div>
</div>
<!-- PHASE 1 -->
<div class="phase active fade-in-3" id="phase-1">
<div class="card" style="padding:18px 16px;">
<div class="card-title" style="font-size:15px;">Identificare cont</div>
<p style="font-size:11px;color:var(--white-dim);margin-bottom:16px;line-height:1.9;">
Selectează contul tău și introdu numărul de telefon pentru a primi un cod de resetare.
</p>
<div class="field">
<label>Contul tău</label>
<select id="elev-sel"><option value="">— selectează —</option></select>
</div>
<div class="field">
<label>Număr de telefon</label>
<div class="phone-wrap">
<div class="phone-prefix">+373</div>
<input class="phone-input" type="tel" id="phone-in" maxlength="9" placeholder="(69) 048 176" inputmode="tel" oninput="fmtPhone(this)">
</div>
<div style="font-size:9px;color:var(--white-faint);margin-top:5px;letter-spacing:1px;">Ex: +373 (69) 048 176</div>
</div>
<button class="btn-primary" onclick="requestReset()" id="btn-reset" style="width:100%;letter-spacing:2px;margin-top:4px;">SOLICITĂ RESETARE →</button>
<div class="alert error" id="err-1" style="margin-top:10px;"></div>
</div>
<div style="text-align:center;margin-top:12px;">
<a href="index.html" style="font-size:10px;color:var(--white-dim);letter-spacing:1px;text-decoration:none;">← înapoi la login</a>
</div>
</div>
<!-- PHASE 2 -->
<div class="phase" id="phase-2">
<div class="sms-box">
<div class="sb-title">Cod trimis prin SMS</div>
<div style="font-size:10px;color:var(--white-dim);letter-spacing:1px;line-height:1.9;">Administratorul ți-a transmis un cod de resetare pe numărul:</div>
<div class="sb-num" id="phone-display"></div>
</div>
<div class="waiting-indicator">
<div class="pulse-dot"></div>
<div>
<div class="wi-text">Așteptăm confirmarea adminului...</div>
<div class="wi-code" id="wait-timer"></div>
</div>
</div>
<div class="card" style="padding:18px 16px;">
<div class="card-title" style="font-size:15px;">Introdu codul din SMS</div>
<div class="field">
<input type="text" id="code-in" maxlength="4" placeholder="• • • •"
inputmode="numeric" autocomplete="one-time-code"
style="font-size:28px;letter-spacing:12px;text-align:center;padding:14px;">
</div>
<button class="btn-primary" onclick="verifyReset()" style="width:100%;letter-spacing:2px;margin-top:4px;">VERIFICĂ COD →</button>
<div class="alert error" id="err-2" style="margin-top:10px;"></div>
<div style="text-align:center;margin-top:12px;">
<button class="btn-ghost" onclick="backToStep1()" style="font-size:9px;">Nu am primit SMS — Înapoi</button>
</div>
</div>
</div>
<!-- PHASE 3 -->
<div class="phase" id="phase-3">
<div class="card" style="padding:18px 16px;">
<div class="card-title" style="font-size:15px;">Parolă nouă</div>
<p style="font-size:11px;color:var(--white-dim);margin-bottom:14px;line-height:1.9;">
Alege o parolă nouă de minimum 6 cifre.
</p>
<div class="field">
<label>Parolă nouă (min. 6 cifre)</label>
<input type="password" id="new-pin1" maxlength="6" placeholder="••••••" inputmode="numeric" autocomplete="new-password">
</div>
<div class="field">
<label>Confirmă parola</label>
<input type="password" id="new-pin2" maxlength="6" placeholder="••••••" inputmode="numeric" autocomplete="new-password">
</div>
<button class="btn-primary" onclick="saveNewPin()" style="width:100%;letter-spacing:2px;margin-top:4px;">SALVEAZĂ PAROLA →</button>
<div class="alert error" id="err-3" style="margin-top:10px;"></div>
</div>
</div>
<!-- PHASE 4: Done -->
<div class="phase" id="phase-4">
<div class="card" style="padding:28px 20px;">
<div class="success-anim">
<svg viewBox="0 0 24 24" fill="none" stroke="#5a9a5a" stroke-width="1.5" stroke-linecap="round">
<path d="M22 11.08V12a10 10 0 11-5.93-9.14"/>
<polyline points="22 4 12 14.01 9 11.01"/>
</svg>
<div class="sa-title">Parolă resetată</div>
<div style="font-size:11px;color:var(--white-dim);letter-spacing:1px;" id="done-name"></div>
</div>
<div style="margin-top:20px;">
<button class="btn-primary" onclick="window.location.href='index.html'" style="width:100%;letter-spacing:2px;">MERGI LA LOGIN →</button>
</div>
</div>
</div>
<div class="footer-mini">SGE &copy;2026 &mdash; Victor Roșca</div>
</div>
<script type="module">
import { initializeApp } from "https://www.gstatic.com/firebasejs/10.12.0/firebase-app.js";
import { getFirestore, collection, getDocs, addDoc, updateDoc, doc, query, where, serverTimestamp }
from "https://www.gstatic.com/firebasejs/10.12.0/firebase-firestore.js";
const cfg = {
apiKey:"AIzaSyB9--Onx3-_YjD-YzblhZjaWSVVqTQJ1lU", authDomain:"vservers1.firebaseapp.com",
projectId:"vservers1", storageBucket:"vservers1.firebasestorage.app",
messagingSenderId:"42433037358", appId:"1:42433037358:web:fde70fec79542428b60bbf"
};
const app = initializeApp(cfg);
const db = getFirestore(app);
let selectedElevId = null, selectedVpass = null, selectedNume = null;
let resetCode = null, resetDocId = null, codeExpiry = null;
// Load elevi
try {
const snap = await getDocs(collection(db,'elevi'));
const sel = document.getElementById('elev-sel');
const elevi = [];
snap.forEach(d => elevi.push({id:d.id,...d.data()}));
elevi.sort((a,b)=>(a.pozitie||0)-(b.pozitie||0));
elevi.forEach(e => {
if (!e.pin) return; // doar cei cu cont activ
const o = document.createElement('option');
o.value = e.id;
o.textContent = `${String(e.pozitie||'').padStart(2,'0')}. ${e.nume}`;
sel.appendChild(o);
});
} catch(e) {}
function setPhase(n) {
document.querySelectorAll('.phase').forEach(p => p.classList.remove('active'));
document.getElementById('phase-'+n).classList.add('active');
window.scrollTo({top:0,behavior:'smooth'});
for (let i=1;i<=3;i++) {
const d = document.getElementById(`s${i}-dot`);
if (i < n) { d.classList.add('done'); d.innerHTML='✓'; }
else if (i===n) { d.classList.add('active'); }
else { d.classList.remove('active','done'); }
}
}
window.fmtPhone = function(input) {
let v = input.value.replace(/\D/g,'');
if(v.length>8)v=v.slice(0,8);
let out='';
if(v.length>=2)out='('+v.slice(0,2)+') '; else out=v;
if(v.length>2)out+=v.slice(2,5);
if(v.length>5)out+=' '+v.slice(5,8);
input.value=out;
};
window.requestReset = async function() {
hideError('err-1');
const id = document.getElementById('elev-sel').value;
const rawPh = document.getElementById('phone-in').value.replace(/\D/g,'');
if (!id) { showError('err-1','err-021','Selectează contul.'); return; }
if (rawPh.length<8){ showError('err-1','err-021','Număr de telefon incomplet.'); return; }
document.getElementById('btn-reset').disabled=true;
const phone = '+373 ('+rawPh.slice(0,2)+') '+rawPh.slice(2,5)+' '+rawPh.slice(5,8);
try {
const snap = await getDocs(query(collection(db,'elevi')));
const elevDoc = snap.docs.find(d=>d.id===id);
if (!elevDoc) { showError('err-1','err-002'); document.getElementById('btn-reset').disabled=false; return; }
selectedElevId = id;
selectedVpass = elevDoc.data().vpassId;
selectedNume = elevDoc.data().nume;
resetCode = String(Math.floor(1000+Math.random()*9000));
const ref = await addDoc(collection(db,'notificari'),{
tip:'reset_request', elevId:id, elevVpass:selectedVpass, elevNume:selectedNume,
telefon:phone, confirmCode:resetCode,
status:'pending', citita:false, timestamp:serverTimestamp()
});
resetDocId = ref.id;
document.getElementById('phone-display').textContent = phone;
codeExpiry = Date.now() + 10*60*1000;
const tv = document.getElementById('wait-timer');
const iv = setInterval(()=>{
const l=Math.max(0,codeExpiry-Date.now());
const m=Math.floor(l/60000), s=Math.floor((l%60000)/1000);
tv.textContent=`Expiră în ${m}:${String(s).padStart(2,'0')}`;
if(l<=0){clearInterval(iv);tv.textContent='Cod expirat';}
},1000);
setPhase(2);
} catch(e){ showError('err-1','err-025'); document.getElementById('btn-reset').disabled=false; }
};
window.verifyReset = function() {
hideError('err-2');
const input = document.getElementById('code-in').value.replace(/\s/g,'');
if(!/^\d{4}$/.test(input)){ showError('err-2','err-029'); return; }
if(codeExpiry && Date.now()>codeExpiry){ showError('err-2','err-006'); return; }
if(input !== resetCode){ showError('err-2','err-007'); return; }
setPhase(3);
};
window.backToStep1 = function() {
document.getElementById('btn-reset').disabled=false;
setPhase(1);
};
window.saveNewPin = async function() {
hideError('err-3');
const p1 = document.getElementById('new-pin1').value;
const p2 = document.getElementById('new-pin2').value;
if(p1.length<6){ showError('err-3','err-008'); return; }
if(p1!==p2){ showError('err-3','err-008','Parolele nu coincid.'); return; }
try {
await updateDoc(doc(db,'elevi',selectedElevId),{pin:p1});
if(resetDocId) await updateDoc(doc(db,'notificari',resetDocId),{status:'completed',citita:true});
document.getElementById('done-name').textContent=selectedNume;
// Sterge sesiunea veche
sessionStorage.removeItem('vs_role');
setPhase(4);
} catch(e){ showError('err-3','err-025'); }
};
</script>
<a href="vhelp.html" class="vhelp-fab" title="VHelp">
<svg viewBox="0 0 24 24" fill="none" stroke="rgba(255,255,255,0.9)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/>
<circle cx="9" cy="10" r="0.5" fill="rgba(255,255,255,0.9)"/>
<circle cx="12" cy="10" r="0.5" fill="rgba(255,255,255,0.9)"/>
<circle cx="15" cy="10" r="0.5" fill="rgba(255,255,255,0.9)"/>
</svg>
</a>
</body>
</html>