From f34ebcc91bdb9875ca16fb65418934710ff397a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Thu, 22 Feb 2024 11:44:22 -0500 Subject: [PATCH] fix: #12357, properly update lists and counters --- public/src/client/groups/details.js | 99 ++++++++++++++-------- public/src/client/groups/memberlist.js | 111 ++++++++++++------------- public/src/modules/helpers.common.js | 2 +- 3 files changed, 120 insertions(+), 92 deletions(-) diff --git a/public/src/client/groups/details.js b/public/src/client/groups/details.js index 2d84e3214d..8dde2e3eab 100644 --- a/public/src/client/groups/details.js +++ b/public/src/client/groups/details.js @@ -6,24 +6,24 @@ define('forum/groups/details', [ 'components', 'coverPhoto', 'pictureCropper', - 'translator', 'api', 'slugify', 'categorySelector', 'bootbox', 'alerts', + 'helpers', ], function ( memberList, iconSelect, components, coverPhoto, pictureCropper, - translator, api, slugify, categorySelector, bootbox, - alerts + alerts, + helpers ) { const Details = {}; let groupName; @@ -85,14 +85,19 @@ define('forum/groups/details', [ break; case 'kick': - translator.translate('[[groups:details.kick-confirm]]', function (translated) { - bootbox.confirm(translated, function (confirm) { - if (!confirm) { - return; - } + bootbox.confirm('[[groups:details.kick-confirm]]', function (confirm) { + if (!confirm) { + return; + } - api.del(`/groups/${ajaxify.data.group.slug}/membership/${uid}`, undefined).then(() => userRow.slideUp().remove()).catch(alerts.error); - }); + api.del(`/groups/${ajaxify.data.group.slug}/membership/${uid}`, undefined).then( + () => { + userRow.remove(); + $('[component="group/member/count"]').text( + helpers.humanReadableNumber(ajaxify.data.group.memberCount - 1) + ); + } + ).catch(alerts.error); }); break; @@ -105,29 +110,42 @@ define('forum/groups/details', [ break; case 'join': - api.put('/groups/' + ajaxify.data.group.slug + '/membership/' + (uid || app.user.uid), undefined).then(() => ajaxify.refresh()).catch(alerts.error); + api.put('/groups/' + ajaxify.data.group.slug + '/membership/' + (uid || app.user.uid), undefined).then( + () => ajaxify.refresh() + ).catch(alerts.error); break; case 'leave': - api.del('/groups/' + ajaxify.data.group.slug + '/membership/' + (uid || app.user.uid), undefined).then(() => ajaxify.refresh()).catch(alerts.error); + api.del('/groups/' + ajaxify.data.group.slug + '/membership/' + (uid || app.user.uid), undefined).then( + () => ajaxify.refresh() + ).catch(alerts.error); break; case 'accept': - api.put(`/groups/${ajaxify.data.group.slug}/pending/${uid}`).then(() => ajaxify.refresh()).catch(alerts.error); + api.put(`/groups/${ajaxify.data.group.slug}/pending/${uid}`).then( + () => { + userRow.remove(); + memberList.refresh(); + updatePendingAlertVisibility(); + } + ).catch(alerts.error); break; case 'reject': - api.del(`/groups/${ajaxify.data.group.slug}/pending/${uid}`).then(() => ajaxify.refresh()).catch(alerts.error); - break; - - case 'issueInvite': - api.post(`/groups/${ajaxify.data.group.slug}/invites/${uid}`).then(() => ajaxify.refresh()).catch(alerts.error); + api.del(`/groups/${ajaxify.data.group.slug}/pending/${uid}`).then( + () => { + userRow.remove(); + memberList.refresh(); + updatePendingAlertVisibility(); + } + ).catch(alerts.error); break; case 'acceptInvite': api.put(`/groups/${ajaxify.data.group.slug}/invites/${app.user.uid}`).then(() => { if (uid) { userRow.remove(); + memberList.refresh(); } else { ajaxify.refresh(); } @@ -139,6 +157,8 @@ define('forum/groups/details', [ api.del(`/groups/${ajaxify.data.group.slug}/invites/${uid || app.user.uid}`).then(() => { if (uid) { userRow.remove(); + updateInviteAlertVisibility(); + memberList.refresh(); } else { ajaxify.refresh(); } @@ -268,6 +288,20 @@ define('forum/groups/details', [ }); }; + function updatePendingAlertVisibility() { + $('[component="groups/pending/alert"]').toggleClass( + 'hidden', + $('[component="groups/pending"] tbody tr').length > 0 + ); + } + + function updateInviteAlertVisibility() { + $('[component="groups/invited/alert"]').toggleClass( + 'hidden', + $('[component="groups/invited"] tbody tr').length > 0 + ); + } + function handleMemberInvitations() { if (!ajaxify.data.group.isOwner) { return; @@ -275,8 +309,9 @@ define('forum/groups/details', [ async function updateList() { const data = await api.get(`/api/groups/${ajaxify.data.group.slug}`); const html = await app.parseAndTranslate('groups/details', 'group.invited', { group: data.group }); - $('[component="groups/invited"] tbody tr').remove(); $('[component="groups/invited"] tbody').html(html); + updateInviteAlertVisibility(); + memberList.refresh(); } const searchInput = $('[component="groups/members/invite"]'); require(['autocomplete'], function (autocomplete) { @@ -305,21 +340,19 @@ define('forum/groups/details', [ } function removeCover() { - translator.translate('[[groups:remove-group-cover-confirm]]', function (translated) { - bootbox.confirm(translated, function (confirm) { - if (!confirm) { - return; - } + bootbox.confirm('[[groups:remove-group-cover-confirm]]', function (confirm) { + if (!confirm) { + return; + } - socket.emit('groups.cover.remove', { - groupName: ajaxify.data.group.name, - }, function (err) { - if (!err) { - ajaxify.refresh(); - } else { - alerts.error(err); - } - }); + socket.emit('groups.cover.remove', { + groupName: ajaxify.data.group.name, + }, function (err) { + if (!err) { + ajaxify.refresh(); + } else { + alerts.error(err); + } }); }); } diff --git a/public/src/client/groups/memberlist.js b/public/src/client/groups/memberlist.js index 73d82ce91e..80c319371d 100644 --- a/public/src/client/groups/memberlist.js +++ b/public/src/client/groups/memberlist.js @@ -1,19 +1,36 @@ 'use strict'; -define('forum/groups/memberlist', ['api', 'bootbox', 'alerts'], function (api, bootbox, alerts) { +define('forum/groups/memberlist', ['api', 'bootbox', 'alerts', 'helpers'], function (api, bootbox, alerts, helpers) { const MemberList = {}; - let groupName; let templateName; MemberList.init = function (_templateName) { templateName = _templateName || 'groups/details'; - groupName = ajaxify.data.group.name; handleMemberAdd(); handleMemberSearch(); handleMemberInfiniteScroll(); }; + MemberList.refresh = async function () { + const { group } = await api.get(`/api/groups/${ajaxify.data.group.slug}`); + const html = await parseAndTranslate(group.members); + $('[component="groups/members"] tbody').html(html); + $('[component="group/member/count"]').text( + helpers.humanReadableNumber(group.memberCount) + ); + $('[component="group/pending/count"]').text( + helpers.humanReadableNumber(group.pending.length) + ); + $('[component="group/invited/count"]').text( + helpers.humanReadableNumber(group.invited.length) + ); + ajaxify.data.group.members = group.members; + ajaxify.data.group.memberCount = group.memberCount; + ajaxify.data.group.invited = group.invited; + ajaxify.data.group.pending = group.pending; + }; + function handleMemberAdd() { $('[component="groups/members/add"]').on('click', function () { app.parseAndTranslate('admin/partials/groups/add-members', {}, function (html) { @@ -29,7 +46,7 @@ define('forum/groups/memberlist', ['api', 'bootbox', 'alerts'], function (api, b modal.find('[data-uid][data-selected]').each(function (index, el) { users.push(foundUsers[$(el).attr('data-uid')]); }); - addUserToGroup(users, function () { + addUsersToGroup(users).then(() => { modal.modal('hide'); }); }, @@ -65,99 +82,77 @@ define('forum/groups/memberlist', ['api', 'bootbox', 'alerts'], function (api, b }); } - function addUserToGroup(users, callback) { - function done() { - users = users.filter(function (user) { - return !$('[component="groups/members"] [data-uid="' + user.uid + '"]').length; - }); - parseAndTranslate(users, function (html) { - $('[component="groups/members"] tbody').prepend(html); - }); - callback(); - } - const uids = users.map(function (user) { return user.uid; }); - if (groupName === 'administrators') { - socket.emit('admin.user.makeAdmins', uids, function (err) { - if (err) { - return alerts.error(err); - } - done(); - }); + async function addUsersToGroup(users) { + const uids = users.map(u => u.uid); + if (ajaxify.data.group.name === 'administrators') { + await socket.emit('admin.user.makeAdmins', uids).catch(alerts.error); } else { - Promise.all(uids.map(uid => api.put('/groups/' + ajaxify.data.group.slug + '/membership/' + uid))).then(done).catch(alerts.error); + await Promise.all(uids.map(uid => api.put('/groups/' + ajaxify.data.group.slug + '/membership/' + uid))).catch(alerts.error); } + + users = users.filter(user => !$('[component="groups/members"] [data-uid="' + user.uid + '"]').length); + const html = await parseAndTranslate(users); + $('[component="groups/members"] tbody').prepend(html); } function handleMemberSearch() { const searchEl = $('[component="groups/members/search"]'); - searchEl.on('keyup', utils.debounce(function () { + searchEl.on('keyup', utils.debounce(async function () { const query = searchEl.val(); - api.get(`/groups/${ajaxify.data.group.slug}/members`, { query }, function (err, results) { - if (err) { - return alerts.error(err); - } - parseAndTranslate(results.users, function (html) { - $('[component="groups/members"] tbody').html(html); - $('[component="groups/members"]').attr('data-nextstart', 20); - }); - }); + const results = await api.get(`/groups/${ajaxify.data.group.slug}/members`, { query }); + const html = await parseAndTranslate(results.users); + $('[component="groups/members"] tbody').html(html); + $('[component="groups/members"]').attr('data-nextstart', 20); }, 250)); } function handleMemberInfiniteScroll() { - $('[component="groups/members"]').on('scroll', function () { + $('[component="groups/members"]').on('scroll', utils.debounce(function () { const $this = $(this); const bottom = ($this[0].scrollHeight - $this.innerHeight()) * 0.9; if ($this.scrollTop() > bottom && !$('[component="groups/members/search"]').val()) { loadMoreMembers(); } - }); + }, 250)); } - function loadMoreMembers() { + async function loadMoreMembers() { const members = $('[component="groups/members"]'); if (members.attr('loading')) { return; } members.attr('loading', 1); - api.get(`/groups/${ajaxify.data.group.slug}/members`, { + const data = await api.get(`/groups/${ajaxify.data.group.slug}/members`, { after: members.attr('data-nextstart'), - }, function (err, data) { - if (err) { - return alerts.error(err); - } + }).catch(alerts.error); - if (data && data.users.length) { - onMembersLoaded(data.users, function () { - members.removeAttr('loading'); - members.attr('data-nextstart', data.nextStart); - }); - } else { - members.removeAttr('loading'); - } - }); + if (data && data.users.length) { + await onMembersLoaded(data.users); + members.removeAttr('loading'); + members.attr('data-nextstart', data.nextStart); + } else { + members.removeAttr('loading'); + } } - function onMembersLoaded(users, callback) { + async function onMembersLoaded(users) { users = users.filter(function (user) { return !$('[component="groups/members"] [data-uid="' + user.uid + '"]').length; }); - parseAndTranslate(users, function (html) { - $('[component="groups/members"] tbody').append(html); - callback(); - }); + const html = await parseAndTranslate(users); + $('[component="groups/members"] tbody').append(html); } - function parseAndTranslate(users, callback) { - app.parseAndTranslate(templateName, 'group.members', { + async function parseAndTranslate(users) { + return await app.parseAndTranslate(templateName, 'group.members', { group: { members: users, isOwner: ajaxify.data.group.isOwner, }, - }, callback); + }); } return MemberList; diff --git a/public/src/modules/helpers.common.js b/public/src/modules/helpers.common.js index 4d2fd5f2bf..42b64f949d 100644 --- a/public/src/modules/helpers.common.js +++ b/public/src/modules/helpers.common.js @@ -167,7 +167,7 @@ module.exports = function (utils, Benchpress, relative_path) { if (groupObj.isPending && groupObj.name !== 'administrators') { return ``; } else if (groupObj.isInvited) { - return ``; + return ``; } else if (!groupObj.disableJoinRequests && groupObj.name !== 'administrators') { return ``; }