fix: #12357, properly update lists and counters

This commit is contained in:
Barış Soner Uşaklı
2024-02-22 11:44:22 -05:00
parent 09b4dcd369
commit f34ebcc91b
3 changed files with 120 additions and 92 deletions

View File

@@ -6,24 +6,24 @@ define('forum/groups/details', [
'components', 'components',
'coverPhoto', 'coverPhoto',
'pictureCropper', 'pictureCropper',
'translator',
'api', 'api',
'slugify', 'slugify',
'categorySelector', 'categorySelector',
'bootbox', 'bootbox',
'alerts', 'alerts',
'helpers',
], function ( ], function (
memberList, memberList,
iconSelect, iconSelect,
components, components,
coverPhoto, coverPhoto,
pictureCropper, pictureCropper,
translator,
api, api,
slugify, slugify,
categorySelector, categorySelector,
bootbox, bootbox,
alerts alerts,
helpers
) { ) {
const Details = {}; const Details = {};
let groupName; let groupName;
@@ -85,14 +85,19 @@ define('forum/groups/details', [
break; break;
case 'kick': case 'kick':
translator.translate('[[groups:details.kick-confirm]]', function (translated) { bootbox.confirm('[[groups:details.kick-confirm]]', function (confirm) {
bootbox.confirm(translated, function (confirm) {
if (!confirm) { if (!confirm) {
return; 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; break;
@@ -105,29 +110,42 @@ define('forum/groups/details', [
break; break;
case 'join': 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; break;
case 'leave': 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; break;
case 'accept': 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; break;
case 'reject': case 'reject':
api.del(`/groups/${ajaxify.data.group.slug}/pending/${uid}`).then(() => ajaxify.refresh()).catch(alerts.error); api.del(`/groups/${ajaxify.data.group.slug}/pending/${uid}`).then(
break; () => {
userRow.remove();
case 'issueInvite': memberList.refresh();
api.post(`/groups/${ajaxify.data.group.slug}/invites/${uid}`).then(() => ajaxify.refresh()).catch(alerts.error); updatePendingAlertVisibility();
}
).catch(alerts.error);
break; break;
case 'acceptInvite': case 'acceptInvite':
api.put(`/groups/${ajaxify.data.group.slug}/invites/${app.user.uid}`).then(() => { api.put(`/groups/${ajaxify.data.group.slug}/invites/${app.user.uid}`).then(() => {
if (uid) { if (uid) {
userRow.remove(); userRow.remove();
memberList.refresh();
} else { } else {
ajaxify.refresh(); ajaxify.refresh();
} }
@@ -139,6 +157,8 @@ define('forum/groups/details', [
api.del(`/groups/${ajaxify.data.group.slug}/invites/${uid || app.user.uid}`).then(() => { api.del(`/groups/${ajaxify.data.group.slug}/invites/${uid || app.user.uid}`).then(() => {
if (uid) { if (uid) {
userRow.remove(); userRow.remove();
updateInviteAlertVisibility();
memberList.refresh();
} else { } else {
ajaxify.refresh(); 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() { function handleMemberInvitations() {
if (!ajaxify.data.group.isOwner) { if (!ajaxify.data.group.isOwner) {
return; return;
@@ -275,8 +309,9 @@ define('forum/groups/details', [
async function updateList() { async function updateList() {
const data = await api.get(`/api/groups/${ajaxify.data.group.slug}`); const data = await api.get(`/api/groups/${ajaxify.data.group.slug}`);
const html = await app.parseAndTranslate('groups/details', 'group.invited', { group: data.group }); const html = await app.parseAndTranslate('groups/details', 'group.invited', { group: data.group });
$('[component="groups/invited"] tbody tr').remove();
$('[component="groups/invited"] tbody').html(html); $('[component="groups/invited"] tbody').html(html);
updateInviteAlertVisibility();
memberList.refresh();
} }
const searchInput = $('[component="groups/members/invite"]'); const searchInput = $('[component="groups/members/invite"]');
require(['autocomplete'], function (autocomplete) { require(['autocomplete'], function (autocomplete) {
@@ -305,8 +340,7 @@ define('forum/groups/details', [
} }
function removeCover() { function removeCover() {
translator.translate('[[groups:remove-group-cover-confirm]]', function (translated) { bootbox.confirm('[[groups:remove-group-cover-confirm]]', function (confirm) {
bootbox.confirm(translated, function (confirm) {
if (!confirm) { if (!confirm) {
return; return;
} }
@@ -321,7 +355,6 @@ define('forum/groups/details', [
} }
}); });
}); });
});
} }
return Details; return Details;

View File

@@ -1,19 +1,36 @@
'use strict'; '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 = {}; const MemberList = {};
let groupName;
let templateName; let templateName;
MemberList.init = function (_templateName) { MemberList.init = function (_templateName) {
templateName = _templateName || 'groups/details'; templateName = _templateName || 'groups/details';
groupName = ajaxify.data.group.name;
handleMemberAdd(); handleMemberAdd();
handleMemberSearch(); handleMemberSearch();
handleMemberInfiniteScroll(); 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() { function handleMemberAdd() {
$('[component="groups/members/add"]').on('click', function () { $('[component="groups/members/add"]').on('click', function () {
app.parseAndTranslate('admin/partials/groups/add-members', {}, function (html) { 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) { modal.find('[data-uid][data-selected]').each(function (index, el) {
users.push(foundUsers[$(el).attr('data-uid')]); users.push(foundUsers[$(el).attr('data-uid')]);
}); });
addUserToGroup(users, function () { addUsersToGroup(users).then(() => {
modal.modal('hide'); modal.modal('hide');
}); });
}, },
@@ -65,99 +82,77 @@ define('forum/groups/memberlist', ['api', 'bootbox', 'alerts'], function (api, b
}); });
} }
function addUserToGroup(users, callback) { async function addUsersToGroup(users) {
function done() { const uids = users.map(u => u.uid);
users = users.filter(function (user) { if (ajaxify.data.group.name === 'administrators') {
return !$('[component="groups/members"] [data-uid="' + user.uid + '"]').length; await socket.emit('admin.user.makeAdmins', uids).catch(alerts.error);
});
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();
});
} else { } 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() { function handleMemberSearch() {
const searchEl = $('[component="groups/members/search"]'); const searchEl = $('[component="groups/members/search"]');
searchEl.on('keyup', utils.debounce(function () { searchEl.on('keyup', utils.debounce(async function () {
const query = searchEl.val(); const query = searchEl.val();
api.get(`/groups/${ajaxify.data.group.slug}/members`, { query }, function (err, results) { const results = await api.get(`/groups/${ajaxify.data.group.slug}/members`, { query });
if (err) { const html = await parseAndTranslate(results.users);
return alerts.error(err);
}
parseAndTranslate(results.users, function (html) {
$('[component="groups/members"] tbody').html(html); $('[component="groups/members"] tbody').html(html);
$('[component="groups/members"]').attr('data-nextstart', 20); $('[component="groups/members"]').attr('data-nextstart', 20);
});
});
}, 250)); }, 250));
} }
function handleMemberInfiniteScroll() { function handleMemberInfiniteScroll() {
$('[component="groups/members"]').on('scroll', function () { $('[component="groups/members"]').on('scroll', utils.debounce(function () {
const $this = $(this); const $this = $(this);
const bottom = ($this[0].scrollHeight - $this.innerHeight()) * 0.9; const bottom = ($this[0].scrollHeight - $this.innerHeight()) * 0.9;
if ($this.scrollTop() > bottom && !$('[component="groups/members/search"]').val()) { if ($this.scrollTop() > bottom && !$('[component="groups/members/search"]').val()) {
loadMoreMembers(); loadMoreMembers();
} }
}); }, 250));
} }
function loadMoreMembers() { async function loadMoreMembers() {
const members = $('[component="groups/members"]'); const members = $('[component="groups/members"]');
if (members.attr('loading')) { if (members.attr('loading')) {
return; return;
} }
members.attr('loading', 1); 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'), after: members.attr('data-nextstart'),
}, function (err, data) { }).catch(alerts.error);
if (err) {
return alerts.error(err);
}
if (data && data.users.length) { if (data && data.users.length) {
onMembersLoaded(data.users, function () { await onMembersLoaded(data.users);
members.removeAttr('loading'); members.removeAttr('loading');
members.attr('data-nextstart', data.nextStart); members.attr('data-nextstart', data.nextStart);
});
} else { } else {
members.removeAttr('loading'); members.removeAttr('loading');
} }
});
} }
function onMembersLoaded(users, callback) { async function onMembersLoaded(users) {
users = users.filter(function (user) { users = users.filter(function (user) {
return !$('[component="groups/members"] [data-uid="' + user.uid + '"]').length; return !$('[component="groups/members"] [data-uid="' + user.uid + '"]').length;
}); });
parseAndTranslate(users, function (html) { const html = await parseAndTranslate(users);
$('[component="groups/members"] tbody').append(html); $('[component="groups/members"] tbody').append(html);
callback();
});
} }
function parseAndTranslate(users, callback) { async function parseAndTranslate(users) {
app.parseAndTranslate(templateName, 'group.members', { return await app.parseAndTranslate(templateName, 'group.members', {
group: { group: {
members: users, members: users,
isOwner: ajaxify.data.group.isOwner, isOwner: ajaxify.data.group.isOwner,
}, },
}, callback); });
} }
return MemberList; return MemberList;

View File

@@ -167,7 +167,7 @@ module.exports = function (utils, Benchpress, relative_path) {
if (groupObj.isPending && groupObj.name !== 'administrators') { if (groupObj.isPending && groupObj.name !== 'administrators') {
return `<button class="btn btn-warning disabled ${btnClass}"><i class="fa fa-clock-o"></i> [[groups:membership.invitation-pending]]</button>`; return `<button class="btn btn-warning disabled ${btnClass}"><i class="fa fa-clock-o"></i> [[groups:membership.invitation-pending]]</button>`;
} else if (groupObj.isInvited) { } else if (groupObj.isInvited) {
return `<button class="btn btn-link" data-action="rejectInvite" data-group="${groupObj.displayName}">[[groups:membership.reject]]</button><button class="btn btn-success" data-action="acceptInvite" data-group="${groupObj.name}"><i class="fa fa-plus"></i> [[groups:membership.accept-invitation]]</button>`; return `<button class="btn btn-warning" data-action="rejectInvite" data-group="${groupObj.displayName}">[[groups:membership.reject]]</button><button class="btn btn-success" data-action="acceptInvite" data-group="${groupObj.name}"><i class="fa fa-plus"></i> [[groups:membership.accept-invitation]]</button>`;
} else if (!groupObj.disableJoinRequests && groupObj.name !== 'administrators') { } else if (!groupObj.disableJoinRequests && groupObj.name !== 'administrators') {
return `<button class="btn btn-success" data-action="join" data-group="${groupObj.displayName}"><i class="fa fa-plus"></i> [[groups:membership.join-group]]</button>`; return `<button class="btn btn-success" data-action="join" data-group="${groupObj.displayName}"><i class="fa fa-plus"></i> [[groups:membership.join-group]]</button>`;
} }