larxius commited on
Commit
d5e2fbf
·
verified ·
1 Parent(s): 57d6e80

Update frontend/src/pages/Settings.jsx

Browse files
Files changed (1) hide show
  1. frontend/src/pages/Settings.jsx +191 -0
frontend/src/pages/Settings.jsx CHANGED
@@ -213,6 +213,197 @@ export const AlertSettingsPage = () => {
213
  fetchSettings();
214
  }, [token]);
215
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
216
  // Auto-refresh user data (e.g., subscription upgrades) when Billing tab is active
217
  useEffect(() => {
218
  let intervalId;
 
213
  fetchSettings();
214
  }, [token]);
215
 
216
+ const fetchSettings = async () => {
217
+ try {
218
+ const res = await fetch('/api/vulnerabilities/settings', {
219
+ headers: { 'Authorization': `Bearer ${token}` }
220
+ });
221
+ if (res.ok) {
222
+ const data = await res.json();
223
+ setEmailNotifications(data.settings.email_notifications);
224
+ setWebhookUrl(data.settings.webhook_url || '');
225
+ setSeverityThreshold(data.settings.severity_threshold);
226
+ }
227
+ } catch (err) {
228
+ console.error("Error loading alert settings", err);
229
+ } finally {
230
+ setLoading(false);
231
+ }
232
+ };
233
+
234
+ const fetchNotificationHistory = async () => {
235
+ setLoadingHistory(true);
236
+ try {
237
+ const res = await fetch('/api/auth/notifications', {
238
+ headers: { 'Authorization': `Bearer ${token}` }
239
+ });
240
+ if (res.ok) {
241
+ const data = await res.json();
242
+ setNotificationHistory(data.notifications || []);
243
+ }
244
+ } catch (err) {
245
+ console.error("Error loading notification history", err);
246
+ } finally {
247
+ setLoadingHistory(false);
248
+ }
249
+ };
250
+
251
+ const fetchTeamUsers = async () => {
252
+ setLoadingTeam(true);
253
+ try {
254
+ const endpoint = user?.org_id ? `/api/auth/organizations/${user.org_id}/users` : '/api/auth/users';
255
+ const res = await fetch(endpoint, {
256
+ headers: { 'Authorization': `Bearer ${token}` }
257
+ });
258
+ if (res.ok) {
259
+ const data = await res.json();
260
+ const filteredUsers = (data.users || []).filter(u => u.role !== 'super_admin');
261
+ setTeamUsers(filteredUsers);
262
+ }
263
+ } catch (err) {
264
+ console.error('Failed to fetch org users', err);
265
+ } finally {
266
+ setLoadingTeam(false);
267
+ }
268
+ };
269
+
270
+ useEffect(() => {
271
+ if (activeTab === 'team' && (user?.role === 'org_admin' || user?.role === 'super_admin')) {
272
+ fetchTeamUsers();
273
+ }
274
+ }, [activeTab, user]);
275
+
276
+ const handleInviteUser = async (e) => {
277
+ e.preventDefault();
278
+ if (!newUserEmail) return;
279
+ setInvitingUser(true);
280
+ try {
281
+ const res = await fetch('/api/auth/users/invite', {
282
+ method: 'POST',
283
+ headers: {
284
+ 'Authorization': `Bearer ${token}`,
285
+ 'Content-Type': 'application/json'
286
+ },
287
+ body: JSON.stringify({
288
+ email: newUserEmail,
289
+ role: newUserRole,
290
+ first_name: newUserFirstName,
291
+ last_name: newUserLastName,
292
+ password: newUserPassword
293
+ })
294
+ });
295
+ const data = await res.json();
296
+ if (res.ok) {
297
+ toast.success(`User added successfully!`);
298
+ setNewUserFirstName('');
299
+ setNewUserLastName('');
300
+ setNewUserEmail('');
301
+ setNewUserPassword('');
302
+ setShowAddMember(false);
303
+ setShowNewUserPassword(false);
304
+ fetchTeamUsers();
305
+ } else {
306
+ toast.error(data.message || 'Failed to invite user');
307
+ }
308
+ } catch (err) {
309
+ toast.error("Error inviting user");
310
+ } finally {
311
+ setInvitingUser(false);
312
+ }
313
+ };
314
+
315
+ const handleUpdateUser = async (e) => {
316
+ e.preventDefault();
317
+ if (!editingUser) return;
318
+ setUpdatingUser(true);
319
+ try {
320
+ const res = await fetch(`/api/auth/users/${editingUser.id}`, {
321
+ method: 'PUT',
322
+ headers: {
323
+ 'Authorization': `Bearer ${token}`,
324
+ 'Content-Type': 'application/json'
325
+ },
326
+ body: JSON.stringify({
327
+ first_name: editingUser.first_name,
328
+ last_name: editingUser.last_name,
329
+ email: editingUser.email,
330
+ password: editingUser.new_password,
331
+ role: editingUser.role
332
+ })
333
+ });
334
+ if (res.ok) {
335
+ toast.success(`User updated successfully!`);
336
+ setEditingUser(null);
337
+ fetchTeamUsers();
338
+ } else {
339
+ const data = await res.json();
340
+ toast.error(data.message || 'Failed to update user');
341
+ }
342
+ } catch (err) {
343
+ toast.error("Error updating user");
344
+ } finally {
345
+ setUpdatingUser(false);
346
+ }
347
+ };
348
+
349
+ const executeDeleteUser = async () => {
350
+ if (!userToDelete) return;
351
+ setDeletingUser(true);
352
+ try {
353
+ const res = await fetch(`/api/auth/users/${userToDelete.id}`, {
354
+ method: 'DELETE',
355
+ headers: { 'Authorization': `Bearer ${token}` }
356
+ });
357
+ if (res.ok) {
358
+ toast.success("User removed successfully!");
359
+ setUserToDelete(null);
360
+ fetchTeamUsers();
361
+ } else {
362
+ const data = await res.json();
363
+ toast.error(data.message || "Failed to remove user");
364
+ }
365
+ } catch (err) {
366
+ toast.error("Error removing user");
367
+ } finally {
368
+ setDeletingUser(false);
369
+ }
370
+ };
371
+
372
+ const handlePasswordChange = async (e) => {
373
+ e.preventDefault();
374
+ setPasswordStatus({ loading: true, error: null, success: false });
375
+ if (passwordData.newPassword !== passwordData.confirmPassword) {
376
+ setPasswordStatus({ loading: false, error: "New passwords do not match", success: false });
377
+ return;
378
+ }
379
+ if (passwordData.newPassword.length < 6) {
380
+ setPasswordStatus({ loading: false, error: "New password must be at least 6 characters", success: false });
381
+ return;
382
+ }
383
+ try {
384
+ const res = await fetch('/api/auth/password', {
385
+ method: 'PUT',
386
+ headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` },
387
+ body: JSON.stringify({ currentPassword: passwordData.currentPassword, newPassword: passwordData.newPassword })
388
+ });
389
+ let data = {};
390
+ try { data = await res.json(); } catch (e) { }
391
+ if (res.ok) {
392
+ setPasswordStatus({ loading: false, error: null, success: true });
393
+ setPasswordData({ currentPassword: '', newPassword: '', confirmPassword: '' });
394
+ toast.success("Password updated successfully!");
395
+ setTimeout(() => setPasswordStatus(prev => ({ ...prev, success: false })), 3000);
396
+ } else {
397
+ const errorMsg = data.message || "Failed to update password";
398
+ setPasswordStatus({ loading: false, error: errorMsg, success: false });
399
+ toast.error(errorMsg);
400
+ }
401
+ } catch (err) {
402
+ setPasswordStatus({ loading: false, error: "Network error occurred", success: false });
403
+ toast.error("Network error occurred");
404
+ }
405
+ };
406
+
407
  // Auto-refresh user data (e.g., subscription upgrades) when Billing tab is active
408
  useEffect(() => {
409
  let intervalId;