From a64e6865dc716439bd4b05f1bfb8489e9912d449 Mon Sep 17 00:00:00 2001 From: Alexey Dudarev <24899236+d-alex171@users.noreply.github.com> Date: Sat, 24 Jan 2026 11:28:05 -0800 Subject: [PATCH 1/2] added change password dialog --- .../pages/security-settings-content.tsx | 199 +++++++++++++++++- 1 file changed, 197 insertions(+), 2 deletions(-) diff --git a/src/components/settings/pages/security-settings-content.tsx b/src/components/settings/pages/security-settings-content.tsx index 05718669..b6e45b26 100644 --- a/src/components/settings/pages/security-settings-content.tsx +++ b/src/components/settings/pages/security-settings-content.tsx @@ -1,3 +1,198 @@ +import React, { useState } from 'react'; +import { createAuthClient } from 'better-auth/client'; +import { Button } from '@/components/ui/button'; +import { Input } from '@/components/ui/input'; +import { Label } from '@/components/ui/label'; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; +import { Separator } from '@/components/ui/separator'; +import { AlertCircle, LogOut, Shield, Lock } from 'lucide-react'; +import { Alert, AlertDescription } from '@/components/ui/alert'; + export function SecuritySettingsContent() { - return <>Security coming soon...; -} + const [currentPassword, setCurrentPassword] = useState(''); + const [newPassword, setNewPassword] = useState(''); + const [confirmPassword, setConfirmPassword] = useState(''); + const [loading, setLoading] = useState(false); + const [message, setMessage] = useState<{ type: 'success' | 'error'; text: string } | null>(null); + + const authClient = createAuthClient() + + const handleLogout = async () => { + try { + setLoading(true); + await authClient.signOut(); + setMessage({ type: 'success', text: 'Successfully logged out' }); + // Redirect to login page + window.location.href = '/login'; + } catch (error) { + setMessage({ type: 'error', text: 'Failed to logout. Please try again.' }); + } finally { + setLoading(false); + } + }; + + const handleRevokeAllSessions = async () => { + try { + setLoading(true); + await authClient.revokeOtherSessions(); + setMessage({ type: 'success', text: 'All other sessions have been revoked' }); + } catch (error) { + setMessage({ type: 'error', text: 'Failed to revoke sessions. Please try again.' }); + } finally { + setLoading(false); + } + }; + + const handleChangePassword = async () => { + setMessage(null); + + if (newPassword !== confirmPassword) { + setMessage({ type: 'error', text: 'New passwords do not match' }); + return; + } + + if (newPassword.length < 8) { + setMessage({ type: 'error', text: 'Password must be at least 8 characters long' }); + return; + } + + try { + setLoading(true); + await authClient.changePassword({ + currentPassword, + newPassword, + revokeOtherSessions: false, + }); + setMessage({ type: 'success', text: 'Password changed successfully' }); + setCurrentPassword(''); + setNewPassword(''); + setConfirmPassword(''); + } catch (error) { + setMessage({ type: 'error', text: 'Failed to change password. Please check your current password.' }); + } finally { + setLoading(false); + } + }; + + return ( +
+
+

Security

+

+ Manage your account security and sessions +

+
+ + + {message && ( + + + {message.text} + + )} + + + + + + Change Password + + + Update your password to keep your account secure + + + +
+
+ + setCurrentPassword(e.target.value)} + disabled={loading} + /> +
+
+ + setNewPassword(e.target.value)} + disabled={loading} + /> +
+
+ + setConfirmPassword(e.target.value)} + disabled={loading} + /> +
+ +
+
+
+ + {/* Session Management Section */} + + + + + Session Management + + + Manage your active sessions across all devices + + + +
+
+

Logout from all devices

+

+ End all sessions except the current one +

+
+ +
+
+
+ + {/* Logout Section */} + + + + + Logout + + + Sign out of your account on this device + + + + + + +
+ ); +} \ No newline at end of file From e6b7dd18ba7acbf2c18ed96b1fee32a23716beb9 Mon Sep 17 00:00:00 2001 From: Alexey Dudarev <24899236+d-alex171@users.noreply.github.com> Date: Sat, 31 Jan 2026 10:39:16 -0800 Subject: [PATCH 2/2] fixed logout button --- .../pages/security-settings-content.tsx | 20 +++++-------------- src/components/settings/settings-dialog.tsx | 2 +- 2 files changed, 6 insertions(+), 16 deletions(-) diff --git a/src/components/settings/pages/security-settings-content.tsx b/src/components/settings/pages/security-settings-content.tsx index b6e45b26..f0d63fda 100644 --- a/src/components/settings/pages/security-settings-content.tsx +++ b/src/components/settings/pages/security-settings-content.tsx @@ -7,6 +7,8 @@ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/com import { Separator } from '@/components/ui/separator'; import { AlertCircle, LogOut, Shield, Lock } from 'lucide-react'; import { Alert, AlertDescription } from '@/components/ui/alert'; +import { forceLogout } from "@/lib/auth/logout"; + export function SecuritySettingsContent() { const [currentPassword, setCurrentPassword] = useState(''); @@ -18,18 +20,8 @@ export function SecuritySettingsContent() { const authClient = createAuthClient() const handleLogout = async () => { - try { - setLoading(true); - await authClient.signOut(); - setMessage({ type: 'success', text: 'Successfully logged out' }); - // Redirect to login page - window.location.href = '/login'; - } catch (error) { - setMessage({ type: 'error', text: 'Failed to logout. Please try again.' }); - } finally { - setLoading(false); - } - }; + await forceLogout(); + }; const handleRevokeAllSessions = async () => { try { @@ -75,7 +67,7 @@ export function SecuritySettingsContent() { }; return ( -
+

Security

@@ -140,7 +132,6 @@ export function SecuritySettingsContent() { - {/* Session Management Section */} @@ -170,7 +161,6 @@ export function SecuritySettingsContent() { - {/* Logout Section */} diff --git a/src/components/settings/settings-dialog.tsx b/src/components/settings/settings-dialog.tsx index 6c4a9e03..c1715091 100644 --- a/src/components/settings/settings-dialog.tsx +++ b/src/components/settings/settings-dialog.tsx @@ -56,7 +56,7 @@ export const SettingsDialog = NiceModal.create(() => {