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 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
- // Send Notification to Admins
71
- try {
72
- const adminUids = await groups.getMembers('administrators', 0, -1);
73
-
74
- if (adminUids && adminUids.length > 0) {
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: `פנייה חדשה מאת ${contactData.fullName}`,
76
+ bodyShort: notificationTitle,
78
77
  bodyLong: contactData.content,
79
- nid: 'contact:' + contactId,
78
+ nid: userNid,
80
79
  path: '/admin/plugins/contact',
81
80
  from: 0
82
81
  });
83
82
 
84
- await notifications.push(notification, adminUids);
85
- } else {
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('Contact Plugin Error:', err);
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', { requests: items });
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
- // Add link to main navigation
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodebb-plugin-simple-contact",
3
- "version": "1.0.0",
3
+ "version": "1.1.2",
4
4
  "description": "תוסף טופס צור קשר עם התראות למנהלים וניהול פניות",
5
5
  "main": "library.js",
6
6
  "nbbpm": {
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">ממתין - פניות לטיפול</div>
6
- <div class="panel-body">
7
- <table class="table table-striped">
8
- <thead>
9
- <tr>
10
- <th>תאריך</th>
11
- <th>שם מלא</th>
12
- <th>משתמש</th>
13
- <th>מייל</th>
14
- <th>תוכן</th>
15
- <th>סטטוס</th>
16
- <th>פעולות</th>
17
- </tr>
18
- </thead>
19
- <tbody id="contact-list-waiting">
20
- {{{ each requests }}}
21
- {{{ if !./handled }}}
22
- <tr data-id="{./id}">
23
- <td>{./date}</td>
24
- <td>{./fullName}</td>
25
- <td>{./username}</td>
26
- <td>{./email}</td>
27
- <td>{./content}</td>
28
- <td><span class="label label-warning">ממתין</span></td>
29
- <td>
30
- <button class="btn btn-sm btn-primary mark-handled">סמן כטופל</button>
31
- </td>
32
- </tr>
33
- {{{ end }}}
34
- {{{ end }}}
35
- </tbody>
36
- </table>
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
- <div class="panel panel-success">
43
- <div class="panel-heading">מטופל - ארכיון פניות</div>
44
- <div class="panel-body">
45
- <table class="table table-striped">
46
- <thead>
47
- <tr>
48
- <th>תאריך</th>
49
- <th>שם מלא</th>
50
- <th>משתמש</th>
51
- <th>מייל</th>
52
- <th>תוכן</th>
53
- <th>סטטוס</th>
54
- <th>פעולות</th>
55
- </tr>
56
- </thead>
57
- <tbody id="contact-list-handled">
58
- {{{ each requests }}}
59
- {{{ if ./handled }}}
60
- <tr data-id="{./id}" class="success">
61
- <td>{./date}</td>
62
- <td>{./fullName}</td>
63
- <td>{./username}</td>
64
- <td>{./email}</td>
65
- <td>{./content}</td>
66
- <td><span class="label label-success">טופל</span></td>
67
- <td>
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
- </tr>
70
- {{{ end }}}
71
- {{{ end }}}
72
- </tbody>
73
- </table>
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
- <div class="panel-heading"><h3 class="panel-title">צור קשר עם ההנהלה</h3></div>
5
- <div class="panel-body">
6
- <form id="contact-form" role="form">
7
- <div class="form-group">
8
- <label for="fullName">שם מלא *</label>
9
- <input type="text" class="form-control" id="fullName" name="fullName" required>
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
- <div class="form-group">
12
- <label for="username">שם משתמש בפורום (במידה וקיים)</label>
13
- <input type="text" class="form-control" id="username" name="username">
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
- <div class="form-group">
16
- <label for="email">כתובת מייל *</label>
17
- <input type="email" class="form-control" id="email" name="email" required>
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
- <div class="form-group">
20
- <label for="content">תוכן הפנייה *</label>
21
- <textarea class="form-control" id="content" name="content" rows="6" required></textarea>
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
- <button type="submit" class="btn btn-primary" id="submit-btn">שלח פנייה</button>
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
- <div id="contact-alert" class="alert" style="display:none; margin-top: 20px;"></div>
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>
@@ -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
- }
@@ -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
- });