nodebb-plugin-simple-contact 1.2.2 → 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/library.js +145 -95
- package/package.json +1 -1
- package/public/templates/admin/plugins/contact.tpl +208 -54
- package/public/templates/contact.tpl +45 -21
package/library.js
CHANGED
|
@@ -4,6 +4,16 @@ const db = require.main.require('./src/database');
|
|
|
4
4
|
const notifications = require.main.require('./src/notifications');
|
|
5
5
|
const groups = require.main.require('./src/groups');
|
|
6
6
|
const socketIndex = require.main.require('./src/socket.io/index');
|
|
7
|
+
const emailer = require.main.require('./src/emailer');
|
|
8
|
+
const user = require.main.require('./src/user');
|
|
9
|
+
|
|
10
|
+
let chats = null;
|
|
11
|
+
let messaging = null;
|
|
12
|
+
|
|
13
|
+
const possiblePaths = ['./src/chats', './src/messaging'];
|
|
14
|
+
|
|
15
|
+
try { chats = require.main.require('./src/chats'); } catch (e) {}
|
|
16
|
+
try { messaging = require.main.require('./src/messaging'); } catch (e) {}
|
|
7
17
|
|
|
8
18
|
const ContactPlugin = {};
|
|
9
19
|
|
|
@@ -19,16 +29,115 @@ ContactPlugin.init = async function (params) {
|
|
|
19
29
|
router.get('/api/admin/plugins/contact', renderAdminPage);
|
|
20
30
|
router.post('/api/admin/plugins/contact/handle', middleware.admin.buildHeader, markAsHandled);
|
|
21
31
|
router.post('/api/admin/plugins/contact/delete', middleware.admin.buildHeader, deleteRequest);
|
|
32
|
+
router.post('/api/admin/plugins/contact/reply', middleware.admin.buildHeader, replyToContact);
|
|
33
|
+
router.post('/api/admin/plugins/contact/chat', middleware.admin.buildHeader, getChatRoom);
|
|
22
34
|
};
|
|
23
35
|
|
|
36
|
+
async function getChatRoom(req, res) {
|
|
37
|
+
if (!chats && !messaging) {
|
|
38
|
+
return res.status(500).json({ error: 'מודולי הצ\'אט לא נמצאו בשרת.' });
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const { touid, title, firstMessage } = req.body;
|
|
42
|
+
const myUid = req.uid;
|
|
43
|
+
|
|
44
|
+
if (!touid) {
|
|
45
|
+
return res.status(400).json({ error: 'חסר מזהה משתמש (UID)' });
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
try {
|
|
49
|
+
let roomId = null;
|
|
50
|
+
|
|
51
|
+
const chatModule = chats || messaging; // עדיפות ל-chats ליצירת חדר
|
|
52
|
+
|
|
53
|
+
if (chatModule.getRoomId) {
|
|
54
|
+
roomId = await chatModule.getRoomId(myUid, touid);
|
|
55
|
+
} else if (chatModule.getRoomIdForUser) {
|
|
56
|
+
roomId = await chatModule.getRoomIdForUser(myUid, touid);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (!roomId) {
|
|
60
|
+
if (chatModule.create) {
|
|
61
|
+
const newRoom = await chatModule.create([myUid, touid]);
|
|
62
|
+
roomId = (newRoom && newRoom.roomId) ? newRoom.roomId : newRoom;
|
|
63
|
+
} else if (chatModule.newRoom) {
|
|
64
|
+
roomId = await chatModule.newRoom(myUid, [touid]);
|
|
65
|
+
} else if (chatModule.createRoom) {
|
|
66
|
+
roomId = await chatModule.createRoom([myUid, touid]);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (!roomId) {
|
|
71
|
+
throw new Error('לא ניתן היה ליצור את החדר');
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (typeof roomId === 'object' && roomId.roomId) {
|
|
75
|
+
roomId = roomId.roomId;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (title) {
|
|
79
|
+
try {
|
|
80
|
+
if (chats && chats.renameRoom) {
|
|
81
|
+
await chats.renameRoom(myUid, roomId, title);
|
|
82
|
+
} else if (messaging && messaging.renameRoom) {
|
|
83
|
+
await messaging.renameRoom(myUid, roomId, title);
|
|
84
|
+
}
|
|
85
|
+
} catch (err) {
|
|
86
|
+
console.warn('[Contact Plugin] Failed to rename room:', err.message);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (firstMessage) {
|
|
91
|
+
let sent = false;
|
|
92
|
+
console.log('[Contact Plugin] Attempting to send message to Room ' + roomId);
|
|
93
|
+
|
|
94
|
+
if (!sent && messaging && messaging.sendMessage) {
|
|
95
|
+
try {
|
|
96
|
+
await messaging.sendMessage({ uid: myUid, roomId: roomId, content: firstMessage });
|
|
97
|
+
sent = true;
|
|
98
|
+
console.log('[Contact Plugin] Sent via messaging.sendMessage (Object)');
|
|
99
|
+
} catch (e) { console.log('Try 1 failed:', e.message); }
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (!sent && chats && chats.addMessage) {
|
|
103
|
+
try {
|
|
104
|
+
await chats.addMessage(myUid, roomId, firstMessage);
|
|
105
|
+
sent = true;
|
|
106
|
+
console.log('[Contact Plugin] Sent via chats.addMessage');
|
|
107
|
+
} catch (e) { console.log('Try 2 failed:', e.message); }
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (!sent && chats && chats.send) {
|
|
111
|
+
try {
|
|
112
|
+
await chats.send(myUid, roomId, firstMessage);
|
|
113
|
+
sent = true;
|
|
114
|
+
console.log('[Contact Plugin] Sent via chats.send');
|
|
115
|
+
} catch (e) { console.log('Try 3 failed:', e.message); }
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (!sent && chats && chats.reply) {
|
|
119
|
+
try {
|
|
120
|
+
await chats.reply(roomId, myUid, firstMessage);
|
|
121
|
+
sent = true;
|
|
122
|
+
console.log('[Contact Plugin] Sent via chats.reply');
|
|
123
|
+
} catch (e) { console.log('Try 4 failed:', e.message); }
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (!sent) {
|
|
127
|
+
console.error('[Contact Plugin] Failed to send message with all known methods.');
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
res.json({ roomId: roomId });
|
|
132
|
+
|
|
133
|
+
} catch (err) {
|
|
134
|
+
console.error('[Contact Plugin Chat Error]', err);
|
|
135
|
+
res.status(500).json({ error: 'שגיאה פנימית: ' + err.message });
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
24
139
|
async function renderContactPage(req, res) {
|
|
25
|
-
res.render('contact', {
|
|
26
|
-
title: 'צור קשר',
|
|
27
|
-
breadcrumbs: [
|
|
28
|
-
{ text: 'דף הבית', url: '/' },
|
|
29
|
-
{ text: 'צור קשר' }
|
|
30
|
-
]
|
|
31
|
-
});
|
|
140
|
+
res.render('contact', { title: 'צור קשר', breadcrumbs: [{ text: 'דף הבית', url: '/' }, { text: 'צור קשר' }] });
|
|
32
141
|
}
|
|
33
142
|
|
|
34
143
|
async function handleContactSubmission(req, res) {
|
|
@@ -39,11 +148,13 @@ async function handleContactSubmission(req, res) {
|
|
|
39
148
|
|
|
40
149
|
const contactId = Date.now();
|
|
41
150
|
const key = 'contact-request:' + contactId;
|
|
151
|
+
const senderUid = req.uid || 0;
|
|
42
152
|
|
|
43
153
|
const contactData = {
|
|
44
154
|
id: contactId,
|
|
45
155
|
fullName: data.fullName,
|
|
46
156
|
username: data.username || 'אורח',
|
|
157
|
+
uid: senderUid,
|
|
47
158
|
email: data.email,
|
|
48
159
|
content: data.content,
|
|
49
160
|
timestamp: contactId,
|
|
@@ -55,35 +166,19 @@ async function handleContactSubmission(req, res) {
|
|
|
55
166
|
await db.sortedSetAdd('contact-requests:sorted', contactId, contactId);
|
|
56
167
|
|
|
57
168
|
const adminUids = await groups.getMembers('administrators', 0, -1);
|
|
58
|
-
|
|
59
169
|
if (adminUids && adminUids.length > 0) {
|
|
60
170
|
await Promise.all(adminUids.map(async (uid) => {
|
|
61
171
|
const userUnreadKey = 'contact:unread_names:' + uid;
|
|
62
172
|
const userNid = 'contact:notification:' + uid;
|
|
63
|
-
|
|
64
173
|
await db.listAppend(userUnreadKey, contactData.fullName);
|
|
65
174
|
const myNames = await db.getListRange(userUnreadKey, 0, -1);
|
|
66
|
-
|
|
67
|
-
let notificationTitle = '';
|
|
68
|
-
if (myNames.length === 1) {
|
|
69
|
-
notificationTitle = `פנייה חדשה מאת ${myNames[0]}`;
|
|
70
|
-
} else {
|
|
71
|
-
notificationTitle = `${myNames.length} פניות חדשות מאת: ${myNames.join(', ')}`;
|
|
72
|
-
}
|
|
73
|
-
|
|
175
|
+
let notificationTitle = (myNames.length === 1) ? `פנייה חדשה מאת ${myNames[0]}` : `${myNames.length} פניות חדשות מאת: ${myNames.join(', ')}`;
|
|
74
176
|
const notification = await notifications.create({
|
|
75
|
-
type: 'new-contact',
|
|
76
|
-
bodyShort: notificationTitle,
|
|
77
|
-
bodyLong: contactData.content,
|
|
78
|
-
nid: userNid,
|
|
79
|
-
path: '/admin/plugins/contact',
|
|
80
|
-
from: 0
|
|
177
|
+
type: 'new-contact', bodyShort: notificationTitle, bodyLong: contactData.content, nid: userNid, path: '/admin/plugins/contact', from: senderUid
|
|
81
178
|
});
|
|
82
|
-
|
|
83
179
|
await notifications.push(notification, [uid]);
|
|
84
180
|
}));
|
|
85
181
|
}
|
|
86
|
-
|
|
87
182
|
res.json({ success: true, message: 'הפנייה נשלחה בהצלחה.' });
|
|
88
183
|
} catch (err) {
|
|
89
184
|
console.error(err);
|
|
@@ -96,90 +191,45 @@ async function renderAdminPage(req, res) {
|
|
|
96
191
|
try {
|
|
97
192
|
const userUnreadKey = 'contact:unread_names:' + req.uid;
|
|
98
193
|
const userNid = 'contact:notification:' + req.uid;
|
|
99
|
-
|
|
100
194
|
await notifications.markRead(userNid, req.uid);
|
|
101
|
-
|
|
102
195
|
await db.delete(userUnreadKey);
|
|
103
|
-
|
|
104
|
-
const unreadCount = await notifications.getUnreadCount(req.uid);
|
|
105
|
-
|
|
106
|
-
socketIndex.in('uid:' + req.uid).emit('event:unread.updateCount', unreadCount);
|
|
107
|
-
|
|
108
|
-
socketIndex.in('uid:' + req.uid).emit('event:notifications.updateCount', unreadCount);
|
|
109
|
-
|
|
110
|
-
} catch (e) {
|
|
111
|
-
console.error('Error handling notifications logic', e);
|
|
112
|
-
}
|
|
196
|
+
} catch (e) { console.error('Error handling notifications logic', e); }
|
|
113
197
|
}
|
|
114
|
-
|
|
115
198
|
const ids = await db.getSortedSetRevRange('contact-requests:sorted', 0, -1);
|
|
116
|
-
let items = [];
|
|
117
|
-
|
|
118
|
-
if (ids.length > 0) {
|
|
119
|
-
const keys = ids.map(id => 'contact-request:' + id);
|
|
120
|
-
items = await db.getObjects(keys);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
const waitingRequests = [];
|
|
124
|
-
const handledRequests = [];
|
|
199
|
+
let items = (ids.length > 0) ? await db.getObjects(ids.map(id => 'contact-request:' + id)) : [];
|
|
200
|
+
const waitingRequests = [], handledRequests = [];
|
|
125
201
|
|
|
126
|
-
|
|
202
|
+
for (const item of items) {
|
|
127
203
|
item.date = new Date(parseInt(item.timestamp)).toLocaleString();
|
|
128
|
-
if (item.
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
});
|
|
204
|
+
if ((!item.uid || parseInt(item.uid) === 0) && item.username && item.username !== 'אורח') {
|
|
205
|
+
try {
|
|
206
|
+
const foundUid = await user.getUidByUsername(item.username);
|
|
207
|
+
item.uid = foundUid ? parseInt(foundUid) : 0;
|
|
208
|
+
} catch (err) { item.uid = 0; }
|
|
209
|
+
} else { item.uid = parseInt(item.uid) || 0; }
|
|
210
|
+
item.showChat = (item.uid > 0);
|
|
211
|
+
if (item.handled) handledRequests.push(item); else waitingRequests.push(item);
|
|
212
|
+
}
|
|
213
|
+
res.render('admin/plugins/contact', { waitingRequests: waitingRequests, handledRequests: handledRequests });
|
|
139
214
|
}
|
|
140
215
|
|
|
141
216
|
async function markAsHandled(req, res) {
|
|
142
|
-
|
|
143
|
-
try {
|
|
144
|
-
await db.setObjectField('contact-request:' + id, 'handled', true);
|
|
145
|
-
res.json({ success: true });
|
|
146
|
-
} catch (err) {
|
|
147
|
-
res.status(500).json({ error: err.message });
|
|
148
|
-
}
|
|
217
|
+
try { await db.setObjectField('contact-request:' + req.body.id, 'handled', true); res.json({ success: true }); } catch (err) { res.status(500).json({ error: err.message }); }
|
|
149
218
|
}
|
|
150
|
-
|
|
151
219
|
async function deleteRequest(req, res) {
|
|
152
|
-
|
|
220
|
+
try { await db.delete('contact-request:' + req.body.id); await db.sortedSetRemove('contact-requests:sorted', req.body.id); res.json({ success: true }); } catch (err) { res.status(500).json({ error: err.message }); }
|
|
221
|
+
}
|
|
222
|
+
async function replyToContact(req, res) {
|
|
223
|
+
const { email, subject, content, original_id } = req.body;
|
|
224
|
+
if (!email || !content) return res.status(400).json({ error: 'חסרים נתונים לשליחה' });
|
|
153
225
|
try {
|
|
154
|
-
await
|
|
155
|
-
await db.
|
|
226
|
+
await emailer.sendToEmail('banned', email, 'he', { subject: subject || 'תשובה', username: email, message: content.replace(/\n/g, '<br>'), body: content.replace(/\n/g, '<br>') });
|
|
227
|
+
if (original_id) await db.setObjectField('contact-request:' + original_id, 'handled', true);
|
|
156
228
|
res.json({ success: true });
|
|
157
|
-
} catch (err) {
|
|
158
|
-
res.status(500).json({ error: err.message });
|
|
159
|
-
}
|
|
229
|
+
} catch (err) { res.status(500).json({ error: err.message }); }
|
|
160
230
|
}
|
|
161
231
|
|
|
162
|
-
ContactPlugin.addNavigation = async function (header) {
|
|
163
|
-
|
|
164
|
-
header.navigation.push({
|
|
165
|
-
route: '/contact',
|
|
166
|
-
iconClass: 'fa-envelope',
|
|
167
|
-
text: 'צור קשר',
|
|
168
|
-
title: 'צור קשר'
|
|
169
|
-
});
|
|
170
|
-
}
|
|
171
|
-
return header;
|
|
172
|
-
};
|
|
173
|
-
|
|
174
|
-
ContactPlugin.addAdminNavigation = async function (header) {
|
|
175
|
-
if (header && Array.isArray(header.plugins)) {
|
|
176
|
-
header.plugins.push({
|
|
177
|
-
route: '/plugins/contact',
|
|
178
|
-
icon: 'fa-envelope',
|
|
179
|
-
name: 'פניות צור קשר'
|
|
180
|
-
});
|
|
181
|
-
}
|
|
182
|
-
return header;
|
|
183
|
-
};
|
|
232
|
+
ContactPlugin.addNavigation = async function (header) { if (header && Array.isArray(header.navigation)) { header.navigation.push({ route: '/contact', iconClass: 'fa-envelope', text: 'צור קשר', title: 'צור קשר' }); } return header; };
|
|
233
|
+
ContactPlugin.addAdminNavigation = async function (header) { if (header && Array.isArray(header.plugins)) { header.plugins.push({ route: '/plugins/contact', icon: 'fa-envelope', name: 'פניות צור קשר' }); } return header; };
|
|
184
234
|
|
|
185
235
|
module.exports = ContactPlugin;
|
package/package.json
CHANGED
|
@@ -26,7 +26,15 @@
|
|
|
26
26
|
<tr data-id="{./id}" class="text-center">
|
|
27
27
|
<td>{./date}</td>
|
|
28
28
|
<td><strong>{./fullName}</strong></td>
|
|
29
|
-
<td>
|
|
29
|
+
<td>
|
|
30
|
+
{{{ if ./showChat }}}
|
|
31
|
+
<a href="{config.relative_path}/admin/manage/users?searchBy=uid&query={./uid}&page=1&sortBy=lastonline" target="_blank" title="ניהול משתמש">
|
|
32
|
+
{./username}
|
|
33
|
+
</a>
|
|
34
|
+
{{{ else }}}
|
|
35
|
+
{./username}
|
|
36
|
+
{{{ end }}}
|
|
37
|
+
</td>
|
|
30
38
|
<td><a href="mailto:{./email}">{./email}</a></td>
|
|
31
39
|
<td style="max-width:260px;">
|
|
32
40
|
<div class="toggle-text" style="white-space:nowrap; overflow:hidden; text-overflow:ellipsis; cursor:pointer;" title="לחץ להצגה/הסתרה">
|
|
@@ -36,10 +44,22 @@
|
|
|
36
44
|
<td>
|
|
37
45
|
<span class="label label-warning" style="border-radius:10px; padding:3px 6px; font-size:11px;">ממתין</span>
|
|
38
46
|
</td>
|
|
39
|
-
<td class="text-
|
|
40
|
-
<
|
|
41
|
-
|
|
42
|
-
|
|
47
|
+
<td class="text-left">
|
|
48
|
+
<div class="btn-group btn-group-sm">
|
|
49
|
+
{{{ if ./showChat }}}
|
|
50
|
+
<button class="btn btn-success reply-chat" data-uid="{./uid}" style="margin-left:2px; border-radius:4px;">
|
|
51
|
+
<i class="fa fa-comments"></i> השב בצאט
|
|
52
|
+
</button>
|
|
53
|
+
{{{ end }}}
|
|
54
|
+
|
|
55
|
+
<button class="btn btn-info reply-email" data-id="{./id}" data-email="{./email}" style="margin-left:2px; border-radius:4px;">
|
|
56
|
+
<i class="fa fa-envelope-o"></i> השב במייל
|
|
57
|
+
</button>
|
|
58
|
+
|
|
59
|
+
<button class="btn btn-primary mark-handled" data-id="{./id}" style="border-radius:4px;">
|
|
60
|
+
✓ סמן כטופל
|
|
61
|
+
</button>
|
|
62
|
+
</div>
|
|
43
63
|
</td>
|
|
44
64
|
</tr>
|
|
45
65
|
{{{ end }}}
|
|
@@ -81,7 +101,15 @@
|
|
|
81
101
|
<tr data-id="{./id}" class="text-center">
|
|
82
102
|
<td>{./date}</td>
|
|
83
103
|
<td><strong>{./fullName}</strong></td>
|
|
84
|
-
<td>
|
|
104
|
+
<td>
|
|
105
|
+
{{{ if ./showChat }}}
|
|
106
|
+
<a href="{config.relative_path}/admin/manage/users?searchBy=uid&query={./uid}&page=1&sortBy=lastonline" target="_blank" title="ניהול משתמש">
|
|
107
|
+
{./username}
|
|
108
|
+
</a>
|
|
109
|
+
{{{ else }}}
|
|
110
|
+
{./username}
|
|
111
|
+
{{{ end }}}
|
|
112
|
+
</td>
|
|
85
113
|
<td><a href="mailto:{./email}">{./email}</a></td>
|
|
86
114
|
<td style="max-width:260px;">
|
|
87
115
|
<div class="toggle-text" style="white-space:nowrap; overflow:hidden; text-overflow:ellipsis; cursor:pointer;" title="לחץ להצגה/הסתרה">
|
|
@@ -108,8 +136,69 @@
|
|
|
108
136
|
{{{ end }}}
|
|
109
137
|
</div>
|
|
110
138
|
</div>
|
|
139
|
+
</div>
|
|
140
|
+
</div>
|
|
111
141
|
|
|
142
|
+
<div id="emailReplyModal" class="modal fade" tabindex="-1" role="dialog">
|
|
143
|
+
<div class="modal-dialog" role="document">
|
|
144
|
+
<div class="modal-content">
|
|
145
|
+
<div class="modal-header">
|
|
146
|
+
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
|
147
|
+
<h4 class="modal-title">תשובה לפנייה במייל</h4>
|
|
148
|
+
</div>
|
|
149
|
+
<div class="modal-body">
|
|
150
|
+
<form id="emailReplyForm">
|
|
151
|
+
<input type="hidden" id="reply-id" name="id">
|
|
152
|
+
<input type="hidden" id="reply-to">
|
|
153
|
+
<div class="form-group">
|
|
154
|
+
<label>נושא:</label>
|
|
155
|
+
<input type="text" class="form-control" id="reply-subject" value="תשובה לפנייתך בצור קשר">
|
|
156
|
+
</div>
|
|
157
|
+
<div class="form-group">
|
|
158
|
+
<label>תוכן ההודעה:</label>
|
|
159
|
+
<textarea class="form-control" id="reply-content" rows="6"></textarea>
|
|
160
|
+
</div>
|
|
161
|
+
</form>
|
|
162
|
+
</div>
|
|
163
|
+
<div class="modal-footer">
|
|
164
|
+
<button type="button" class="btn btn-default" data-dismiss="modal">ביטול</button>
|
|
165
|
+
<button type="button" class="btn btn-primary" id="send-reply-btn">שלח מייל</button>
|
|
166
|
+
</div>
|
|
112
167
|
</div>
|
|
168
|
+
</div>
|
|
169
|
+
</div>
|
|
170
|
+
|
|
171
|
+
<div id="chatReplyModal" class="modal fade" tabindex="-1" role="dialog">
|
|
172
|
+
<div class="modal-dialog" role="document">
|
|
173
|
+
<div class="modal-content">
|
|
174
|
+
<div class="modal-header">
|
|
175
|
+
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
|
176
|
+
<h4 class="modal-title">פתיחת צ'אט ושליחת הודעה</h4>
|
|
177
|
+
</div>
|
|
178
|
+
<div class="modal-body">
|
|
179
|
+
<form id="chatReplyForm">
|
|
180
|
+
<input type="hidden" id="chat-uid">
|
|
181
|
+
<input type="hidden" id="chat-original-id"> <div class="form-group">
|
|
182
|
+
<label>כותרת הצ'אט:</label>
|
|
183
|
+
<input type="text" class="form-control" id="chat-title-input">
|
|
184
|
+
<p class="help-block" style="font-size:12px;">שם החדר ישתנה לכותרת זו.</p>
|
|
185
|
+
</div>
|
|
186
|
+
|
|
187
|
+
<div class="form-group">
|
|
188
|
+
<label>הודעה:</label>
|
|
189
|
+
<textarea class="form-control" id="chat-message-input" rows="4"></textarea>
|
|
190
|
+
<p class="help-block" style="font-size:12px;">הודעה זו תישלח אוטומטית למשתמש.</p>
|
|
191
|
+
</div>
|
|
192
|
+
</form>
|
|
193
|
+
</div>
|
|
194
|
+
<div class="modal-footer">
|
|
195
|
+
<button type="button" class="btn btn-default" data-dismiss="modal">ביטול</button>
|
|
196
|
+
<button type="button" class="btn btn-success" id="create-chat-btn">
|
|
197
|
+
<i class="fa fa-paper-plane"></i> שלח הודעת צ'אט
|
|
198
|
+
</button>
|
|
199
|
+
</div>
|
|
200
|
+
</div>
|
|
201
|
+
</div>
|
|
113
202
|
</div>
|
|
114
203
|
|
|
115
204
|
<script>
|
|
@@ -123,17 +212,7 @@
|
|
|
123
212
|
if (window.app && typeof window.app.require === 'function') {
|
|
124
213
|
window.app.require('alerts').then(function(alerts) {
|
|
125
214
|
type === 'success' ? alerts.success(clean) : alerts.error(clean);
|
|
126
|
-
}).catch(function() {
|
|
127
|
-
alert(clean);
|
|
128
|
-
});
|
|
129
|
-
return;
|
|
130
|
-
}
|
|
131
|
-
const req = window.require || window.requirejs;
|
|
132
|
-
if (req) {
|
|
133
|
-
req(['alerts'], function(alerts) {
|
|
134
|
-
if (!alerts) return alert(clean);
|
|
135
|
-
type === 'success' ? alerts.success(clean) : alerts.error(clean);
|
|
136
|
-
});
|
|
215
|
+
}).catch(function() { alert(clean); });
|
|
137
216
|
return;
|
|
138
217
|
}
|
|
139
218
|
alert(clean);
|
|
@@ -152,6 +231,108 @@
|
|
|
152
231
|
}
|
|
153
232
|
|
|
154
233
|
function initContactPage() {
|
|
234
|
+
|
|
235
|
+
$('.reply-chat').off('click').on('click', function(e) {
|
|
236
|
+
e.preventDefault();
|
|
237
|
+
var btn = $(this);
|
|
238
|
+
var uid = btn.data('uid') || btn.attr('data-uid');
|
|
239
|
+
var originalId = btn.closest('tr').attr('data-id');
|
|
240
|
+
|
|
241
|
+
if (!uid || uid == 0) {
|
|
242
|
+
return showMessage('error', 'שגיאה: מזהה משתמש (UID) חסר.');
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
var row = btn.closest('tr');
|
|
246
|
+
var fullName = row.find('strong').text().trim();
|
|
247
|
+
var contentDiv = row.find('.toggle-text');
|
|
248
|
+
var rawContent = contentDiv.text().trim();
|
|
249
|
+
var shortContent = rawContent.length > 50 ? rawContent.substring(0, 50) + '...' : rawContent;
|
|
250
|
+
|
|
251
|
+
$('#chat-uid').val(uid);
|
|
252
|
+
$('#chat-original-id').val(originalId);
|
|
253
|
+
$('#chat-title-input').val('בעניין פנייתך בצור קשר');
|
|
254
|
+
$('#chat-message-input').val('שלום ,\nכהמשך לפנייתך בצור קשר.\nתשובתינו היא:');
|
|
255
|
+
|
|
256
|
+
$('#chatReplyModal').modal('show');
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
$('#create-chat-btn').off('click').on('click', function() {
|
|
260
|
+
var btn = $(this);
|
|
261
|
+
var uid = $('#chat-uid').val();
|
|
262
|
+
var title = $('#chat-title-input').val();
|
|
263
|
+
var message = $('#chat-message-input').val();
|
|
264
|
+
|
|
265
|
+
if (!uid) return;
|
|
266
|
+
|
|
267
|
+
btn.prop('disabled', true);
|
|
268
|
+
|
|
269
|
+
$.post(config.relative_path + '/api/admin/plugins/contact/chat', {
|
|
270
|
+
touid: uid,
|
|
271
|
+
title: title,
|
|
272
|
+
firstMessage: message,
|
|
273
|
+
_csrf: config.csrf_token
|
|
274
|
+
})
|
|
275
|
+
.done(function(data) {
|
|
276
|
+
$('#chatReplyModal').modal('hide');
|
|
277
|
+
|
|
278
|
+
if (data && data.roomId) {
|
|
279
|
+
showMessage('success', "הודעת הצ'אט נשלחה בהצלחה");
|
|
280
|
+
|
|
281
|
+
// setTimeout(function() { ajaxify.refresh(); }, 1500);
|
|
282
|
+
} else {
|
|
283
|
+
showMessage('error', 'לא התקבל מזהה חדר מהשרת, ייתכן וההודעה לא נשלחה.');
|
|
284
|
+
}
|
|
285
|
+
})
|
|
286
|
+
.fail(function(xhr) {
|
|
287
|
+
var err = xhr.responseJSON ? xhr.responseJSON.error : 'שגיאה בשליחת ההודעה';
|
|
288
|
+
showMessage('error', err);
|
|
289
|
+
})
|
|
290
|
+
.always(function() {
|
|
291
|
+
btn.prop('disabled', false);
|
|
292
|
+
});
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
$('.reply-email').off('click').on('click', function() {
|
|
296
|
+
var email = $(this).data('email');
|
|
297
|
+
var id = $(this).data('id');
|
|
298
|
+
$('#reply-to').val(email);
|
|
299
|
+
$('#reply-id').val(id);
|
|
300
|
+
$('#reply-content').val('');
|
|
301
|
+
$('#emailReplyModal').modal('show');
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
$('#send-reply-btn').off('click').on('click', function() {
|
|
305
|
+
var btn = $(this);
|
|
306
|
+
var email = $('#reply-to').val();
|
|
307
|
+
var subject = $('#reply-subject').val();
|
|
308
|
+
var content = $('#reply-content').val();
|
|
309
|
+
var id = $('#reply-id').val();
|
|
310
|
+
|
|
311
|
+
if (!content) return showMessage('error', 'נא לכתוב תוכן להודעה');
|
|
312
|
+
|
|
313
|
+
btn.prop('disabled', true);
|
|
314
|
+
|
|
315
|
+
$.post(config.relative_path + '/api/admin/plugins/contact/reply', {
|
|
316
|
+
email: email,
|
|
317
|
+
subject: subject,
|
|
318
|
+
content: content,
|
|
319
|
+
original_id: id,
|
|
320
|
+
_csrf: config.csrf_token
|
|
321
|
+
})
|
|
322
|
+
.done(function(data) {
|
|
323
|
+
$('#emailReplyModal').modal('hide');
|
|
324
|
+
showMessage('success', 'המייל נשלח בהצלחה והפנייה סומנה כטופלה');
|
|
325
|
+
setTimeout(function() { ajaxify.refresh(); }, 1000);
|
|
326
|
+
})
|
|
327
|
+
.fail(function(xhr) {
|
|
328
|
+
var err = xhr.responseJSON ? xhr.responseJSON.error : 'שגיאה בשליחה';
|
|
329
|
+
showMessage('error', err);
|
|
330
|
+
})
|
|
331
|
+
.always(function() {
|
|
332
|
+
btn.prop('disabled', false);
|
|
333
|
+
});
|
|
334
|
+
});
|
|
335
|
+
|
|
155
336
|
$('.mark-handled').off('click').on('click', function() {
|
|
156
337
|
var id = $(this).data('id');
|
|
157
338
|
confirmBox('האם לסמן פנייה זו כטופלה?', function(ok) {
|
|
@@ -169,51 +350,24 @@
|
|
|
169
350
|
$('.toggle-text').off('click').on('click', function() {
|
|
170
351
|
var $el = $(this);
|
|
171
352
|
if ($el.css('white-space') === 'nowrap') {
|
|
172
|
-
$el.css({
|
|
173
|
-
'white-space': 'normal',
|
|
174
|
-
'word-break': 'break-word',
|
|
175
|
-
'overflow': 'visible'
|
|
176
|
-
});
|
|
353
|
+
$el.css({ 'white-space': 'normal', 'word-break': 'break-word', 'overflow': 'visible' });
|
|
177
354
|
} else {
|
|
178
|
-
$el.css({
|
|
179
|
-
'white-space': 'nowrap',
|
|
180
|
-
'overflow': 'hidden',
|
|
181
|
-
'text-overflow': 'ellipsis'
|
|
182
|
-
});
|
|
355
|
+
$el.css({ 'white-space': 'nowrap', 'overflow': 'hidden', 'text-overflow': 'ellipsis' });
|
|
183
356
|
}
|
|
184
357
|
});
|
|
358
|
+
|
|
359
|
+
$('.modal').on('click', '[data-dismiss="modal"]', function(e) {
|
|
360
|
+
e.preventDefault();
|
|
361
|
+
$(this).closest('.modal').modal('hide');
|
|
362
|
+
});
|
|
185
363
|
}
|
|
186
364
|
|
|
187
365
|
function performHandle(id) {
|
|
188
|
-
$.post(config.relative_path + '/api/admin/plugins/contact/handle', {
|
|
189
|
-
id: id,
|
|
190
|
-
_csrf: config.csrf_token
|
|
191
|
-
})
|
|
192
|
-
.done(function(data) {
|
|
193
|
-
if (data.success) {
|
|
194
|
-
showMessage('success', 'הפנייה סומנה כטופלה בהצלחה');
|
|
195
|
-
ajaxify.refresh();
|
|
196
|
-
}
|
|
197
|
-
})
|
|
198
|
-
.fail(function() {
|
|
199
|
-
showMessage('error', 'שגיאה בעדכון הפנייה');
|
|
200
|
-
});
|
|
366
|
+
$.post(config.relative_path + '/api/admin/plugins/contact/handle', { id: id, _csrf: config.csrf_token }).done(function(data) { if (data.success) { showMessage('success', 'הפנייה סומנה כטופלה בהצלחה'); ajaxify.refresh(); } }).fail(function() { showMessage('error', 'שגיאה בעדכון הפנייה'); });
|
|
201
367
|
}
|
|
202
368
|
|
|
203
369
|
function performDelete(id) {
|
|
204
|
-
$.post(config.relative_path + '/api/admin/plugins/contact/delete', {
|
|
205
|
-
id: id,
|
|
206
|
-
_csrf: config.csrf_token
|
|
207
|
-
})
|
|
208
|
-
.done(function(data) {
|
|
209
|
-
if (data.success) {
|
|
210
|
-
showMessage('success', 'הפנייה נמחקה בהצלחה');
|
|
211
|
-
ajaxify.refresh();
|
|
212
|
-
}
|
|
213
|
-
})
|
|
214
|
-
.fail(function() {
|
|
215
|
-
showMessage('error', 'שגיאה במחיקת הפנייה');
|
|
216
|
-
});
|
|
370
|
+
$.post(config.relative_path + '/api/admin/plugins/contact/delete', { id: id, _csrf: config.csrf_token }).done(function(data) { if (data.success) { showMessage('success', 'הפנייה נמחקה בהצלחה'); ajaxify.refresh(); } }).fail(function() { showMessage('error', 'שגיאה במחיקת הפנייה'); });
|
|
217
371
|
}
|
|
218
372
|
|
|
219
373
|
$(document).ready(initContactPage);
|
|
@@ -223,4 +377,4 @@
|
|
|
223
377
|
}
|
|
224
378
|
});
|
|
225
379
|
})();
|
|
226
|
-
</script>
|
|
380
|
+
</script>
|
|
@@ -26,8 +26,8 @@
|
|
|
26
26
|
</div>
|
|
27
27
|
|
|
28
28
|
<div class="form-group" style="margin-bottom:20px;">
|
|
29
|
-
<label for="
|
|
30
|
-
<textarea class="form-control" id="
|
|
29
|
+
<label for="contact-message" style="font-weight:600; display:block; margin-bottom:6px;">תוכן הפנייה *</label>
|
|
30
|
+
<textarea class="form-control" id="contact-message" name="content" rows="6" required style="border-radius:10px; padding:10px;"></textarea>
|
|
31
31
|
</div>
|
|
32
32
|
|
|
33
33
|
<button type="submit" class="btn btn-primary btn-block" id="submit-btn" style="border-radius:22px; font-weight:600; padding:12px; margin-top:10px;">
|
|
@@ -45,38 +45,64 @@
|
|
|
45
45
|
|
|
46
46
|
<script>
|
|
47
47
|
(function() {
|
|
48
|
-
var
|
|
48
|
+
var loadContactForm = function() {
|
|
49
|
+
if (typeof window.jQuery === 'undefined' || typeof window.app === 'undefined') {
|
|
50
|
+
setTimeout(loadContactForm, 200);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
var $ = window.jQuery;
|
|
49
55
|
var form = $('#contact-form');
|
|
56
|
+
if (!form.length) return;
|
|
57
|
+
|
|
50
58
|
var btn = $('#submit-btn');
|
|
51
59
|
var alertBox = $('#contact-alert');
|
|
60
|
+
var isLoggedIn = (app.user && app.user.uid > 0);
|
|
52
61
|
|
|
53
|
-
if (
|
|
62
|
+
if (isLoggedIn) {
|
|
54
63
|
$('#username-group').hide();
|
|
55
64
|
}
|
|
56
65
|
|
|
57
66
|
form.off('submit').on('submit', function(e) {
|
|
58
67
|
e.preventDefault();
|
|
68
|
+
|
|
69
|
+
var contentVal = $('#contact-message').val();
|
|
70
|
+
var fullNameVal = $('#fullName').val();
|
|
71
|
+
var emailVal = $('#email').val();
|
|
72
|
+
var usernameVal = isLoggedIn ? app.user.username : $('#username').val();
|
|
73
|
+
|
|
74
|
+
if (!contentVal || contentVal.trim() === '') {
|
|
75
|
+
alertBox.removeClass('alert-success').addClass('alert-danger').text('אנא כתוב תוכן לפנייה').fadeIn();
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
|
|
59
79
|
btn.prop('disabled', true).text('שולח...');
|
|
60
80
|
alertBox.hide().removeClass('alert-success alert-danger');
|
|
61
81
|
|
|
62
|
-
var
|
|
63
|
-
fullName:
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
82
|
+
var payload = {
|
|
83
|
+
fullName: fullNameVal,
|
|
84
|
+
email: emailVal,
|
|
85
|
+
content: contentVal,
|
|
86
|
+
username: usernameVal,
|
|
67
87
|
_csrf: config.csrf_token
|
|
68
88
|
};
|
|
69
89
|
|
|
90
|
+
console.log('Sending Payload:', payload);
|
|
91
|
+
|
|
70
92
|
$.ajax({
|
|
71
93
|
url: config.relative_path + '/api/contact/send',
|
|
72
94
|
type: 'POST',
|
|
73
|
-
data:
|
|
95
|
+
data: payload,
|
|
96
|
+
headers: {
|
|
97
|
+
'x-csrf-token': config.csrf_token
|
|
98
|
+
},
|
|
74
99
|
success: function(response) {
|
|
75
100
|
alertBox.addClass('alert-success').text(response.message || 'הפנייה נשלחה בהצלחה').fadeIn();
|
|
76
101
|
form[0].reset();
|
|
77
102
|
},
|
|
78
103
|
error: function(xhr) {
|
|
79
|
-
|
|
104
|
+
console.error('Error:', xhr);
|
|
105
|
+
var msg = (xhr.responseJSON && xhr.responseJSON.error) ? xhr.responseJSON.error : 'אירעה שגיאה בשליחה. נסה שוב.';
|
|
80
106
|
alertBox.addClass('alert-danger').text(msg).fadeIn();
|
|
81
107
|
},
|
|
82
108
|
complete: function() {
|
|
@@ -86,16 +112,14 @@
|
|
|
86
112
|
});
|
|
87
113
|
};
|
|
88
114
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
window.
|
|
115
|
+
loadContactForm();
|
|
116
|
+
|
|
117
|
+
if (typeof window.jQuery !== 'undefined') {
|
|
118
|
+
$(window).on('action:ajaxify.end', function(ev, data) {
|
|
119
|
+
if (data.url.indexOf('contact') !== -1) {
|
|
120
|
+
loadContactForm();
|
|
121
|
+
}
|
|
122
|
+
});
|
|
93
123
|
}
|
|
94
|
-
|
|
95
|
-
$(window).on('action:ajaxify.end', function(ev, data) {
|
|
96
|
-
if (data.url === 'contact' || data.url === 'forum/contact') {
|
|
97
|
-
init();
|
|
98
|
-
}
|
|
99
|
-
});
|
|
100
124
|
})();
|
|
101
125
|
</script>
|