File size: 10,368 Bytes
3e64e35 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 | /* ============================================================
SpeakFlow AI β session.js
Shared session management for index.html
============================================================ */
'use strict';
(function initSession() {
const session = JSON.parse(localStorage.getItem('sf_session') || 'null');
// Route protection β redirect to login if not logged in
if (!session || !session.loggedIn) {
window.location.href = 'login.html';
return;
}
// Show user info in navbar
const info = document.getElementById('navUserInfo');
const nameEl = document.getElementById('navUserName');
if (info && nameEl) {
nameEl.textContent = session.name || 'User';
info.style.display = 'flex';
}
// Profile button β open profile modal
const profileBtn = document.getElementById('navProfileBtn');
if (profileBtn) {
profileBtn.addEventListener('click', openProfileModal);
}
// Logout
const logoutBtn = document.getElementById('navLogoutBtn');
if (logoutBtn) {
logoutBtn.addEventListener('click', () => {
localStorage.removeItem('sf_session');
window.location.href = 'login.html';
});
}
// ββ Profile Modal ββββββββββββββββββββββββββββββββββββββββ
function openProfileModal() {
if (document.getElementById('sfProfileModal')) return;
const users = JSON.parse(localStorage.getItem('sf_users') || '[]');
const user = users.find(u => u.email === session.email) || {};
const history = JSON.parse(localStorage.getItem('sf_analysis_history') || '[]');
const userAnalyses = history.filter(h => h.userEmail === session.email).length;
const modal = document.createElement('div');
modal.id = 'sfProfileModal';
modal.innerHTML = `
<div class="sf-modal-overlay" id="sfModalOverlay">
<div class="sf-modal-box glass-card">
<div class="sf-modal-header">
<div class="sf-modal-avatar"><i class="fas fa-user-circle"></i></div>
<h2>My Profile</h2>
<button class="sf-modal-close" id="sfModalClose"><i class="fas fa-times"></i></button>
</div>
<div class="sf-modal-body" id="sfProfileView">
<div class="sf-profile-row"><span><i class="fas fa-user"></i> Full Name</span><strong id="pName">${session.name}</strong></div>
<div class="sf-profile-row"><span><i class="fas fa-envelope"></i> Email</span><strong>${session.email}</strong></div>
<div class="sf-profile-row"><span><i class="fas fa-chart-bar"></i> Total Analyses</span><strong>${userAnalyses}</strong></div>
<div class="sf-profile-row"><span><i class="fas fa-calendar-alt"></i> Member Since</span><strong>${user.createdAt ? new Date(user.createdAt).toLocaleDateString() : 'N/A'}</strong></div>
<div class="sf-modal-actions">
<button class="btn btn-primary" id="sfEditProfileBtn"><i class="fas fa-edit"></i> Edit Profile</button>
<button class="btn btn-outline" id="sfChangePassBtn"><i class="fas fa-key"></i> Change Password</button>
</div>
</div>
<div class="sf-modal-body" id="sfEditView" style="display:none;">
<label>Full Name</label>
<input class="sf-input" type="text" id="sfNewName" value="${session.name}" placeholder="Full Name" />
<div class="sf-modal-actions">
<button class="btn btn-primary" id="sfSaveNameBtn"><i class="fas fa-save"></i> Save Changes</button>
<button class="btn btn-ghost" id="sfCancelEditBtn"><i class="fas fa-arrow-left"></i> Back</button>
</div>
<p id="sfEditMsg" style="color:var(--green);margin-top:8px;display:none;"></p>
</div>
<div class="sf-modal-body" id="sfPassView" style="display:none;">
<label>Current Password</label>
<input class="sf-input" type="password" id="sfOldPass" placeholder="Current password" />
<label>New Password</label>
<input class="sf-input" type="password" id="sfNewPass" placeholder="New password" />
<label>Confirm New Password</label>
<input class="sf-input" type="password" id="sfConfPass" placeholder="Confirm new password" />
<div class="sf-modal-actions">
<button class="btn btn-primary" id="sfSavePassBtn"><i class="fas fa-save"></i> Update Password</button>
<button class="btn btn-ghost" id="sfCancelPassBtn"><i class="fas fa-arrow-left"></i> Back</button>
</div>
<p id="sfPassMsg" style="margin-top:8px;display:none;"></p>
</div>
</div>
</div>`;
document.body.appendChild(modal);
// inject modal CSS if not already
if (!document.getElementById('sfModalStyle')) {
const s = document.createElement('style');
s.id = 'sfModalStyle';
s.textContent = `
#sfProfileModal { position:fixed;inset:0;z-index:9999; }
.sf-modal-overlay { position:absolute;inset:0;background:rgba(0,0,0,0.6);backdrop-filter:blur(4px);display:flex;align-items:center;justify-content:center;padding:16px; }
.sf-modal-box { background:var(--surface);border-radius:24px;padding:32px;width:100%;max-width:480px;position:relative;box-shadow:var(--shadow-lg); }
.sf-modal-header { display:flex;align-items:center;gap:16px;margin-bottom:24px; }
.sf-modal-avatar { font-size:2.5rem;color:var(--blue); }
.sf-modal-header h2 { font-size:1.4rem;font-weight:700;flex:1; }
.sf-modal-close { background:var(--surface-2);border-radius:50%;width:36px;height:36px;display:flex;align-items:center;justify-content:center;font-size:1rem;cursor:pointer;border:none;color:var(--text-muted); }
.sf-profile-row { display:flex;justify-content:space-between;align-items:center;padding:12px 0;border-bottom:1px solid var(--border);font-size:0.95rem; }
.sf-profile-row span { color:var(--text-muted);display:flex;align-items:center;gap:8px; }
.sf-modal-actions { display:flex;gap:12px;margin-top:24px;flex-wrap:wrap; }
.sf-input { width:100%;padding:12px 16px;border:1px solid var(--border);border-radius:12px;background:var(--surface-2);color:var(--text);font-size:0.95rem;margin-bottom:16px;margin-top:4px;outline:none; }
.sf-input:focus { border-color:var(--blue); }
.sf-modal-body label { font-size:0.85rem;font-weight:600;color:var(--text-muted); }
.nav-user-info { display:flex;align-items:center;gap:8px; }
.btn-user-profile { display:flex;align-items:center;gap:8px;padding:8px 14px;background:rgba(37,99,235,0.1);border-radius:50px;color:var(--blue);font-weight:600;font-size:0.9rem;cursor:pointer;border:none;transition:all .2s; }
.btn-user-profile:hover { background:rgba(37,99,235,0.2); }
.btn-logout { display:flex;align-items:center;gap:6px;padding:8px 14px;background:rgba(239,68,68,0.1);border-radius:50px;color:var(--red);font-weight:600;font-size:0.9rem;cursor:pointer;border:none;transition:all .2s; }
.btn-logout:hover { background:rgba(239,68,68,0.2); }
`;
document.head.appendChild(s);
}
document.getElementById('sfModalClose').onclick = closeModal;
document.getElementById('sfModalOverlay').onclick = (e) => { if(e.target.id==='sfModalOverlay') closeModal(); };
document.getElementById('sfEditProfileBtn').onclick = () => {
document.getElementById('sfProfileView').style.display = 'none';
document.getElementById('sfEditView').style.display = 'block';
};
document.getElementById('sfCancelEditBtn').onclick = () => {
document.getElementById('sfEditView').style.display = 'none';
document.getElementById('sfProfileView').style.display = 'block';
};
document.getElementById('sfSaveNameBtn').onclick = () => {
const newName = document.getElementById('sfNewName').value.trim();
if (!newName) return;
// Update user in localStorage
const users2 = JSON.parse(localStorage.getItem('sf_users') || '[]');
const idx = users2.findIndex(u => u.email === session.email);
if (idx !== -1) { users2[idx].name = newName; localStorage.setItem('sf_users', JSON.stringify(users2)); }
session.name = newName;
localStorage.setItem('sf_session', JSON.stringify(session));
document.getElementById('navUserName').textContent = newName;
document.getElementById('pName').textContent = newName;
const msg = document.getElementById('sfEditMsg');
msg.textContent = 'β
Name updated successfully!';
msg.style.display = 'block';
};
document.getElementById('sfChangePassBtn').onclick = () => {
document.getElementById('sfProfileView').style.display = 'none';
document.getElementById('sfPassView').style.display = 'block';
};
document.getElementById('sfCancelPassBtn').onclick = () => {
document.getElementById('sfPassView').style.display = 'none';
document.getElementById('sfProfileView').style.display = 'block';
};
document.getElementById('sfSavePassBtn').onclick = () => {
const old = document.getElementById('sfOldPass').value;
const nw = document.getElementById('sfNewPass').value;
const conf = document.getElementById('sfConfPass').value;
const msg = document.getElementById('sfPassMsg');
const users3 = JSON.parse(localStorage.getItem('sf_users') || '[]');
const idx = users3.findIndex(u => u.email === session.email);
if (idx === -1 || users3[idx].password !== old) {
msg.textContent = 'β Current password is incorrect.'; msg.style.color='var(--red)'; msg.style.display='block'; return;
}
if (nw.length < 6) { msg.textContent = 'β Password must be at least 6 characters.'; msg.style.color='var(--red)'; msg.style.display='block'; return; }
if (nw !== conf) { msg.textContent = 'β Passwords do not match.'; msg.style.color='var(--red)'; msg.style.display='block'; return; }
users3[idx].password = nw;
localStorage.setItem('sf_users', JSON.stringify(users3));
msg.textContent = 'β
Password updated!'; msg.style.color='var(--green)'; msg.style.display='block';
};
}
function closeModal() {
const m = document.getElementById('sfProfileModal');
if (m) m.remove();
}
})();
|