diff --git a/index.html b/index.html
index 90db50a..a3a193a 100644
--- a/index.html
+++ b/index.html
@@ -1805,10 +1805,15 @@ function loadFriends() {
friendsList = [];
for (const fuid of allFriendUids) {
+ const req = [...sentSnap.docs, ...receivedSnap.docs].find(d =>
+ (d.data().fromUid === currentUser.uid && d.data().toUid === fuid) ||
+ (d.data().toUid === currentUser.uid && d.data().fromUid === fuid)
+ );
+ const addedAt = req?.data()?.createdAt?.toMillis?.() || 0;
const unsubProfile = onSnapshot(doc(db, 'profiles', fuid), profileSnap => {
if (!profileSnap.exists()) return;
const idx = friendsList.findIndex(f => f.uid === fuid);
- const data = { uid: fuid, ...profileSnap.data() };
+ const data = { uid: fuid, addedAt, ...profileSnap.data() };
if (idx >= 0) {
friendsList[idx] = data;
} else {
@@ -1900,7 +1905,8 @@ function renderFriendsPanel() {
if (friendsList.length === 0) {
fml.innerHTML = `
🤝
No friends yet
Send a request above to add your first StepMate.
`;
} else {
- fml.innerHTML = friendsList.map(f => {
+ const sortedByAdded = [...friendsList].sort((a,b) => (b.addedAt || 0) - (a.addedAt || 0));
+ fml.innerHTML = sortedByAdded.map(f => {
const steps = getStepsForPeriod(f.stepsByDate, currentTab);
return `
@@ -1909,6 +1915,7 @@ function renderFriendsPanel() {
${esc(f.displayName || f.email)}
${steps.toLocaleString()} steps today
+
`;
}).join('');
}
@@ -1927,8 +1934,10 @@ function updateBadge() {
window.sendFriendRequest = async function() {
const emailInput = document.getElementById('add-friend-email');
const errEl = document.getElementById('add-friend-error');
+ const btn = document.querySelector('#panel-friends .add-friend-row .btn');
const email = emailInput.value.trim().toLowerCase();
errEl.style.display = 'none';
+ errEl.style.color = '';
if (!email || !/\S+@\S+\.\S+/.test(email)) {
errEl.textContent = 'Please enter a valid email.';
@@ -1941,17 +1950,21 @@ window.sendFriendRequest = async function() {
return;
}
+ btn.disabled = true;
+ btn.innerHTML = '';
+
const usersQ = query(collection(db, 'users'), where('email', '==', email));
const snap = await getDocs(usersQ);
if (snap.empty) {
errEl.textContent = 'No StepMates account found for that email.';
errEl.style.display = 'block';
+ btn.disabled = false;
+ btn.innerHTML = 'Send Request';
return;
}
const toUser = snap.docs[0];
const toUid = toUser.id;
- const toData = toUser.data();
const existingQ = query(collection(db, 'friendRequests'),
where('fromUid', '==', currentUser.uid),
@@ -1961,6 +1974,8 @@ window.sendFriendRequest = async function() {
if (!existingSnap.empty) {
errEl.textContent = 'You already sent a request to this person.';
errEl.style.display = 'block';
+ btn.disabled = false;
+ btn.innerHTML = 'Send Request';
return;
}
@@ -1975,7 +1990,12 @@ window.sendFriendRequest = async function() {
});
emailInput.value = '';
- showToast('Friend request sent!', 'success');
+ btn.disabled = false;
+ btn.innerHTML = 'Send Request';
+ errEl.textContent = '✓ Friend request sent!';
+ errEl.style.color = 'var(--success)';
+ errEl.style.display = 'block';
+ setTimeout(() => { errEl.style.display = 'none'; }, 4000);
await loadFriends();
}
@@ -1985,6 +2005,19 @@ window.respondRequest = async function(requestId, status) {
await loadFriends();
}
+window.removeFriend = async function(friendUid, friendName) {
+ if (!confirm(`Remove ${friendName} from your friends?`)) return;
+ const uid = currentUser.uid;
+ const frRef = collection(db, 'friendRequests');
+ const q1 = query(frRef, where('fromUid', '==', uid), where('toUid', '==', friendUid));
+ const q2 = query(frRef, where('fromUid', '==', friendUid), where('toUid', '==', uid));
+ const [s1, s2] = await Promise.all([getDocs(q1), getDocs(q2)]);
+ const deletes = [...s1.docs, ...s2.docs].map(d => updateDoc(doc(db, 'friendRequests', d.id), { status: 'removed' }));
+ await Promise.all(deletes);
+ showToast(`${friendName} removed`, '');
+ await loadFriends();
+}
+
// ─────────────────────────────────────────────
// PANEL SWITCHING
// ─────────────────────────────────────────────