diff --git a/package-lock.json b/package-lock.json index d3141ec..82430ad 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "textsender", - "version": "0.0.6", + "version": "0.0.7", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "textsender", - "version": "0.0.6", + "version": "0.0.7", "dependencies": { "react": "^19.2.7", "react-dom": "^19.2.7", diff --git a/package.json b/package.json index bd1e976..def122f 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "textsender", "private": true, - "version": "0.0.6", + "version": "0.0.7", "type": "module", "scripts": { "dev": "vite", diff --git a/src/api/loginApi.js b/src/api/loginApi.js index c3cba83..fb0903b 100644 --- a/src/api/loginApi.js +++ b/src/api/loginApi.js @@ -37,4 +37,33 @@ export const userApi = { throw new Error('Error logging in'); } }, + + update_password: async ( + userId, + currentPassword, + updatedPassword, + confirmedPassword + ) => { + const request = { + user_id: userId, + current_password: currentPassword, + updated_password: updatedPassword, + confirmed_password: confirmedPassword, + }; + + const reponse = await fetch( + `${AUTH_API_BASE_URL}/api/v1/user/password/update`, + { + method: 'PATCH', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(request), + } + ); + + if (reponse.ok) { + return reponse.json(); + } else { + throw new Error('Error logging in'); + } + }, }; diff --git a/src/components/ProfileForm.css b/src/components/ProfileForm.css index 31bd471..7abcd2f 100644 --- a/src/components/ProfileForm.css +++ b/src/components/ProfileForm.css @@ -1,41 +1,95 @@ .profile-form { - max-width: 400px; + background: white; + border-radius: 12px; + box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3); + padding: 40px; + width: 100%; + max-width: 420px; margin: 0 auto; - padding: 20px; - border: 1px solid #ccc; - border-radius: 8px; - box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); - background-color: #ffffff; } .profile-form h2 { + color: #333; + font-size: 28px; + font-weight: 600; text-align: center; - margin-bottom: 20px; + margin-bottom: 30px; } .profile-form form { - display: flex; - flex-direction: column; + margin-bottom: 25px; } .profile-form div { - margin-bottom: 15px; + margin-bottom: 20px; } .profile-form label { - font-weight: bold; - margin-bottom: 5px; display: block; + color: #555; + font-size: 14px; + font-weight: 500; + margin-bottom: 6px; } .profile-form input[type='text'], -.profile-form input[type='tel'] { +.profile-form input[type='tel'], +.profile-form input[type='password'] { width: 100%; - padding: 8px; - border: 1px solid #ccc; - border-radius: 4px; + padding: 12px 16px; + border: 2px solid #e1e5e9; + border-radius: 8px; + font-size: 16px; + transition: all 0.3s ease; + box-sizing: border-box; +} + +.profile-form input[type='text']:focus, +.profile-form input[type='tel']:focus, +.profile-form input[type='password']:focus { + outline: none; + border-color: #667eea; + box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1); } .profile-form input[readonly] { - background-color: #f9f9f9; + background-color: #f9fafb; + cursor: not-allowed; +} + +.profile-form button[type='submit'] { + width: 100%; + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + color: white; + border: none; + border-radius: 8px; + padding: 14px; + font-size: 16px; + font-weight: 600; + cursor: pointer; + transition: all 0.3s ease; + margin-top: 10px; +} + +.profile-form button[type='submit']:hover:not(:disabled) { + transform: translateY(-1px); + box-shadow: 0 10px 25px rgba(102, 126, 234, 0.4); +} + +.profile-form button[type='button'] { + width: 100%; + background: #f1f5f9; + color: #334155; + border: 1px solid #cbd5e1; + border-radius: 8px; + padding: 14px; + font-size: 16px; + font-weight: 500; + cursor: pointer; + transition: all 0.3s ease; + margin-top: 10px; +} + +.profile-form button[type='button']:hover { + background: #e2e8f0; } diff --git a/src/components/ProfileForm.jsx b/src/components/ProfileForm.jsx index 2ed853e..9a8521b 100644 --- a/src/components/ProfileForm.jsx +++ b/src/components/ProfileForm.jsx @@ -9,6 +9,7 @@ import './ProfileForm.css'; const ProfileForm = () => { const navigate = useNavigate(); const [activeView, setActiveView] = useState('profile'); + const [subView, setSubView] = useState('details'); const [formData, setFormData] = useState({ firstname: '', lastname: '', @@ -18,6 +19,12 @@ const ProfileForm = () => { lastLoginDate: new Date().toISOString().split('T')[0], }); + const [passwordData, setPasswordData] = useState({ + currentPassword: '', + newPassword: '', + confirmNewPassword: '', + }); + useEffect(() => { const fetchData = async () => { const userId = tokenService.getUserId(); @@ -47,6 +54,14 @@ const ProfileForm = () => { setFormData({ ...formData, [name]: value }); }; + const handlePasswordChange = (e) => { + const { name, value } = e.target; + setPasswordData((prev) => ({ + ...prev, + [name]: value, + })); + }; + const handleNavClick = (view) => { if (view === 'profile') { navigate('/user/profile'); @@ -55,6 +70,155 @@ const ProfileForm = () => { } }; + const handlePasswordSubmit = async (e) => { + e.preventDefault(); + + try { + const userId = tokenService.getUserId(); + const currentPassword = passwordData.currentPassword; + const newPassword = passwordData.newPassword; + const confirmNewPassword = passwordData.confirmNewPassword; + + const response = await userApi.update_password( + userId, + currentPassword, + newPassword, + confirmNewPassword + ); + if (response) { + console.log('Successfully updated password'); + } else { + console.error('Error updating password'); + } + } catch (error) { + console.error('Login error:', error); + } finally { + } + }; + + const renderPasswordForm = () => ( +