// ── Profile page logic ──────────────────────────────────────────────────────── let rigs = []; // ── Toast ───────────────────────────────────────────────────────────────────── function showToast(msg, type = 'success') { const el = document.createElement('div'); el.className = `toast align-items-center text-bg-${type} border-0 show`; el.innerHTML = `
${msg}
`; document.getElementById('toastContainer').appendChild(el); setTimeout(() => el.remove(), 3500); } function showAlert(id, msg, type = 'danger') { const el = document.getElementById(id); el.className = `alert alert-${type} mt-3`; el.textContent = msg; el.classList.remove('d-none'); } function hideAlert(id) { document.getElementById(id).classList.add('d-none'); } // ── Load profile ───────────────────────────────────────────────────────────── async function loadProfile() { try { const user = await apiGet('/users/profile/'); document.getElementById('firstName').value = user.first_name || ''; document.getElementById('lastName').value = user.last_name || ''; document.getElementById('email').value = user.email; document.getElementById('profileUsername').textContent = '@' + user.username; if (user.avatar_url) { document.getElementById('avatarWrap').innerHTML = `avatar`; } else { const initials = ((user.first_name?.[0] || '') + (user.last_name?.[0] || '') || user.username?.[0] || '?').toUpperCase(); document.getElementById('avatarInitials').textContent = initials; } } catch(e) { showToast('Failed to load profile', 'danger'); } } // ── Save profile info ───────────────────────────────────────────────────────── document.getElementById('profileForm').addEventListener('submit', async e => { e.preventDefault(); hideAlert('profileAlert'); const btn = document.getElementById('saveProfileBtn'); btn.disabled = true; try { await apiPatch('/users/profile/', { first_name: document.getElementById('firstName').value.trim(), last_name: document.getElementById('lastName').value.trim(), }); showAlert('profileAlert', 'Profile saved!', 'success'); showToast('Profile updated!'); } catch(e) { showAlert('profileAlert', formatErrors(e.data)); } finally { btn.disabled = false; } }); // ── Avatar upload ───────────────────────────────────────────────────────────── document.getElementById('avatarInput').addEventListener('change', async e => { const file = e.target.files[0]; if (!file) return; const alertEl = document.getElementById('avatarAlert'); alertEl.classList.add('d-none'); try { // Step 1: upload image to /api/photos/upload/ const form = new FormData(); form.append('file', file); const photo = await apiPost('/photos/upload/', form); // Step 2: set it as the user's avatar const updated = await apiPatch('/users/profile/', { avatar: photo.id }); if (updated.avatar_url) { document.getElementById('avatarWrap').innerHTML = `avatar`; } showToast('Avatar updated!'); } catch(e) { alertEl.textContent = (e.data && formatErrors(e.data)) || e.message || 'Upload failed. Please try a smaller image.'; alertEl.classList.remove('d-none'); } }); // ── Change password ─────────────────────────────────────────────────────────── document.getElementById('passwordForm').addEventListener('submit', async e => { e.preventDefault(); hideAlert('passwordAlert'); const p1 = document.getElementById('newPassword1').value; const p2 = document.getElementById('newPassword2').value; if (p1 !== p2) { showAlert('passwordAlert', 'New passwords do not match.'); return; } try { await apiPost('/auth/password/change/', { old_password: document.getElementById('oldPassword').value, new_password1: p1, new_password2: p2, }); showAlert('passwordAlert', 'Password changed successfully!', 'success'); document.getElementById('passwordForm').reset(); showToast('Password changed!'); } catch(e) { showAlert('passwordAlert', formatErrors(e.data)); } }); // ── Rigs table ──────────────────────────────────────────────────────────────── function renderRigs() { const tbody = document.getElementById('rigsBody'); const wrap = document.getElementById('rigsTableWrap'); const empty = document.getElementById('rigsEmpty'); document.getElementById('rigsSpinner').classList.add('d-none'); if (!rigs.length) { empty.classList.remove('d-none'); return; } wrap.classList.remove('d-none'); tbody.innerHTML = rigs.map(rig => ` ${rig.name} ${rig.rig_items.length} item${rig.rig_items.length === 1 ? '' : 's'} ${rig.is_public ? 'Public' : 'Private'} `).join(''); } async function loadRigs() { try { rigs = await apiGet('/rigs/'); renderRigs(); } catch(e) { document.getElementById('rigsSpinner').classList.add('d-none'); showToast('Failed to load rigs', 'danger'); } } async function toggleRig(id) { const rig = rigs.find(r => r.id === id); if (!rig) return; try { const updated = await apiPatch(`/rigs/${id}/`, { is_public: !rig.is_public }); const idx = rigs.findIndex(r => r.id === id); if (idx >= 0) rigs[idx] = { ...rigs[idx], is_public: updated.is_public }; renderRigs(); showToast(`Rig is now ${updated.is_public ? 'public' : 'private'}.`); } catch(e) { showToast('Failed to update rig.', 'danger'); } } // ── Init ────────────────────────────────────────────────────────────────────── loadProfile(); loadRigs();