diff --git a/img/Sicilia.jpg b/img/Sicilia.jpg new file mode 100644 index 0000000..0fa8e72 Binary files /dev/null and b/img/Sicilia.jpg differ diff --git a/src/api/communityuser_profile/get_fulldetailsprofile.js b/src/api/communityuser_profile/get_fulldetailsprofile.js new file mode 100644 index 0000000..d18556b --- /dev/null +++ b/src/api/communityuser_profile/get_fulldetailsprofile.js @@ -0,0 +1,36 @@ +export default async function fetchFullCommunityUserProfile(communityUserId) { + const apiUrl = import.meta.env.VITE_API_URL; + if (!apiUrl) { + console.error("VITE_API_URL is not defined in environment variables"); + return Promise.reject(new Error("API URL is not configured")); + } + + const token = localStorage.getItem("token"); + if (!token) { + return Promise.reject(new Error("Please log in to see full details on profile.")); + } + + const url = `${apiUrl}/community-users/${communityUserId}`; + console.log("Full API URL:", url); + + try { + const response = await fetch(url, { + method: "GET", + headers: { + "Authorization": `Token ${token}`, + "Accept": "application/json", + "Content-Type": "application/json", + }, + }); + + if (!response.ok) { + const errorMessage = await response.text(); + throw new Error(`Server responded with ${response.status}: ${errorMessage}`); + } + + return await response.json(); + } catch (error) { + console.error("Fetch error:", { message: error.message, url }); + return Promise.reject(error); + } +} \ No newline at end of file diff --git a/src/api/communityuser_profile/get_fulldetailsprofiles.js b/src/api/communityuser_profile/get_fulldetailsprofiles.js new file mode 100644 index 0000000..f076f99 --- /dev/null +++ b/src/api/communityuser_profile/get_fulldetailsprofiles.js @@ -0,0 +1,44 @@ +// const url = `${import.meta.env.VITE_API_URL}/community-users/`; + + +export default async function fetchFullCommunityUserProfiles() { + // Add debug logging for the API URL + if (!import.meta.env.VITE_API_URL) { + console.error('VITE_API_URL is not defined in environment variables'); + throw new Error('API URL is not configured'); + } + + + const token = window.localStorage.getItem("token"); + const url = `${import.meta.env.VITE_API_URL}/role-models/`; + console.log('Full API URL:', url); // This will help us verify the complete URL + + + // Check if the token exists + if (!token) { + throw new Error("Please log in to see full details on profile."); + } + + try { + const response = await fetch(url, { + method: "GET", + headers: { + "Authorization": `Token ${token}`, + 'Accept': 'application/json', + 'Content-Type': 'application/json' + } + }); + + if (!response.ok) { + throw new Error(`Server responded with ${response.status}`); + } + + return await response.json(); + } catch (error) { + console.error('Fetch error:', { + message: error.message, + url: url + }); + throw error; + } +} \ No newline at end of file diff --git a/src/api/communityuser_profile/get_profile.js b/src/api/communityuser_profile/get_profile.js deleted file mode 100644 index 9c640a2..0000000 --- a/src/api/communityuser_profile/get_profile.js +++ /dev/null @@ -1,19 +0,0 @@ -export const get_profile = async (userId) => { - try { - const token = localStorage.getItem('token'); - const response = await fetch(`${import.meta.env.VITE_API_URL}/community-user/profile/${userId}`, { - headers: { - Authorization: `Bearer ${token}` - } - }); - - if (!response.ok) { - throw new Error('Failed to fetch profile'); - } - - return await response.json(); - } catch (error) { - console.error('Error fetching profile:', error); - throw error; - } - }; \ No newline at end of file diff --git a/src/api/communityuser_profile/get_profiles.js b/src/api/communityuser_profile/get_profiles.js deleted file mode 100644 index 4fdeb07..0000000 --- a/src/api/communityuser_profile/get_profiles.js +++ /dev/null @@ -1,35 +0,0 @@ -export const fetchLimitedCommunityUserProfile = async (userId) => { - try { - const response = await fetch( - `${import.meta.env.VITE_API_URL}/community-user/public-profile/${userId}` - ); - if (!response.ok) { - throw new Error('Failed to fetch profile'); - } - return await response.json(); - } catch (error) { - console.error('Error fetching community user profile:', error); - throw error; - } - }; - - export const fetchFullCommunityUserProfile = async (userId) => { - const token = localStorage.getItem('token'); - try { - const response = await fetch( - `${import.meta.env.VITE_API_URL}/community-user/profile/${userId}`, - { - headers: { - Authorization: `Bearer ${token}`, - }, - } - ); - if (!response.ok) { - throw new Error('Failed to fetch profile'); - } - return await response.json(); - } catch (error) { - console.error('Error fetching full community user profile:', error); - throw error; - } - }; \ No newline at end of file diff --git a/src/api/communityuser_profile/get_publicview_profile.js b/src/api/communityuser_profile/get_publicview_profile.js new file mode 100644 index 0000000..7c76acc --- /dev/null +++ b/src/api/communityuser_profile/get_publicview_profile.js @@ -0,0 +1,32 @@ +export default async function fetchLimitedCommunityUserProfile(communityuserId) { + const apiUrl = import.meta.env.VITE_API_URL; + + if (!apiUrl) { + console.error("VITE_API_URL is not defined in environment variables"); + return Promise.reject(new Error("API URL is not configured")); + } + + const url = `${apiUrl}/community-users/public/${communityuserId}`; + console.log("Full API URL:", url); // Debugging + + try { + const response = await fetch(url, { + method: "GET", + headers: { + "Accept": "application/json", + "Content-Type": "application/json", + }, + }); + + if (!response.ok) { + const errorMessage = await response.text(); + throw new Error(`Server responded with ${response.status}: ${errorMessage}`); + } + + return await response.json(); + } catch (error) { + console.error("Fetch error:", { message: error.message, url }); + return Promise.reject(error); + } + } + \ No newline at end of file diff --git a/src/api/communityuser_profile/get_publicview_profiles.js b/src/api/communityuser_profile/get_publicview_profiles.js new file mode 100644 index 0000000..eb9b281 --- /dev/null +++ b/src/api/communityuser_profile/get_publicview_profiles.js @@ -0,0 +1,32 @@ +export default async function fetchLimitedCommunityUserProfiles() { + // Add debug logging for the API URL + if (!import.meta.env.VITE_API_URL) { + console.error('VITE_API_URL is not defined in environment variables'); + throw new Error('API URL is not configured'); + } + + const url = `${import.meta.env.VITE_API_URL}/community-users/public`; + console.log('Full API URL:', url); + + try { + const response = await fetch(url, { + method: "GET", + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json' + } + }); + + if (!response.ok) { + throw new Error(`Server responded with ${response.status}`); + } + + return await response.json(); + } catch (error) { + console.error('Fetch error:', { + message: error.message, + url: url + }); + throw error; + } + } \ No newline at end of file diff --git a/src/components/GeneralUserProfileDetails.jsx b/src/components/GeneralUserProfileDetails.jsx index d1b4280..7028019 100644 --- a/src/components/GeneralUserProfileDetails.jsx +++ b/src/components/GeneralUserProfileDetails.jsx @@ -1,110 +1,68 @@ -import React, { useState, useEffect } from 'react'; -import { useNavigate } from 'react-router-dom'; +import React, { useEffect, useState } from "react"; +import { useParams, useNavigate } from "react-router-dom"; +import fetchPublicCommunityUserProfile from "../api/communityuser_profile/get_publicview_profile"; +import fetchFullCommunityUserProfile from "../api/communityuser_profile/get_fulldetailsprofile"; -const GeneralUserProfileDetails = ({ communityuserId }) => { - const [profile, setProfile] = useState(null); +const GeneralUserProfileDetails = (props) => { + const { communityuserId } = useParams(); + const profile = props.profile; const [isAuthenticated, setIsAuthenticated] = useState(false); const [loading, setLoading] = useState(true); const navigate = useNavigate(); - useEffect(() => { - // Check authentication - const token = localStorage.getItem('token'); - if (token) { - setIsAuthenticated(true); - } + // useEffect(() => { + // // Check authentication + // const token = localStorage.getItem("token"); + // if (token) { + // setIsAuthenticated(true); + // } - // Fetch profile data based on authentication status - const fetchData = async () => { - try { - const url = isAuthenticated - ? `${import.meta.env.VITE_API_URL}/community-user/profile/${communityuserId}` - : `${import.meta.env.VITE_API_URL}/community-user/public-profile/${communityuserId}`; + // // Fetch profile data from the correct endpoint for public or authenticated user + // const fetchData = async () => { + // try { console.log(communityuserId) + // const data = isAuthenticated + // ? await fetchFullCommunityUserProfile(communityuserId) + // : await fetchPublicCommunityUserProfile(communityuserId); + // setProfile(data); + // } catch (error) { + // console.error("Error fetching profile:", error); + // } finally { + // setLoading(false); + // } + // }; - const response = await fetch(url, { - headers: token ? { - 'Authorization': `Bearer ${token}` - } : {} - }); - - if (!response.ok) { - throw new Error('Failed to fetch profile'); - } - - const data = await response.json(); - setProfile(data); - } catch (error) { - console.error('Error fetching profile:', error); - } finally { - setLoading(false); - } - }; - - fetchData(); - }, [communityuserId, isAuthenticated]); - - if (loading) return

