From be1238e24d005b80e12d01efd2c1fd772a0d1c33 Mon Sep 17 00:00:00 2001 From: phoenix Date: Wed, 1 Jul 2026 23:56:22 -0400 Subject: [PATCH] tsk-5: Add profile page (#12) Closes #5 Reviewed-on: http://git.kundeng.us/phoenix/textsender/pulls/12 --- src/App.jsx | 2 + src/api/loginApi.js | 18 ++++ src/components/Dashboard.jsx | 16 ++-- src/components/ProfileForm.css | 41 +++++++++ src/components/ProfileForm.jsx | 161 +++++++++++++++++++++++++++++++++ 5 files changed, 229 insertions(+), 9 deletions(-) create mode 100644 src/components/ProfileForm.css create mode 100644 src/components/ProfileForm.jsx diff --git a/src/App.jsx b/src/App.jsx index a524fa0..9e83a6b 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -8,6 +8,7 @@ import { import Dashboard from './components/Dashboard'; import Login from './components/Login'; import Register from './components/Register'; +import ProfileForm from './components/ProfileForm'; import './App.css'; @@ -19,6 +20,7 @@ function App() { } /> } /> } /> + } /> ); diff --git a/src/api/loginApi.js b/src/api/loginApi.js index 717ab4d..c3cba83 100644 --- a/src/api/loginApi.js +++ b/src/api/loginApi.js @@ -20,3 +20,21 @@ export const loginApi = { } }, }; + +export const userApi = { + get_user_profile: async (userId) => { + const reponse = await fetch( + `${AUTH_API_BASE_URL}/api/v1/user/profile/${userId}`, + { + method: 'GET', + headers: { 'Content-Type': 'application/json' }, + } + ); + + if (reponse.ok) { + return reponse.json(); + } else { + throw new Error('Error logging in'); + } + }, +}; diff --git a/src/components/Dashboard.jsx b/src/components/Dashboard.jsx index cf5148a..1a44675 100644 --- a/src/components/Dashboard.jsx +++ b/src/components/Dashboard.jsx @@ -1,7 +1,7 @@ import { useState } from 'react'; +import { useNavigate } from 'react-router-dom'; import AddContact from './AddContact'; -// import ViewContact from './ViewContact'; import ViewSentMessages from './ViewSentMessages'; import './Dashboard.css'; @@ -9,12 +9,12 @@ import SendMessageWizardModal from './SendMessageWizard/SendMessageWizardModal'; import ViewContactWizardModal from './ViewContactWizard/ViewContactWizardModal'; const Dashboard = () => { + const navigate = useNavigate(); const [activeView, setActiveView] = useState('dashboard'); const [isWizardOpen, setIsWizardOpen] = useState(false); const [isViewContactWizardOpen, setIsViewContactWizardOpen] = useState(false); const [isViewSentMessagesOpen, setViewSentMessagesOpen] = useState(false); const [showContactForm, setShowContactForm] = useState(false); - // const [isPopupOpen, setIsPopupOpen] = useState(false); const handleAddContactClick = () => { setShowContactForm(true); @@ -22,15 +22,9 @@ const Dashboard = () => { const handleContactSuccess = (contactData) => { console.log('Contact created successfully:', contactData); - - // You could: - // 1. Refresh the contacts list if you have one - // 2. Show a success notification - // 3. Update local state with the new contact }; const handleWizardComplete = () => { - // Add your logic here for each button setIsWizardOpen(false); }; @@ -47,7 +41,11 @@ const Dashboard = () => { }; const handleNavClick = (view) => { - setActiveView(view); + if (view === 'profile') { + navigate('/user/profile'); + } else { + setActiveView(view); + } }; return ( diff --git a/src/components/ProfileForm.css b/src/components/ProfileForm.css new file mode 100644 index 0000000..31bd471 --- /dev/null +++ b/src/components/ProfileForm.css @@ -0,0 +1,41 @@ +.profile-form { + max-width: 400px; + 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 { + text-align: center; + margin-bottom: 20px; +} + +.profile-form form { + display: flex; + flex-direction: column; +} + +.profile-form div { + margin-bottom: 15px; +} + +.profile-form label { + font-weight: bold; + margin-bottom: 5px; + display: block; +} + +.profile-form input[type='text'], +.profile-form input[type='tel'] { + width: 100%; + padding: 8px; + border: 1px solid #ccc; + border-radius: 4px; +} + +.profile-form input[readonly] { + background-color: #f9f9f9; +} diff --git a/src/components/ProfileForm.jsx b/src/components/ProfileForm.jsx new file mode 100644 index 0000000..2ed853e --- /dev/null +++ b/src/components/ProfileForm.jsx @@ -0,0 +1,161 @@ +import React, { useState, useEffect } from 'react'; +import { useNavigate } from 'react-router-dom'; + +import { tokenService } from '../services/TokenService'; +import { userApi } from '../api/loginApi'; + +import './ProfileForm.css'; + +const ProfileForm = () => { + const navigate = useNavigate(); + const [activeView, setActiveView] = useState('profile'); + const [formData, setFormData] = useState({ + firstname: '', + lastname: '', + phone: '', + username: '', + createdDate: new Date().toISOString().split('T')[0], + lastLoginDate: new Date().toISOString().split('T')[0], + }); + + useEffect(() => { + const fetchData = async () => { + const userId = tokenService.getUserId(); + const response = await userApi.get_user_profile(userId); + + if (response) { + const userProfile = response.data[0]; + setFormData((prev) => ({ + ...prev, + firstname: userProfile.firstname, + lastname: userProfile.lastname, + phone: userProfile.phone_number, + username: userProfile.username, + createdDate: userProfile.created, + lastLoginDate: userProfile.last_login, + })); + } else { + console.error('Error getting user profile'); + } + }; + + fetchData(); + }, []); + + const handleChange = (e) => { + const { name, value } = e.target; + setFormData({ ...formData, [name]: value }); + }; + + const handleNavClick = (view) => { + if (view === 'profile') { + navigate('/user/profile'); + } else { + navigate(`/${view}`); + } + }; + + return ( +
+ {/* Navbar */} + + + {/* Main Content */} +
+

User Profile

+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+
+ ); +}; + +export default ProfileForm;