nodebb-plugin-simple-contact 1.0.0 → 1.1.2
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 +63 -49
- package/package.json +1 -1
- package/plugin.json +0 -9
- package/public/templates/admin/plugins/contact.tpl +216 -68
- package/public/templates/contact.tpl +96 -21
- package/public/js/admin.js +0 -36
- package/public/js/client.js +0 -54
package/library.js
CHANGED
|
@@ -2,9 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const db = require.main.require('./src/database');
|
|
4
4
|
const notifications = require.main.require('./src/notifications');
|
|
5
|
-
const user = require.main.require('./src/user');
|
|
6
5
|
const groups = require.main.require('./src/groups');
|
|
7
|
-
const utils = require.main.require('./src/utils');
|
|
8
6
|
|
|
9
7
|
const ContactPlugin = {};
|
|
10
8
|
|
|
@@ -12,24 +10,16 @@ ContactPlugin.init = async function (params) {
|
|
|
12
10
|
const router = params.router;
|
|
13
11
|
const middleware = params.middleware;
|
|
14
12
|
|
|
15
|
-
console.log('--- Contact Plugin Initialized ---'); // בדיקה שהתוסף נטען
|
|
16
|
-
|
|
17
|
-
// Route for the user facing page
|
|
18
13
|
router.get('/contact', middleware.buildHeader, renderContactPage);
|
|
19
14
|
router.get('/api/contact', renderContactPage);
|
|
20
|
-
|
|
21
|
-
// API Route to submit form
|
|
22
15
|
router.post('/api/contact/send', middleware.applyCSRF, handleContactSubmission);
|
|
23
16
|
|
|
24
|
-
// Route for Admin Panel
|
|
25
17
|
router.get('/admin/plugins/contact', middleware.admin.buildHeader, renderAdminPage);
|
|
26
18
|
router.get('/api/admin/plugins/contact', renderAdminPage);
|
|
27
|
-
|
|
28
|
-
// API to mark as handled
|
|
29
19
|
router.post('/api/admin/plugins/contact/handle', middleware.admin.buildHeader, markAsHandled);
|
|
20
|
+
router.post('/api/admin/plugins/contact/delete', middleware.admin.buildHeader, deleteRequest);
|
|
30
21
|
};
|
|
31
22
|
|
|
32
|
-
// Render User Page (עם תיקון פירורי הלחם)
|
|
33
23
|
async function renderContactPage(req, res) {
|
|
34
24
|
res.render('contact', {
|
|
35
25
|
title: 'צור קשר',
|
|
@@ -40,11 +30,8 @@ async function renderContactPage(req, res) {
|
|
|
40
30
|
});
|
|
41
31
|
}
|
|
42
32
|
|
|
43
|
-
// Handle Form Submission (עם הלוגיקה המשופרת והבטוחה)
|
|
44
33
|
async function handleContactSubmission(req, res) {
|
|
45
34
|
const data = req.body;
|
|
46
|
-
|
|
47
|
-
// Validation
|
|
48
35
|
if (!data.fullName || !data.email || !data.content) {
|
|
49
36
|
return res.status(400).json({ error: 'נא למלא את כל שדות החובה.' });
|
|
50
37
|
}
|
|
@@ -63,42 +50,61 @@ async function handleContactSubmission(req, res) {
|
|
|
63
50
|
};
|
|
64
51
|
|
|
65
52
|
try {
|
|
66
|
-
// Save to DB
|
|
67
53
|
await db.setObject(key, contactData);
|
|
68
54
|
await db.sortedSetAdd('contact-requests:sorted', contactId, contactId);
|
|
69
55
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
56
|
+
const adminUids = await groups.getMembers('administrators', 0, -1);
|
|
57
|
+
|
|
58
|
+
if (adminUids && adminUids.length > 0) {
|
|
59
|
+
await Promise.all(adminUids.map(async (uid) => {
|
|
60
|
+
const userUnreadKey = 'contact:unread_names:' + uid;
|
|
61
|
+
const userNid = 'contact:notification:' + uid;
|
|
62
|
+
|
|
63
|
+
await db.listAppend(userUnreadKey, contactData.fullName);
|
|
64
|
+
|
|
65
|
+
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
|
+
|
|
75
74
|
const notification = await notifications.create({
|
|
76
75
|
type: 'new-contact',
|
|
77
|
-
bodyShort:
|
|
76
|
+
bodyShort: notificationTitle,
|
|
78
77
|
bodyLong: contactData.content,
|
|
79
|
-
nid:
|
|
78
|
+
nid: userNid,
|
|
80
79
|
path: '/admin/plugins/contact',
|
|
81
80
|
from: 0
|
|
82
81
|
});
|
|
83
82
|
|
|
84
|
-
await notifications.push(notification,
|
|
85
|
-
}
|
|
86
|
-
console.warn('Contact Plugin: No administrators found to notify.');
|
|
87
|
-
}
|
|
88
|
-
} catch (notifyErr) {
|
|
89
|
-
console.error('Contact Plugin Notification Error:', notifyErr);
|
|
90
|
-
// לא מכשילים את הבקשה אם רק ההתראה נכשלה
|
|
83
|
+
await notifications.push(notification, [uid]);
|
|
84
|
+
}));
|
|
91
85
|
}
|
|
92
86
|
|
|
93
87
|
res.json({ success: true, message: 'הפנייה נשלחה בהצלחה.' });
|
|
94
88
|
} catch (err) {
|
|
95
|
-
console.error(
|
|
96
|
-
res.status(500).json({ error: 'שגיאה
|
|
89
|
+
console.error(err);
|
|
90
|
+
res.status(500).json({ error: 'שגיאה פנימית.' });
|
|
97
91
|
}
|
|
98
92
|
}
|
|
99
93
|
|
|
100
|
-
// Render Admin Page
|
|
101
94
|
async function renderAdminPage(req, res) {
|
|
95
|
+
if (req.uid) {
|
|
96
|
+
try {
|
|
97
|
+
const userUnreadKey = 'contact:unread_names:' + req.uid;
|
|
98
|
+
const userNid = 'contact:notification:' + req.uid;
|
|
99
|
+
|
|
100
|
+
await notifications.markRead(userNid, req.uid);
|
|
101
|
+
|
|
102
|
+
await db.delete(userUnreadKey);
|
|
103
|
+
} catch (e) {
|
|
104
|
+
console.error('Error handling notifications logic', e);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
102
108
|
const ids = await db.getSortedSetRevRange('contact-requests:sorted', 0, -1);
|
|
103
109
|
let items = [];
|
|
104
110
|
|
|
@@ -107,19 +113,26 @@ async function renderAdminPage(req, res) {
|
|
|
107
113
|
items = await db.getObjects(keys);
|
|
108
114
|
}
|
|
109
115
|
|
|
116
|
+
const waitingRequests = [];
|
|
117
|
+
const handledRequests = [];
|
|
118
|
+
|
|
110
119
|
items.forEach(item => {
|
|
111
|
-
// המרת תאריך למחרוזת קריאה
|
|
112
120
|
item.date = new Date(parseInt(item.timestamp)).toLocaleString();
|
|
121
|
+
if (item.handled) {
|
|
122
|
+
handledRequests.push(item);
|
|
123
|
+
} else {
|
|
124
|
+
waitingRequests.push(item);
|
|
125
|
+
}
|
|
113
126
|
});
|
|
114
127
|
|
|
115
|
-
res.render('admin/plugins/contact', {
|
|
128
|
+
res.render('admin/plugins/contact', {
|
|
129
|
+
waitingRequests: waitingRequests,
|
|
130
|
+
handledRequests: handledRequests
|
|
131
|
+
});
|
|
116
132
|
}
|
|
117
133
|
|
|
118
|
-
// Mark as Handled logic
|
|
119
134
|
async function markAsHandled(req, res) {
|
|
120
135
|
const id = req.body.id;
|
|
121
|
-
if (!id) return res.status(400).json({ error: 'Missing ID' });
|
|
122
|
-
|
|
123
136
|
try {
|
|
124
137
|
await db.setObjectField('contact-request:' + id, 'handled', true);
|
|
125
138
|
res.json({ success: true });
|
|
@@ -128,23 +141,24 @@ async function markAsHandled(req, res) {
|
|
|
128
141
|
}
|
|
129
142
|
}
|
|
130
143
|
|
|
131
|
-
|
|
144
|
+
async function deleteRequest(req, res) {
|
|
145
|
+
const id = req.body.id;
|
|
146
|
+
try {
|
|
147
|
+
await db.delete('contact-request:' + id);
|
|
148
|
+
await db.sortedSetRemove('contact-requests:sorted', id);
|
|
149
|
+
res.json({ success: true });
|
|
150
|
+
} catch (err) {
|
|
151
|
+
res.status(500).json({ error: err.message });
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
132
155
|
ContactPlugin.addNavigation = async function (header) {
|
|
133
|
-
header.navigation.push({
|
|
134
|
-
route: '/contact',
|
|
135
|
-
iconClass: 'fa-envelope',
|
|
136
|
-
text: 'צור קשר'
|
|
137
|
-
});
|
|
156
|
+
header.navigation.push({ route: '/contact', iconClass: 'fa-envelope', text: 'צור קשר' });
|
|
138
157
|
return header;
|
|
139
158
|
};
|
|
140
159
|
|
|
141
|
-
// Add link to admin menu
|
|
142
160
|
ContactPlugin.addAdminNavigation = async function (header) {
|
|
143
|
-
header.plugins.push({
|
|
144
|
-
route: '/plugins/contact',
|
|
145
|
-
icon: 'fa-envelope',
|
|
146
|
-
name: 'פניות צור קשר'
|
|
147
|
-
});
|
|
161
|
+
header.plugins.push({ route: '/plugins/contact', icon: 'fa-envelope', name: 'פניות צור קשר' });
|
|
148
162
|
return header;
|
|
149
163
|
};
|
|
150
164
|
|
package/package.json
CHANGED
package/plugin.json
CHANGED
|
@@ -1,20 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "nodebb-plugin-simple-contact",
|
|
3
3
|
"name": "Simple Contact Form",
|
|
4
|
-
"description": "A contact form with admin notifications.",
|
|
5
|
-
"url": "http://localhost",
|
|
6
4
|
"library": "./library.js",
|
|
7
5
|
"hooks": [
|
|
8
6
|
{ "hook": "static:app.load", "method": "init" },
|
|
9
7
|
{ "hook": "filter:navigation.available", "method": "addNavigation" },
|
|
10
8
|
{ "hook": "filter:admin.header.build", "method": "addAdminNavigation" }
|
|
11
9
|
],
|
|
12
|
-
"scripts": [
|
|
13
|
-
"public/js/client.js"
|
|
14
|
-
],
|
|
15
|
-
"acpScripts": [
|
|
16
|
-
"public/js/admin.js"
|
|
17
|
-
],
|
|
18
|
-
"modules": {},
|
|
19
10
|
"templates": "public/templates"
|
|
20
11
|
}
|
|
@@ -1,78 +1,226 @@
|
|
|
1
|
-
<div class="row">
|
|
1
|
+
<div class="row text-center">
|
|
2
2
|
<div class="col-xs-12">
|
|
3
|
-
|
|
4
|
-
<div class="panel panel-warning">
|
|
5
|
-
<div class="panel-heading"
|
|
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
|
-
|
|
3
|
+
|
|
4
|
+
<div class="panel panel-warning shadow-sm" style="border:none; border-radius:12px;">
|
|
5
|
+
<div class="panel-heading text-center" style="border-radius:12px 12px 0 0; font-weight:600;">
|
|
6
|
+
ממתין - פניות לטיפול
|
|
7
|
+
</div>
|
|
8
|
+
|
|
9
|
+
<div class="panel-body" style="background:#fafafa;">
|
|
10
|
+
{{{ if waitingRequests.length }}}
|
|
11
|
+
<div class="table-responsive">
|
|
12
|
+
<table class="table table-hover text-center" style="margin-bottom:0;">
|
|
13
|
+
<thead>
|
|
14
|
+
<tr>
|
|
15
|
+
<th class="text-center">תאריך</th>
|
|
16
|
+
<th class="text-center">שם מלא</th>
|
|
17
|
+
<th class="text-center">משתמש</th>
|
|
18
|
+
<th class="text-center">מייל</th>
|
|
19
|
+
<th class="text-center">תוכן</th>
|
|
20
|
+
<th class="text-center">סטטוס</th>
|
|
21
|
+
<th class="text-center">פעולות</th>
|
|
22
|
+
</tr>
|
|
23
|
+
</thead>
|
|
24
|
+
<tbody id="contact-list-waiting">
|
|
25
|
+
{{{ each waitingRequests }}}
|
|
26
|
+
<tr data-id="{./id}" class="text-center">
|
|
27
|
+
<td>{./date}</td>
|
|
28
|
+
<td><strong>{./fullName}</strong></td>
|
|
29
|
+
<td>{./username}</td>
|
|
30
|
+
<td><a href="mailto:{./email}">{./email}</a></td>
|
|
31
|
+
<td style="max-width:260px;">
|
|
32
|
+
<div class="toggle-text" style="white-space:nowrap; overflow:hidden; text-overflow:ellipsis; cursor:pointer;" title="לחץ להצגה/הסתרה">
|
|
33
|
+
{./content}
|
|
34
|
+
</div>
|
|
35
|
+
</td>
|
|
36
|
+
<td>
|
|
37
|
+
<span class="label label-warning" style="border-radius:10px; padding:3px 6px; font-size:11px;">ממתין</span>
|
|
38
|
+
</td>
|
|
39
|
+
<td class="text-center">
|
|
40
|
+
<button class="btn btn-xs btn-primary mark-handled" data-id="{./id}" style="border-radius:14px; font-size:11px; padding:3px 8px;">
|
|
41
|
+
✓ סמן כטופל
|
|
42
|
+
</button>
|
|
43
|
+
</td>
|
|
44
|
+
</tr>
|
|
45
|
+
{{{ end }}}
|
|
46
|
+
</tbody>
|
|
47
|
+
</table>
|
|
48
|
+
</div>
|
|
49
|
+
{{{ else }}}
|
|
50
|
+
<div class="alert alert-info text-center" style="border-radius:10px;">
|
|
51
|
+
אין פניות ממתינות כרגע.
|
|
52
|
+
</div>
|
|
53
|
+
{{{ end }}}
|
|
37
54
|
</div>
|
|
38
55
|
</div>
|
|
39
56
|
|
|
40
|
-
<hr>
|
|
57
|
+
<hr style="opacity:.2;">
|
|
58
|
+
|
|
59
|
+
<div class="panel panel-success shadow-sm" style="border:none; border-radius:12px;">
|
|
60
|
+
<div class="panel-heading text-center" style="border-radius:12px 12px 0 0; font-weight:600;">
|
|
61
|
+
מטופל - ארכיון פניות
|
|
62
|
+
</div>
|
|
41
63
|
|
|
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
|
-
|
|
64
|
+
<div class="panel-body" style="background:#fafafa;">
|
|
65
|
+
{{{ if handledRequests.length }}}
|
|
66
|
+
<div class="table-responsive">
|
|
67
|
+
<table class="table table-hover text-center" style="margin-bottom:0;">
|
|
68
|
+
<thead>
|
|
69
|
+
<tr>
|
|
70
|
+
<th class="text-center">תאריך</th>
|
|
71
|
+
<th class="text-center">שם מלא</th>
|
|
72
|
+
<th class="text-center">משתמש</th>
|
|
73
|
+
<th class="text-center">מייל</th>
|
|
74
|
+
<th class="text-center">תוכן</th>
|
|
75
|
+
<th class="text-center">סטטוס</th>
|
|
76
|
+
<th class="text-center">פעולות</th>
|
|
77
|
+
</tr>
|
|
78
|
+
</thead>
|
|
79
|
+
<tbody id="contact-list-handled">
|
|
80
|
+
{{{ each handledRequests }}}
|
|
81
|
+
<tr data-id="{./id}" class="text-center">
|
|
82
|
+
<td>{./date}</td>
|
|
83
|
+
<td><strong>{./fullName}</strong></td>
|
|
84
|
+
<td>{./username}</td>
|
|
85
|
+
<td><a href="mailto:{./email}">{./email}</a></td>
|
|
86
|
+
<td style="max-width:260px;">
|
|
87
|
+
<div class="toggle-text" style="white-space:nowrap; overflow:hidden; text-overflow:ellipsis; cursor:pointer;" title="לחץ להצגה/הסתרה">
|
|
88
|
+
{./content}
|
|
89
|
+
</div>
|
|
90
|
+
</td>
|
|
91
|
+
<td>
|
|
92
|
+
<span class="label label-success" style="border-radius:10px; padding:3px 6px; font-size:11px;">טופל</span>
|
|
93
|
+
</td>
|
|
94
|
+
<td class="text-center">
|
|
95
|
+
<button class="btn btn-xs btn-danger delete-request" data-id="{./id}" style="border-radius:14px; font-size:11px; padding:3px 8px;">
|
|
96
|
+
× מחק
|
|
97
|
+
</button>
|
|
68
98
|
</td>
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
</
|
|
73
|
-
</
|
|
99
|
+
</tr>
|
|
100
|
+
{{{ end }}}
|
|
101
|
+
</tbody>
|
|
102
|
+
</table>
|
|
103
|
+
</div>
|
|
104
|
+
{{{ else }}}
|
|
105
|
+
<div class="alert alert-info text-center" style="border-radius:10px;">
|
|
106
|
+
ארכיון הפניות ריק.
|
|
107
|
+
</div>
|
|
108
|
+
{{{ end }}}
|
|
74
109
|
</div>
|
|
75
110
|
</div>
|
|
76
111
|
|
|
77
112
|
</div>
|
|
78
|
-
</div>
|
|
113
|
+
</div>
|
|
114
|
+
|
|
115
|
+
<script>
|
|
116
|
+
(function() {
|
|
117
|
+
if (typeof define === 'function' && define.amd) {
|
|
118
|
+
define('admin/plugins/contact', [], function() { return {}; });
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function showMessage(type, msg) {
|
|
122
|
+
const clean = msg.replace(/<[^>]*>/g, '');
|
|
123
|
+
if (window.app && typeof window.app.require === 'function') {
|
|
124
|
+
window.app.require('alerts').then(function(alerts) {
|
|
125
|
+
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
|
+
});
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
alert(clean);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function confirmBox(message, cb) {
|
|
143
|
+
if (window.app && window.app.require) {
|
|
144
|
+
window.app.require('bootbox').then(function(bootbox) {
|
|
145
|
+
bootbox.confirm(message, cb);
|
|
146
|
+
});
|
|
147
|
+
} else if (window.bootbox) {
|
|
148
|
+
window.bootbox.confirm(message, cb);
|
|
149
|
+
} else {
|
|
150
|
+
cb(confirm(message));
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function initContactPage() {
|
|
155
|
+
$('.mark-handled').off('click').on('click', function() {
|
|
156
|
+
var id = $(this).data('id');
|
|
157
|
+
confirmBox('האם לסמן פנייה זו כטופלה?', function(ok) {
|
|
158
|
+
if (ok) performHandle(id);
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
$('.delete-request').off('click').on('click', function() {
|
|
163
|
+
var id = $(this).data('id');
|
|
164
|
+
confirmBox('האם למחוק פנייה זו לצמיתות?', function(ok) {
|
|
165
|
+
if (ok) performDelete(id);
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
$('.toggle-text').off('click').on('click', function() {
|
|
170
|
+
var $el = $(this);
|
|
171
|
+
if ($el.css('white-space') === 'nowrap') {
|
|
172
|
+
$el.css({
|
|
173
|
+
'white-space': 'normal',
|
|
174
|
+
'word-break': 'break-word',
|
|
175
|
+
'overflow': 'visible'
|
|
176
|
+
});
|
|
177
|
+
} else {
|
|
178
|
+
$el.css({
|
|
179
|
+
'white-space': 'nowrap',
|
|
180
|
+
'overflow': 'hidden',
|
|
181
|
+
'text-overflow': 'ellipsis'
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
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
|
+
});
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
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
|
+
});
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
$(document).ready(initContactPage);
|
|
220
|
+
$(window).on('action:ajaxify.end', function(e, data) {
|
|
221
|
+
if (data.tpl_url === 'admin/plugins/contact') {
|
|
222
|
+
initContactPage();
|
|
223
|
+
}
|
|
224
|
+
});
|
|
225
|
+
})();
|
|
226
|
+
</script>
|
|
@@ -1,29 +1,104 @@
|
|
|
1
|
-
<div class="row">
|
|
2
|
-
<div class="col-lg-8 col-lg-offset-2">
|
|
3
|
-
<div class="panel panel-default">
|
|
4
|
-
|
|
5
|
-
<div class="panel-
|
|
6
|
-
<
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
1
|
+
<div class="row text-center" style="display:flex; justify-content:center; align-items:center;">
|
|
2
|
+
<div class="col-lg-8 col-lg-offset-2" style="margin-top:20px;">
|
|
3
|
+
<div class="panel panel-default shadow-sm" style="border-radius:14px; border:none;">
|
|
4
|
+
|
|
5
|
+
<div class="panel-heading text-center" style="background:linear-gradient(135deg,#2b6cb0,#2c5282); color:#fff; border-radius:14px 14px 0 0; padding:15px;">
|
|
6
|
+
<h3 class="panel-title" style="font-weight:600; margin:0;">צור קשר עם ההנהלה</h3>
|
|
7
|
+
</div>
|
|
8
|
+
|
|
9
|
+
<div class="panel-body text-center" style="background:#fafafa; padding:20px 25px;">
|
|
10
|
+
|
|
11
|
+
<form id="contact-form" role="form" style="max-width:600px; margin:0 auto;">
|
|
12
|
+
|
|
13
|
+
<div class="form-group" style="margin-bottom:16px;">
|
|
14
|
+
<label for="fullName" style="font-weight:600; display:block; margin-bottom:6px;">שם מלא *</label>
|
|
15
|
+
<input type="text" class="form-control text-center" id="fullName" name="fullName" required style="border-radius:10px; padding:10px;">
|
|
10
16
|
</div>
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
<
|
|
17
|
+
|
|
18
|
+
<div class="form-group" style="margin-bottom:16px;">
|
|
19
|
+
<label for="username" style="font-weight:600; display:block; margin-bottom:6px;">שם משתמש בפורום</label>
|
|
20
|
+
<input type="text" class="form-control text-center" id="username" name="username" style="border-radius:10px; padding:10px;">
|
|
14
21
|
</div>
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
<
|
|
22
|
+
|
|
23
|
+
<div class="form-group" style="margin-bottom:16px;">
|
|
24
|
+
<label for="email" style="font-weight:600; display:block; margin-bottom:6px;">כתובת מייל *</label>
|
|
25
|
+
<input type="email" class="form-control text-center" id="email" name="email" required style="border-radius:10px; padding:10px;">
|
|
18
26
|
</div>
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
<
|
|
27
|
+
|
|
28
|
+
<div class="form-group" style="margin-bottom:20px;">
|
|
29
|
+
<label for="content" style="font-weight:600; display:block; margin-bottom:6px;">תוכן הפנייה *</label>
|
|
30
|
+
<textarea class="form-control text-center" id="content" name="content" rows="6" required style="border-radius:10px; padding:10px;"></textarea>
|
|
22
31
|
</div>
|
|
23
|
-
|
|
32
|
+
|
|
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;">
|
|
34
|
+
שלח פנייה
|
|
35
|
+
</button>
|
|
36
|
+
|
|
24
37
|
</form>
|
|
25
|
-
|
|
38
|
+
|
|
39
|
+
<div id="contact-alert" class="alert text-center" style="display:none; margin-top:20px; border-radius:10px;"></div>
|
|
40
|
+
|
|
26
41
|
</div>
|
|
27
42
|
</div>
|
|
28
43
|
</div>
|
|
29
|
-
</div>
|
|
44
|
+
</div>
|
|
45
|
+
|
|
46
|
+
<script>
|
|
47
|
+
(function() {
|
|
48
|
+
function initContactForm($) {
|
|
49
|
+
var form = $('#contact-form');
|
|
50
|
+
var btn = $('#submit-btn');
|
|
51
|
+
var alertBox = $('#contact-alert');
|
|
52
|
+
|
|
53
|
+
form.off('submit').on('submit', function(e) {
|
|
54
|
+
e.preventDefault();
|
|
55
|
+
|
|
56
|
+
btn.prop('disabled', true).text('שולח...');
|
|
57
|
+
alertBox.hide().removeClass('alert-success alert-danger');
|
|
58
|
+
|
|
59
|
+
var formData = {
|
|
60
|
+
fullName: form.find('#fullName').val(),
|
|
61
|
+
username: form.find('#username').val(),
|
|
62
|
+
email: form.find('#email').val(),
|
|
63
|
+
content: form.find('#content').val(),
|
|
64
|
+
_csrf: config.csrf_token
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
$.ajax({
|
|
68
|
+
url: config.relative_path + '/api/contact/send',
|
|
69
|
+
type: 'POST',
|
|
70
|
+
data: formData,
|
|
71
|
+
success: function(response) {
|
|
72
|
+
alertBox.addClass('alert-success').text(response.message || 'הפנייה נשלחה בהצלחה').fadeIn();
|
|
73
|
+
form[0].reset();
|
|
74
|
+
btn.text('שלח פנייה');
|
|
75
|
+
},
|
|
76
|
+
error: function(xhr) {
|
|
77
|
+
var msg = (xhr.responseJSON && xhr.responseJSON.error) ? xhr.responseJSON.error : 'אירעה שגיאה בשליחה';
|
|
78
|
+
alertBox.addClass('alert-danger').text(msg).fadeIn();
|
|
79
|
+
},
|
|
80
|
+
complete: function() {
|
|
81
|
+
btn.prop('disabled', false).text('שלח פנייה');
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function safeBoot() {
|
|
88
|
+
if (typeof jQuery === 'undefined') {
|
|
89
|
+
setTimeout(safeBoot, 50);
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
var $ = jQuery;
|
|
93
|
+
initContactForm($);
|
|
94
|
+
|
|
95
|
+
$(window).off('action:ajaxify.end.contact').on('action:ajaxify.end.contact', function(ev, data) {
|
|
96
|
+
if (data.url === 'contact') {
|
|
97
|
+
initContactForm($);
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
safeBoot();
|
|
103
|
+
})();
|
|
104
|
+
</script>
|
package/public/js/admin.js
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
/* globals $, app, socket */
|
|
4
|
-
|
|
5
|
-
// הקוד הזה ירוץ ברגע שפאנל הניהול נטען
|
|
6
|
-
$(document).ready(function () {
|
|
7
|
-
// האזנה לאירוע ש-NodeBB מסיים לטעון דף חדש (Ajaxify)
|
|
8
|
-
$(window).on('action:ajaxify.end', function (event, data) {
|
|
9
|
-
// בדיקה: האם הגענו לדף של התוסף שלנו?
|
|
10
|
-
if (data.tpl_url === 'admin/plugins/contact') {
|
|
11
|
-
initializeAdminPage();
|
|
12
|
-
}
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
// אם אנחנו כבר בדף הזה ברגע הטעינה הראשונה
|
|
16
|
-
if (ajaxify.data.template && ajaxify.data.template['admin/plugins/contact']) {
|
|
17
|
-
initializeAdminPage();
|
|
18
|
-
}
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
function initializeAdminPage() {
|
|
22
|
-
console.log('✅ Contact Admin Page logic triggered via Hook');
|
|
23
|
-
|
|
24
|
-
// לוגיקה לסימון כטופל
|
|
25
|
-
$('.mark-handled-btn').on('click', function () {
|
|
26
|
-
var id = $(this).data('id');
|
|
27
|
-
var btn = $(this);
|
|
28
|
-
|
|
29
|
-
$.post('/api/admin/plugins/contact/handle', { id: id }, function (data) {
|
|
30
|
-
if (data.success) {
|
|
31
|
-
btn.closest('tr').addClass('table-success');
|
|
32
|
-
btn.replaceWith('<span class="badge bg-success">טופל</span>');
|
|
33
|
-
}
|
|
34
|
-
});
|
|
35
|
-
});
|
|
36
|
-
}
|
package/public/js/client.js
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
// החלק הזה מטפל בלוגיקה של הטופס
|
|
4
|
-
$(document).ready(function() {
|
|
5
|
-
$(window).on('action:ajaxify.end', function(event, data) {
|
|
6
|
-
if (data.url === 'contact' || ajaxify.data.template.name === 'contact') {
|
|
7
|
-
$('#contact-form').off('submit').on('submit', function(e) {
|
|
8
|
-
e.preventDefault();
|
|
9
|
-
var btn = $('#submit-btn');
|
|
10
|
-
var alertBox = $('#contact-alert');
|
|
11
|
-
var form = $(this);
|
|
12
|
-
|
|
13
|
-
btn.prop('disabled', true);
|
|
14
|
-
|
|
15
|
-
var formData = {
|
|
16
|
-
fullName: form.find('#fullName').val(),
|
|
17
|
-
username: form.find('#username').val(),
|
|
18
|
-
email: form.find('#email').val(),
|
|
19
|
-
content: form.find('#content').val()
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
$.ajax({
|
|
23
|
-
url: config.relative_path + '/api/contact/send',
|
|
24
|
-
type: 'POST',
|
|
25
|
-
data: formData,
|
|
26
|
-
headers: { 'x-csrf-token': config.csrf_token },
|
|
27
|
-
success: function(response) {
|
|
28
|
-
alertBox.removeClass('alert-danger').addClass('alert-success')
|
|
29
|
-
.text(response.message).show();
|
|
30
|
-
form[0].reset();
|
|
31
|
-
},
|
|
32
|
-
error: function(xhr) {
|
|
33
|
-
// הצגת הודעת שגיאה מפורטת אם השרת החזיר כזו
|
|
34
|
-
var msg = (xhr.responseJSON && xhr.responseJSON.error) ? xhr.responseJSON.error : 'שגיאה בשליחה';
|
|
35
|
-
alertBox.removeClass('alert-success').addClass('alert-danger')
|
|
36
|
-
.text(msg).show();
|
|
37
|
-
},
|
|
38
|
-
complete: function() {
|
|
39
|
-
btn.prop('disabled', false);
|
|
40
|
-
}
|
|
41
|
-
});
|
|
42
|
-
});
|
|
43
|
-
}
|
|
44
|
-
});
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
// החלק הזה "מרגיע" את NodeBB שלא יחפש מודול חסר
|
|
48
|
-
define('forum/contact', [], function() {
|
|
49
|
-
return {
|
|
50
|
-
init: function() {
|
|
51
|
-
console.log('Contact page loaded.');
|
|
52
|
-
}
|
|
53
|
-
};
|
|
54
|
-
});
|