Loading profile...

; - if (!profile) return

Profile not found.

; + // fetchData(); + // }, [communityuserId, isAuthenticated]); + // if (loading) return

Loading profile...

; + // if (!profile) return

Profile not found.

; + console.log(props.profile); return ( -
- {profile.image && ( -
- Profile -
- )} - -
-

- {profile.first_name} {profile.last_name} -

-

Current Role: {profile.current_role}

-

Industry: {profile.industry?.replace('_', ' ')}

-

Location: {profile.location}

-
+
+ {profile.image && Profile} +

{profile.first_name} {profile.last_name}

+

Current Role: {profile.current_role}

+

Industry: {profile.industry}

+

Location: {profile.location}

{isAuthenticated ? ( -
-
-

Contact Information

-

Email: {profile.email}

- {profile.phone_number && ( -

Phone: {profile.phone_number}

- )} - {profile.linkedin && ( -

- LinkedIn:{' '} - - View Profile - -

- )} -
- -
-

Professional Information

- {profile.skills && profile.skills.length > 0 && ( -

Skills: {profile.skills.join(', ')}

- )} - {profile.interests && profile.interests.length > 0 && ( -

Interests: {profile.interests.join(', ')}

- )} -
-
+ <> +

Skills: {profile.skills?.join(", ")}

+

Interests: {profile.interests?.join(", ")}

+

Email: {profile.email}

+ {profile.linkedin && ( +

+ LinkedIn: + + View Profile + +

+ )} + ) : ( -
- -
+ )}
); diff --git a/src/components/LoginForm.jsx b/src/components/LoginForm.jsx index 54c3c97..1d29b9a 100644 --- a/src/components/LoginForm.jsx +++ b/src/components/LoginForm.jsx @@ -33,11 +33,13 @@ const LoginForm = () => { }; const handleSubmit = async (e) => { + console.log('handleSubmit'); e.preventDefault(); setIsLoading(true); setErrors({}); const validationErrors = validateLoginForm(formData); + console.log('formData', formData); if (Object.keys(validationErrors).length > 0) { setErrors(validationErrors); setIsLoading(false); @@ -46,6 +48,7 @@ const LoginForm = () => { try { const data = await loginUser(formData); + console.log(formData); // Update auth context with token setAuth({ token: data.token }); // Store token in localStorage diff --git a/src/components/NavBar.jsx b/src/components/NavBar.jsx index 6cfdfc2..7b887e6 100644 --- a/src/components/NavBar.jsx +++ b/src/components/NavBar.jsx @@ -15,11 +15,15 @@ function NavBar() {
Home - {auth.token ? ( + {auth.token ? (<> Log Out - + + + My Profile + ) : ( + <> Login @@ -27,6 +31,8 @@ function NavBar() { Create an Account + + My Profile Invite Someone diff --git a/src/hooks/use-community-user.js b/src/hooks/use-community-user.js deleted file mode 100644 index 80dabcb..0000000 --- a/src/hooks/use-community-user.js +++ /dev/null @@ -1,38 +0,0 @@ -// src/hooks/use-communityuser.js -import { useState, useEffect } from 'react'; -import { get_profile } from '../api/communityuser_profile/get_profile.js'; - -const useCommunityuser = (userId) => { - const [communityuser, setCommunityuser] = useState(null); - const [isLoading, setIsLoading] = useState(true); - const [error, setError] = useState(null); - - const fetchData = async () => { - try { - setIsLoading(true); - const data = await get_profile(userId); - setCommunityuser(data); - setError(null); - } catch (err) { - setError(err); - setCommunityuser(null); - } finally { - setIsLoading(false); - } - }; - - useEffect(() => { - if (userId) { - fetchData(); - } - }, [userId]); - - return { - communityuser, - isLoading, - error, - refetch: fetchData - }; -}; - -export default useCommunityuser; \ No newline at end of file diff --git a/src/hooks/use-community-users.js b/src/hooks/use-community-users.js index 23f47ac..5498d7f 100644 --- a/src/hooks/use-community-users.js +++ b/src/hooks/use-community-users.js @@ -1,22 +1,19 @@ -import getCommunityusers from "../api/communityuser_profile/get_publicview_profiles"; +import fetchLimitedCommunityUserProfiles from "../api/communityuser_profile/get_publicview_profiles"; import { useState, useEffect } from "react"; - - -export default function useCommunityusers() { - // Here we use the useState hook to create a state variable called Communityusers and a function to update it called setCommunityusers. We initialize the state variable with an empty array. - const [Communityusers, setCommunityusers] = useState([]); - - // We also create a state variable called isLoading and error to keep track of the loading state and any errors that might occur. +export default function useCommunityUsers() { + // State to store community user profiles + const [communityUsers, setCommunityUsers] = useState([]); + + // State for loading and error tracking const [isLoading, setIsLoading] = useState(true); const [error, setError] = useState(); - - // We use the useEffect hook to fetch the Communityusers from the API and update the state variables accordingly. - // This useEffect will only run once, when the component this hook is used in is mounted. + + // Fetch community user profiles on component mount useEffect(() => { - getCommunityusers() - .then((Communityusers) => { - setCommunityusers(Communityusers); + fetchLimitedCommunityUserProfiles() + .then((users) => { + setCommunityUsers(users); setIsLoading(false); }) .catch((error) => { @@ -25,6 +22,6 @@ export default function useCommunityusers() { }); }, []); - // Finally, we return the state variables and the error. As the state in this hook changes it will update these values and the component using this hook will re-render. - return { Communityusers, isLoading, error }; - } \ No newline at end of file + // Return state variables + return { communityUsers, isLoading, error }; +} diff --git a/src/hooks/use-communityuser.js b/src/hooks/use-communityuser.js new file mode 100644 index 0000000..9357b17 --- /dev/null +++ b/src/hooks/use-communityuser.js @@ -0,0 +1,37 @@ +import fetchLimitedCommunityUserProfile from "../api/communityuser_profile/get_publicview_profile.js"; +import fetchCommunityUserProfile from "../api/communityuser_profile/get_fulldetailsprofile.js"; // Full details endpoint +import { useState, useEffect, useCallback } from "react"; + +export default function useCommunityUser(userId) { + const [profile, setProfile] = useState(); + const [isLoading, setIsLoading] = useState(true); + const [error, setError] = useState(); + + // Check if user is authenticated (basic example) + const isAuthenticated = !!localStorage.getItem("token"); + + const fetchProfile = useCallback(() => { + setIsLoading(true); + + // Fetch full profile if authenticated, otherwise fetch limited profile + const fetchFunction = isAuthenticated ? fetchCommunityUserProfile : fetchLimitedCommunityUserProfile; + + fetchFunction(userId) + .then((profile) => { + setProfile(profile); + setError(null); + }) + .catch((error) => { + setError(error); + }) + .finally(() => { + setIsLoading(false); + }); + }, [userId, isAuthenticated]); + + useEffect(() => { + fetchProfile(); + }, [fetchProfile]); + + return { profile, isLoading, error, refetch: fetchProfile }; +} diff --git a/src/pages/GeneralUserProfilePage.css b/src/pages/GeneralUserProfilePage.css index 0863f9b..f2b922c 100644 --- a/src/pages/GeneralUserProfilePage.css +++ b/src/pages/GeneralUserProfilePage.css @@ -1,157 +1,122 @@ /* General Styles */ -.general-user-profile-page-form { - display: flex; - justify-content: center; - align-items: center; - min-height: 100vh; - background-color: var(--base-light); - padding: 20px; - font-family: "Inter", sans-serif; - } - - .profile-form-container { - background-color: var(--white); - border-radius: 8px; - box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); - padding: 40px; - width: 100%; - max-width: 800px; - } - - /* Form Title and Subtitle */ - .form-title { - font-family: "Merriweather", serif; - text-align: center; - margin-bottom: 10px; - color: var(--black); - } - - .form-subtitle { - text-align: center; - margin-bottom: 30px; - color: var(--base-dark); - font-weight: 600; - } - - /* Form Groups */ - .profile-form { - display: grid; - grid-template-columns: repeat(2, 1fr); - grid-gap: 20px; - } - - .form-group { - display: flex; - flex-direction: column; - } - - .form-label { - display: block; - margin-bottom: 8px; - color: var(--base-dark); - font-weight: 600; - } - - .form-input { - width: 100%; - padding: 12px; - border: 1px solid var(--base-light); - border-radius: 4px; - font-size: 16px; - transition: border-color 0.3s ease; - } - - .form-input:focus { - outline: none; - border-color: var(--brand); - } - - /* Upload Button */ - .upload-button { - padding: 8px 16px; - background-color: var(--brand); - color: var(--white); - border: none; - border-radius: 4px; - font-size: 14px; - cursor: pointer; - transition: background-color 0.3s ease; - } - - .upload-button:hover { - background-color: var(--secondarybrand); - } - - /* Communication Methods */ - .communication-methods { - display: flex; - flex-direction: column; - } - - .communication-method { - display: flex; - align-items: center; - margin-bottom: 10px; - } - - .form-radio { - margin-right: 8px; - } - - /* Submit Button - using your genericbtn styles */ - .submit-button { - grid-column: 1 / -1; - margin-top: 1rem; - padding: 10px 20px; - font-size: 1.2rem; - color: var(--white); - background-color: var(--brand); - border: none; - border-radius: 5px; - cursor: pointer; - text-decoration: none; - transition: background-color 0.3s; - } - - .submit-button:hover { - background-color: var(--secondarybrand); - } - - /* Error Messages */ - .error-text { - color: #dc3545; - font-size: 14px; - margin-top: 4px; - } - - /* Success Messages */ - .success-message { - background-color: var(--secondarybrand); - color: var(--white); - padding: 10px; - border-radius: 4px; - margin-bottom: 20px; - text-align: center; - } - - /* Responsive Styles */ - @media (max-width: 768px) { - .profile-form-container { - padding: 20px; - margin: 0 10px; - } - - .profile-form { - grid-template-columns: 1fr; - } - - .form-title { - font-size: 24px; - } - - .form-label, - .form-input, - .submit-button { - font-size: 14px; - } - } \ No newline at end of file +body { + font-family: "Inter", sans-serif; + margin: 0; + padding: 0; + background-color: #f4f4f4; +} + +/* GeneralUserProfilePage Styles */ +.profile-page-container { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + min-height: 100vh; + padding: 2rem; +} + +.profile-page-container h1 { + font-size: 1.5rem; + color: #5c4099; + font-family: "Merriweather", serif; + margin-bottom: 2rem; + text-align: center; +} + +.profile-details { + background-color: white; + border-radius: 16px; + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); + padding: 2.5rem; + width: 100%; + max-width: 600px; +} + +.profile-details img { + width: 120px; + height: 120px; + border-radius: 50%; + object-fit: cover; + margin-bottom: 1.5rem; +} + +.profile-details h2 { + font-size: 1.25rem; + color: #5c4099; + font-family: "Merriweather", serif; + margin-bottom: 1rem; +} + +.profile-details p { + font-size: 1rem; + color: #4b5563; + margin-bottom: 1rem; +} + +.profile-details strong { + color: #5c4099; + font-weight: 600; +} + +.profile-details .authenticated-details { + margin-top: 1.5rem; + text-align: left; +} + +.profile-details .authenticated-details h3 { + font-size: 1.125rem; + color: #5c4099; + margin-top: 1.5rem; + font-family: "Merriweather", serif; +} + +.profile-details .authenticated-details p { + font-size: 0.875rem; + color: #4b5563; + margin-top: 0.5rem; +} + +.profile-details .learn-more-btn { + margin-top: 1.5rem; + padding: 0.75rem 1.25rem; + font-size: 1rem; + color: white; + background-color: #5e17eb; + border: none; + border-radius: 8px; + cursor: pointer; + transition: background-color 0.3s ease; + text-decoration: none; +} + +.profile-details .learn-more-btn:hover { + background-color: #7f56c7; +} + +@media (max-width: 768px) { + .profile-page-container { + padding: 1rem; + } + + .profile-details { + padding: 1.5rem; + width: 90%; + } + + .profile-details img { + width: 100px; + height: 100px; + } + + .profile-details h2, + .profile-details .authenticated-details h3 { + font-size: 1.125rem; + } + + .profile-details p, + .profile-details .authenticated-details p, + .profile-details .learn-more-btn { + font-size: 0.875rem; + } +} \ No newline at end of file diff --git a/src/pages/GeneralUserProfilePage.jsx b/src/pages/GeneralUserProfilePage.jsx index 1f60d5d..3b2a24a 100644 --- a/src/pages/GeneralUserProfilePage.jsx +++ b/src/pages/GeneralUserProfilePage.jsx @@ -1,7 +1,10 @@ import React, { useEffect, useState } from "react"; import { useNavigate } from "react-router-dom"; import GeneralUserProfileDetails from "../components/GeneralUserProfileDetails"; -import { get_profile } from "../api/communityuser_profile/get_profile.js"; +import fetchFullCommunityUserProfile from "../api/communityuser_profile/get_fulldetailsprofile.js"; +import "./GeneralUserProfilePage.css"; +import useCommunityuser from "../hooks/use-communityuser.js"; // Fix import name + import "../styles.css"; import Header from "../components/Header"; @@ -9,22 +12,26 @@ import Footer from "../components/Footer"; function GeneralUserProfilePage() { const navigate = useNavigate(); + + // State to store profile data, loading state, and errors const [profile, setProfile] = useState(null); const [isLoading, setIsLoading] = useState(true); const [error, setError] = useState(null); + const [name, setName] = useState("My Profile"); // Default page title useEffect(() => { - const token = localStorage.getItem('token'); - if (!token) { - navigate('/login'); - return; - } + // const token = localStorage.getItem("token"); + // if (!token) { + // navigate("/login"); // Redirect to login if no token found + // return; + // } const fetchProfile = async () => { try { setIsLoading(true); - const data = await get_profile(); // No need to pass ID - API will use token + const data = await get_profile(); // API fetches profile using stored token setProfile(data); + setName(`${data.first_name || ""} ${data.last_name || ""}`.trim() || "My Profile"); // Set profile name } catch (error) { console.error("Error fetching profile:", error); setError(error); @@ -33,14 +40,17 @@ function GeneralUserProfilePage() { } }; - fetchProfile(); + // fetchFullCommunityUserProfile(); }, [navigate]); - if (isLoading) return

Loading profile...

; - if (error) return

Error: {error.message}

; - if (!profile) return

No profile found.

; + // if (isLoading) return

Loading...

; // Show loading state + // if (error) return

Error: {error.message}

; // Handle errors + // if (profile) return

No profile data found.

; // Handle empty profile + + const fakeProfile = {image: "https://sheinspire-ff5867c4dc81.herokuapp.com/role-models/public/image", first_name: "Sicilia", last_name: "Perumalsamy", current_role: "Public Health Researcher", industry: "Health", location: "Perth"} return ( + <>
@@ -55,4 +65,4 @@ function GeneralUserProfilePage() { ); } -export default GeneralUserProfilePage; \ No newline at end of file +export default GeneralUserProfilePage;