nodebb-plugin-admin-chats 1.1.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.vscode/settings.json +3 -0
- package/README.md +56 -56
- package/client.js +387 -260
- package/library.js +450 -372
- package/package.json +12 -12
- package/plugin.json +64 -19
- package/public/languages/en-GB/admin-chats.json +9 -0
- package/public/languages/he/admin-chats.json +9 -0
package/client.js
CHANGED
|
@@ -1,260 +1,387 @@
|
|
|
1
|
-
$(document).ready(function() {
|
|
2
|
-
const LOCK_PREFIX = '[admin-chat-lock]';
|
|
3
|
-
const
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
const
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
const
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
}
|
|
1
|
+
$(document).ready(function() {
|
|
2
|
+
const LOCK_PREFIX = '[admin-chat-lock]';
|
|
3
|
+
const roomStateCache = new Map();
|
|
4
|
+
const TEXT = {
|
|
5
|
+
he: {
|
|
6
|
+
lockBanner: '🔒 חדר זה ננעל ע"י המנהלים.',
|
|
7
|
+
menuLock: 'נעל חדר',
|
|
8
|
+
menuRelease: 'שחרר נעילה',
|
|
9
|
+
updateError: 'לא ניתן לעדכן את נעילת החדר.',
|
|
10
|
+
viewChats: "צפיה בצ'אטים",
|
|
11
|
+
emptyState: "אנא בחר צ'אט מסרגל הצד.",
|
|
12
|
+
lockedAction: 'לא ניתן לבצע פעולה זו בחדר נעול',
|
|
13
|
+
},
|
|
14
|
+
en: {
|
|
15
|
+
lockBanner: '🔒 This room was locked by the administrators.',
|
|
16
|
+
menuLock: 'Lock Room',
|
|
17
|
+
menuRelease: 'Release Lock',
|
|
18
|
+
updateError: 'Unable to update room lock.',
|
|
19
|
+
viewChats: 'View Chats',
|
|
20
|
+
emptyState: 'Please select a chat from the sidebar.',
|
|
21
|
+
lockedAction: 'This action cannot be performed in a locked room.',
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
function isEnglishSystem() {
|
|
26
|
+
return $('html').attr('lang') && $('html').attr('lang').startsWith('en');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function t(key) {
|
|
30
|
+
const dict = isEnglishSystem() ? TEXT.en : TEXT.he;
|
|
31
|
+
return dict[key];
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function replaceAdminEmptyStateText() {
|
|
35
|
+
if (!app.user.isAdmin) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
$('span.text-muted.text-sm').each(function() {
|
|
40
|
+
const currentText = $(this).text().trim();
|
|
41
|
+
if (
|
|
42
|
+
currentText.includes("אין לכם צ'אטים פעילים") ||
|
|
43
|
+
currentText === "אין לכם צ'אטים פעילים." ||
|
|
44
|
+
currentText.includes('You have no active chats') ||
|
|
45
|
+
currentText === 'You have no active chats.'
|
|
46
|
+
) {
|
|
47
|
+
$(this).text(t('emptyState'));
|
|
48
|
+
$(this).removeClass('text-muted');
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function getChatWindows() {
|
|
54
|
+
return $('[component="chat/message/window"]');
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function getWindowRoomId($window) {
|
|
58
|
+
const roomId = $window.find('[component="chat/messages"]').first().attr('data-roomid') ||
|
|
59
|
+
$window.closest('.chat-modal').attr('data-roomid') ||
|
|
60
|
+
(ajaxify && ajaxify.data && ajaxify.data.roomId);
|
|
61
|
+
return parseInt(roomId, 10) || 0;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function getCachedRoomData(roomId) {
|
|
65
|
+
const cached = roomStateCache.get(String(roomId));
|
|
66
|
+
if (!cached) {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
if (Date.now() - cached.timestamp > 10000) {
|
|
70
|
+
roomStateCache.delete(String(roomId));
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
return cached.data;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function setCachedRoomData(roomId, data) {
|
|
77
|
+
roomStateCache.set(String(roomId), {
|
|
78
|
+
data,
|
|
79
|
+
timestamp: Date.now(),
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
async function fetchRoomData(roomId) {
|
|
84
|
+
if (!roomId) {
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const currentRoom = ajaxify && ajaxify.data && (ajaxify.data.room || ajaxify.data);
|
|
89
|
+
if (currentRoom && parseInt(currentRoom.roomId, 10) === roomId && currentRoom.adminChatLock) {
|
|
90
|
+
setCachedRoomData(roomId, currentRoom);
|
|
91
|
+
return currentRoom;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const cached = getCachedRoomData(roomId);
|
|
95
|
+
if (cached) {
|
|
96
|
+
return cached;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const response = await fetch(`${config.relative_path || ''}/api/chats/${roomId}`, {
|
|
100
|
+
headers: {
|
|
101
|
+
'x-csrf-token': config.csrf_token,
|
|
102
|
+
},
|
|
103
|
+
credentials: 'same-origin',
|
|
104
|
+
});
|
|
105
|
+
if (!response.ok) {
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const payload = await response.json();
|
|
110
|
+
const roomData = payload && payload.roomId ? payload : (payload && payload.room ? payload.room : null);
|
|
111
|
+
if (roomData) {
|
|
112
|
+
setCachedRoomData(roomId, roomData);
|
|
113
|
+
}
|
|
114
|
+
return roomData;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function isLockedForUser(roomData) {
|
|
118
|
+
return !!(roomData && roomData.adminChatLock && roomData.adminChatLock.isLocked && !(app.user && app.user.isAdmin));
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function setComposerHidden($window, hidden) {
|
|
122
|
+
$window.find('[component="chat/composer"]').each(function() {
|
|
123
|
+
const $composer = $(this);
|
|
124
|
+
if (hidden) {
|
|
125
|
+
$composer.addClass('hidden').hide();
|
|
126
|
+
} else {
|
|
127
|
+
$composer.removeClass('hidden').show();
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
$window.find('[component="chat/input"], [component="chat/send"], button[data-action="send"], textarea.chat-input')
|
|
132
|
+
.prop('disabled', hidden)
|
|
133
|
+
.attr('disabled', hidden ? 'disabled' : null);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function renderLockBanner($window, hidden) {
|
|
137
|
+
$window.find('.admin-chat-lock-banner').remove();
|
|
138
|
+
if (!hidden) {
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const target = $window.find('[component="chat/messages"]').first();
|
|
143
|
+
if (!target.length) {
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const positionStyle = isEnglishSystem() ? 'float:right; clear:both;' : 'float:left; clear:both;';
|
|
148
|
+
target.prepend(`<div class="admin-chat-lock-banner alert alert-warning mb-2 text-start" style="${positionStyle} max-width: fit-content;">${t('lockBanner')}</div>`);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function updateLockedActionVisibility($window, hidden) {
|
|
152
|
+
[
|
|
153
|
+
'[data-action="reply"]',
|
|
154
|
+
'[data-action="edit"]',
|
|
155
|
+
'[data-action="delete"]',
|
|
156
|
+
'[data-action="restore"]',
|
|
157
|
+
'[data-action="kick"]',
|
|
158
|
+
'[data-action="toggleOwner"]'
|
|
159
|
+
].forEach(function(selector) {
|
|
160
|
+
$window.find(selector).toggleClass('hidden', hidden).toggle(!hidden);
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
$window.find('[component="chat/controlsToggle"]').closest('.dropdown').toggleClass('hidden', hidden).toggle(!hidden);
|
|
164
|
+
$window.find('[component="chat/manage/user/add/search"], [component="chat/manage/user/list/search"], [component="chat/manage/save"]')
|
|
165
|
+
.toggleClass('hidden', hidden)
|
|
166
|
+
.toggle(!hidden)
|
|
167
|
+
.prop('disabled', hidden)
|
|
168
|
+
.attr('disabled', hidden ? 'disabled' : null);
|
|
169
|
+
$window.find('[component="chat/manage-modal"] .form-text, [component="chat/manage-modal"] .text-danger')
|
|
170
|
+
.toggleClass('hidden', hidden);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function normalizeLockMessages($window) {
|
|
174
|
+
$window.find('[component="chat/system-message"] > div').each(function() {
|
|
175
|
+
const $el = $(this);
|
|
176
|
+
const text = $el.text().trim();
|
|
177
|
+
if (!text.includes(LOCK_PREFIX.slice(1, -1)) && !text.includes('admin-chat-lock')) {
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
$el.text(t('lockBanner'));
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function getRoomMenuTargets($window) {
|
|
185
|
+
const scoped = $window.find('[component="chat/controls"]');
|
|
186
|
+
if (scoped.length) {
|
|
187
|
+
return scoped;
|
|
188
|
+
}
|
|
189
|
+
return $window.find('[component="chat/header"], .chat-header, .modal-header, [component="chat/nav"]').find('.dropdown-menu');
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function renderAdminLockControl($window, roomData) {
|
|
193
|
+
$window.find('.admin-chat-lock-toggle-item, .admin-chat-lock-divider, .admin-chat-lock-item-wrap').remove();
|
|
194
|
+
|
|
195
|
+
if (!app.user.isAdmin || !roomData || !roomData.roomId) {
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const menus = getRoomMenuTargets($window);
|
|
200
|
+
if (!menus.length) {
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const lockData = roomData.adminChatLock || {};
|
|
205
|
+
const isLocked = !!lockData.isLocked;
|
|
206
|
+
const itemText = isLocked ? t('menuRelease') : t('menuLock');
|
|
207
|
+
const iconClass = isLocked ? 'fa-lock-open' : 'fa-lock';
|
|
208
|
+
const menuItemHtml = `
|
|
209
|
+
<li role="presentation" class="admin-chat-lock-item-wrap">
|
|
210
|
+
<a href="#" role="menuitem" class="dropdown-item rounded-1 d-flex align-items-center gap-2 admin-chat-lock-toggle-item" data-room-id="${roomData.roomId}" data-locked="${isLocked}">
|
|
211
|
+
<i class="fa fa-fw ${iconClass}"></i>
|
|
212
|
+
<span>${itemText}</span>
|
|
213
|
+
</a>
|
|
214
|
+
</li>
|
|
215
|
+
<li role="presentation" class="dropdown-divider admin-chat-lock-divider"></li>
|
|
216
|
+
`;
|
|
217
|
+
|
|
218
|
+
menus.each(function() {
|
|
219
|
+
const $menu = $(this);
|
|
220
|
+
if ($menu.find('.admin-chat-lock-toggle-item').length) {
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
$menu.prepend(menuItemHtml);
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
async function applyUiToWindow($window) {
|
|
228
|
+
const roomId = getWindowRoomId($window);
|
|
229
|
+
if (!roomId) {
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
const roomData = await fetchRoomData(roomId);
|
|
234
|
+
if (!roomData) {
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const hidden = isLockedForUser(roomData);
|
|
239
|
+
setComposerHidden($window, hidden);
|
|
240
|
+
updateLockedActionVisibility($window, hidden);
|
|
241
|
+
renderLockBanner($window, hidden);
|
|
242
|
+
renderAdminLockControl($window, roomData);
|
|
243
|
+
normalizeLockMessages($window);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
async function refreshChatUi() {
|
|
247
|
+
replaceAdminEmptyStateText();
|
|
248
|
+
const windows = getChatWindows();
|
|
249
|
+
await Promise.all(windows.map(function() {
|
|
250
|
+
return applyUiToWindow($(this));
|
|
251
|
+
}).get());
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
async function toggleRoomLock(roomId, nextState) {
|
|
255
|
+
const response = await fetch(`${config.relative_path || ''}/api/admin-chats/${roomId}/lock`, {
|
|
256
|
+
method: 'POST',
|
|
257
|
+
headers: {
|
|
258
|
+
'Content-Type': 'application/json',
|
|
259
|
+
'x-csrf-token': config.csrf_token,
|
|
260
|
+
},
|
|
261
|
+
body: JSON.stringify({ locked: nextState }),
|
|
262
|
+
credentials: 'same-origin',
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
if (!response.ok) {
|
|
266
|
+
throw new Error('Unable to update room lock');
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
return await response.json();
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
$(window).on('action:ajaxify.end', function(ev, data) {
|
|
273
|
+
const templateName = ajaxify && ajaxify.data && ajaxify.data.template ? ajaxify.data.template.name : '';
|
|
274
|
+
|
|
275
|
+
if (app.user.isAdmin && templateName.startsWith('account/')) {
|
|
276
|
+
const userSlug = ajaxify.data.userslug || (ajaxify.data.user && ajaxify.data.user.userslug);
|
|
277
|
+
|
|
278
|
+
if (userSlug) {
|
|
279
|
+
const relativePath = config.relative_path || '';
|
|
280
|
+
const btnHtml = `
|
|
281
|
+
<li role="presentation">
|
|
282
|
+
<a class="dropdown-item rounded-1 d-flex align-items-center gap-2" href="${relativePath}/user/${userSlug}/chats" role="menuitem">
|
|
283
|
+
<i class="far fa-fw fa-comments"></i>
|
|
284
|
+
<span>${t('viewChats')}</span>
|
|
285
|
+
</a>
|
|
286
|
+
</li>
|
|
287
|
+
<li role="presentation" class="dropdown-divider"></li>
|
|
288
|
+
`;
|
|
289
|
+
const menu = $('.account-sub-links');
|
|
290
|
+
if (menu.length) {
|
|
291
|
+
menu.find(`a[href*="/user/${userSlug}/chats"]`).parent().remove();
|
|
292
|
+
menu.prepend(btnHtml);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
const url = data && data.url ? data.url : '';
|
|
298
|
+
if (url.match(/^user\/.+\/chats/) || url === 'chats') {
|
|
299
|
+
refreshChatUi();
|
|
300
|
+
setTimeout(refreshChatUi, 500);
|
|
301
|
+
setTimeout(refreshChatUi, 1200);
|
|
302
|
+
}
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
$(window).on('action:chat.loaded', function() {
|
|
306
|
+
refreshChatUi();
|
|
307
|
+
setTimeout(refreshChatUi, 200);
|
|
308
|
+
setTimeout(refreshChatUi, 1000);
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
$(window).on('action:chat.closed', function() {
|
|
312
|
+
setTimeout(refreshChatUi, 200);
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
$(window).on('action:chat.onMessagesAddedToDom action:chat.edited action:chat.renamed', function() {
|
|
316
|
+
setTimeout(refreshChatUi, 0);
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
$(document).on('click', '.admin-chat-lock-toggle-item', async function(ev) {
|
|
320
|
+
ev.preventDefault();
|
|
321
|
+
|
|
322
|
+
const $button = $(this);
|
|
323
|
+
const roomId = parseInt($button.attr('data-room-id'), 10);
|
|
324
|
+
const isLocked = $button.attr('data-locked') === 'true';
|
|
325
|
+
|
|
326
|
+
if (!roomId) {
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
$button.addClass('disabled').attr('aria-disabled', 'true');
|
|
331
|
+
|
|
332
|
+
try {
|
|
333
|
+
const result = await toggleRoomLock(roomId, !isLocked);
|
|
334
|
+
const currentRoom = ajaxify && ajaxify.data && (ajaxify.data.room || ajaxify.data);
|
|
335
|
+
if (currentRoom && parseInt(currentRoom.roomId, 10) === roomId) {
|
|
336
|
+
currentRoom.adminChatLock = result.lockData;
|
|
337
|
+
currentRoom.canReply = !result.lockData.isLocked || (app.user && app.user.isAdmin);
|
|
338
|
+
currentRoom.showUserInput = currentRoom.canReply;
|
|
339
|
+
if (ajaxify.data.room) {
|
|
340
|
+
ajaxify.data.room.adminChatLock = result.lockData;
|
|
341
|
+
ajaxify.data.room.canReply = currentRoom.canReply;
|
|
342
|
+
ajaxify.data.room.showUserInput = currentRoom.showUserInput;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
const cached = getCachedRoomData(roomId) || { roomId };
|
|
347
|
+
cached.adminChatLock = result.lockData;
|
|
348
|
+
cached.canReply = !result.lockData.isLocked || (app.user && app.user.isAdmin);
|
|
349
|
+
cached.showUserInput = cached.canReply;
|
|
350
|
+
setCachedRoomData(roomId, cached);
|
|
351
|
+
await refreshChatUi();
|
|
352
|
+
} catch (err) {
|
|
353
|
+
app.alertError(t('updateError'));
|
|
354
|
+
$button.removeClass('disabled').removeAttr('aria-disabled');
|
|
355
|
+
}
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
// Intercept error alerts to translate locked action errors
|
|
359
|
+
if (app && app.alertError) {
|
|
360
|
+
const originalAlertError = app.alertError;
|
|
361
|
+
app.alertError = function(error) {
|
|
362
|
+
let message = error;
|
|
363
|
+
if (typeof error === 'object' && error.message) {
|
|
364
|
+
message = error.message;
|
|
365
|
+
}
|
|
366
|
+
if (typeof message === 'string' && message.includes('admin-chats:errors.lockedAction')) {
|
|
367
|
+
message = t('lockedAction');
|
|
368
|
+
}
|
|
369
|
+
return originalAlertError.call(this, message);
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// Intercept and translate error messages from API
|
|
374
|
+
if (app.alertError && !app.alertError._adminChatsWrapped) {
|
|
375
|
+
const originalAlertError = app.alertError;
|
|
376
|
+
app.alertError = function(message) {
|
|
377
|
+
if (typeof message === 'string') {
|
|
378
|
+
// Check if message contains translation key
|
|
379
|
+
if (message.includes('[[admin-chats:errors.lockedAction]]') || message.includes('errors.lockedAction')) {
|
|
380
|
+
message = t('lockedAction');
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
return originalAlertError.call(this, message);
|
|
384
|
+
};
|
|
385
|
+
app.alertError._adminChatsWrapped = true;
|
|
386
|
+
}
|
|
387
|
+
});
|