// ── 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 = `
`;
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 =
`
`;
} 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 =
`
`;
}
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();