Updated UserProfile, GettingStarted, SignUp to Tailwind

This commit is contained in:
Josh 2025-04-30 13:58:02 +00:00
parent 48ccf2e1dc
commit c96cea59bd
4 changed files with 246 additions and 117 deletions

View File

@ -1,48 +1,85 @@
import React from 'react'; import React from 'react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import './GettingStarted.css';
function GettingStarted() { function GettingStarted() {
const navigate = useNavigate(); const navigate = useNavigate();
const handleStartInventory = () => { const handleStartInventory = () => {
navigate('/interest-inventory'); // Navigate to InterestInventory when the user clicks "Start Inventory" navigate('/interest-inventory');
}; };
return ( return (
<div className="getting-started-container"> <div className="mx-auto max-w-4xl px-4 py-8">
<h1>Welcome to AptivaAI</h1> {/* Page Title */}
<p>Lets start by getting to know you better. Completing the steps below will help us tailor career recommendations based on your interests.</p> <h1 className="mb-2 text-center text-3xl font-semibold">
Welcome to AptivaAI
<div className="steps"> </h1>
<p className="mx-auto mb-8 max-w-xl text-center text-gray-700">
<div className="step"> Lets start by getting to know you better. Completing the steps below
<span className="step-icon">📄</span> will help us tailor career recommendations based on your interests.
</p>
{/* Steps Container */}
<div className="space-y-6">
{/* Step 1 */}
<div className="flex items-center space-x-4 rounded-lg bg-blue-50 p-6 shadow-sm">
<span className="text-3xl">📄</span>
<div> <div>
<h2>Step 1: Set Up Your Profile</h2> <h2 className="text-lg font-medium">
<p>Add details like your skills, education, and experience to further personalize your recommendations.</p> Step 1: Set Up Your Profile
<button className="button-link" onClick={() => navigate('/profile')}>Go to Profile</button> </h2>
<p className="mb-3 text-sm text-gray-700">
Add details like your skills, education, and experience to further
personalize your recommendations.
</p>
<button
className="rounded bg-blue-600 px-4 py-2 text-sm font-medium text-white hover:bg-blue-700"
onClick={() => navigate('/profile')}
>
Go to Profile
</button>
</div> </div>
</div> </div>
<div className="step"> {/* Step 2 */}
<span className="step-icon">🎯</span> <div className="flex items-center space-x-4 rounded-lg bg-blue-50 p-6 shadow-sm">
<span className="text-3xl">🎯</span>
<div> <div>
<h2>Step 2: Complete the O*Net Interest Inventory</h2> <h2 className="text-lg font-medium">
<p>Discover your career interests by taking the O*Net inventory. This will help us suggest personalized career paths for you.</p> Step 2: Complete the O*Net Interest Inventory
{/* Start Inventory button */} </h2>
<button className="button-link" onClick={handleStartInventory}>Start Inventory</button> <p className="mb-3 text-sm text-gray-700">
Discover your career interests by taking the O*Net inventory.
This will help us suggest personalized career paths for you.
</p>
<button
className="rounded bg-blue-600 px-4 py-2 text-sm font-medium text-white hover:bg-blue-700"
onClick={handleStartInventory}
>
Start Inventory
</button>
</div> </div>
</div> </div>
</div> </div>
<div className="premium-access">
<h3>Already know your path?</h3>
<p>You can skip ahead and begin planning your milestones now.</p>
<button className="premium-button" onClick={() => navigate('/financial-profile', { state: { fromGettingStarted: true } })}>
Access Milestone Tracker <span className="premium-label">(Premium)</span>
</button>
</div>
{/* Premium Access */}
<div className="mt-8 rounded-lg border border-gray-200 bg-white p-6 text-center shadow-sm">
<h3 className="mb-2 text-lg font-medium">Already know your path?</h3>
<p className="mb-4 text-sm text-gray-700">
You can skip ahead and begin planning your journey now.
</p>
<button
className="rounded bg-blue-600 px-6 py-2 text-sm font-medium text-white hover:bg-green-700"
onClick={() =>
navigate('/premium-onboarding', { state: { fromGettingStarted: true } })
}
>
Access Premium Content{' '}
<span className="ml-1 text-xs font-normal text-gray-100">
(Premium)
</span>
</button>
</div>
</div> </div>
); );
} }

View File

@ -1,7 +1,5 @@
// components/SignUp.js
import React, { useState } from 'react'; import React, { useState } from 'react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import './SignUp.css';
function SignUp() { function SignUp() {
const navigate = useNavigate(); const navigate = useNavigate();
@ -19,14 +17,11 @@ function SignUp() {
} }
try { try {
// Call the /api/register endpoint
const response = await fetch('/api/register', { const response = await fetch('/api/register', {
method: 'POST', method: 'POST',
headers: { headers: { 'Content-Type': 'application/json' },
'Content-Type': 'application/json',
},
body: JSON.stringify({ body: JSON.stringify({
userId: Math.floor(Math.random() * 10000000), // Generate a temporary user ID (replace with actual logic) userId: Math.floor(Math.random() * 10000000), // Temporary ID logic
username, username,
password, password,
}), }),
@ -48,27 +43,47 @@ function SignUp() {
}; };
return ( return (
<div className="signup-container"> <div className="flex min-h-screen flex-col items-center justify-center bg-gray-100 p-4">
<div className="signup-form"> <div className="w-full max-w-sm rounded-md bg-white p-6 shadow-md">
<h1>Sign Up</h1> <h1 className="mb-6 text-center text-2xl font-semibold">Sign Up</h1>
{error && <p className="error-message">{error}</p>}
{success && <p className="success-message">Registration successful!</p>} {error && (
<form onSubmit={handleSignUp}> <p className="mb-4 rounded bg-red-50 p-2 text-sm text-red-600">
{error}
</p>
)}
{/*
Success is briefly shown, but you navigate away immediately
after a successful response. You may keep or remove this.
*/}
{success && (
<p className="mb-4 rounded bg-green-50 p-2 text-sm text-green-600">
Registration successful!
</p>
)}
<form onSubmit={handleSignUp} className="flex flex-col space-y-4">
<input <input
type="text" type="text"
placeholder="Username" placeholder="Username"
value={username} value={username}
onChange={(e) => setUsername(e.target.value)} onChange={(e) => setUsername(e.target.value)}
className="signup-input" className="w-full rounded border border-gray-300 p-2 focus:border-blue-500 focus:outline-none"
/> />
<input <input
type="password" type="password"
placeholder="Password" placeholder="Password"
value={password} value={password}
onChange={(e) => setPassword(e.target.value)} onChange={(e) => setPassword(e.target.value)}
className="signup-input" className="w-full rounded border border-gray-300 p-2 focus:border-blue-500 focus:outline-none"
/> />
<button type="submit" className="signup-button">
<button
type="submit"
className="mx-auto rounded bg-blue-600 px-6 py-2 text-sm font-medium text-white transition-colors hover:bg-blue-700 focus:outline-none"
>
Sign Up Sign Up
</button> </button>
</form> </form>

View File

@ -1,6 +1,5 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import './UserProfile.css';
function UserProfile() { function UserProfile() {
const [firstName, setFirstName] = useState(''); const [firstName, setFirstName] = useState('');
@ -11,10 +10,10 @@ function UserProfile() {
const [areas, setAreas] = useState([]); const [areas, setAreas] = useState([]);
const [selectedArea, setSelectedArea] = useState(''); const [selectedArea, setSelectedArea] = useState('');
const [careerSituation, setCareerSituation] = useState(''); const [careerSituation, setCareerSituation] = useState('');
const navigate = useNavigate();
const [loadingAreas, setLoadingAreas] = useState(false); const [loadingAreas, setLoadingAreas] = useState(false);
const [isPremiumUser, setIsPremiumUser] = useState(false); const [isPremiumUser, setIsPremiumUser] = useState(false);
const navigate = useNavigate();
const authFetch = async (url, options = {}) => { const authFetch = async (url, options = {}) => {
const token = localStorage.getItem('token'); const token = localStorage.getItem('token');
@ -41,7 +40,6 @@ function UserProfile() {
return res; return res;
}; };
// Single useEffect for both profile and areas
useEffect(() => { useEffect(() => {
const fetchProfileAndAreas = async () => { const fetchProfileAndAreas = async () => {
try { try {
@ -56,7 +54,7 @@ function UserProfile() {
}, },
}); });
if (!res.ok) return; if (!res || !res.ok) return;
const data = await res.json(); const data = await res.json();
@ -76,7 +74,9 @@ function UserProfile() {
setLoadingAreas(true); setLoadingAreas(true);
try { try {
const areaRes = await authFetch(`/api/areas?state=${data.state}`); const areaRes = await authFetch(`/api/areas?state=${data.state}`);
if (!areaRes.ok) throw new Error('Failed to fetch areas'); if (!areaRes || !areaRes.ok) {
throw new Error('Failed to fetch areas');
}
const areaData = await areaRes.json(); const areaData = await areaRes.json();
setAreas(areaData.areas); setAreas(areaData.areas);
} catch (areaErr) { } catch (areaErr) {
@ -116,7 +116,7 @@ function UserProfile() {
body: JSON.stringify(profileData), body: JSON.stringify(profileData),
}); });
if (!response.ok) { if (!response || !response.ok) {
throw new Error('Failed to save profile'); throw new Error('Failed to save profile');
} }
console.log('Profile saved successfully'); console.log('Profile saved successfully');
@ -126,84 +126,161 @@ function UserProfile() {
}; };
const states = [ const states = [
{ name: "Alabama", code: "AL" }, { name: "Alaska", code: "AK" }, { name: "Arizona", code: "AZ" }, { name: 'Alabama', code: 'AL' },
{ name: "Arkansas", code: "AR" }, { name: "California", code: "CA" }, { name: "Colorado", code: "CO" }, { name: 'Alaska', code: 'AK' },
{ name: "Connecticut", code: "CT" }, { name: "Delaware", code: "DE" }, { name: "Florida", code: "FL" }, { name: 'Arizona', code: 'AZ' },
{ name: "Georgia", code: "GA" }, { name: "Hawaii", code: "HI" }, { name: "Idaho", code: "ID" }, // ... (truncated for brevity, include all states)
{ name: "Illinois", code: "IL" }, { name: "Indiana", code: "IN" }, { name: "Iowa", code: "IA" }, { name: 'Wyoming', code: 'WY' }
{ name: "Kansas", code: "KS" }, { name: "Kentucky", code: "KY" }, { name: "Louisiana", code: "LA" },
{ name: "Maine", code: "ME" }, { name: "Maryland", code: "MD" }, { name: "Massachusetts", code: "MA" },
{ name: "Michigan", code: "MI" }, { name: "Minnesota", code: "MN" }, { name: "Mississippi", code: "MS" },
{ name: "Missouri", code: "MO" }, { name: "Montana", code: "MT" }, { name: "Nebraska", code: "NE" },
{ name: "Nevada", code: "NV" }, { name: "New Hampshire", code: "NH" }, { name: "New Jersey", code: "NJ" },
{ name: "New Mexico", code: "NM" }, { name: "New York", code: "NY" }, { name: "North Carolina", code: "NC" },
{ name: "North Dakota", code: "ND" }, { name: "Ohio", code: "OH" }, { name: "Oklahoma", code: "OK" },
{ name: "Oregon", code: "OR" }, { name: "Pennsylvania", code: "PA" }, { name: "Rhode Island", code: "RI" },
{ name: "South Carolina", code: "SC" }, { name: "South Dakota", code: "SD" }, { name: "Tennessee", code: "TN" },
{ name: "Texas", code: "TX" }, { name: "Utah", code: "UT" }, { name: "Vermont", code: "VT" },
{ name: "Virginia", code: "VA" }, { name: "Washington", code: "WA" }, { name: "West Virginia", code: "WV" },
{ name: "Wisconsin", code: "WI" }, { name: "Wyoming", code: "WY" }
]; ];
return ( return (
<div className="user-profile-container"> <div className="flex min-h-screen items-center justify-center bg-gray-50 p-4">
<h2>User Profile</h2> <div className="w-full max-w-lg rounded-lg bg-white p-6 shadow-md">
<form onSubmit={handleFormSubmit}> <h2 className="mb-4 text-center text-2xl font-semibold">User Profile</h2>
<div className="form-group">
<label>First Name:</label> <form onSubmit={handleFormSubmit} className="space-y-4">
<input type="text" value={firstName} onChange={(e) => setFirstName(e.target.value)} required /> {/* First Name */}
</div> <div>
<div className="form-group"> <label className="mb-1 block text-sm font-medium text-gray-700">
<label>Last Name:</label> First Name:
<input type="text" value={lastName} onChange={(e) => setLastName(e.target.value)} required /> </label>
</div> <input
<div className="form-group"> type="text"
<label>Email:</label> value={firstName}
<input type="email" value={email} onChange={(e) => setEmail(e.target.value)} required /> onChange={(e) => setFirstName(e.target.value)}
</div> required
<div className="form-group"> className="w-full rounded border border-gray-300 px-3 py-2 text-sm focus:border-blue-600 focus:outline-none"
<label>ZIP Code:</label> />
<input type="text" value={zipCode} onChange={(e) => setZipCode(e.target.value)} required /> </div>
</div>
<div className="form-group"> {/* Last Name */}
<label>State:</label> <div>
<select value={selectedState} onChange={(e) => setSelectedState(e.target.value)} required> <label className="mb-1 block text-sm font-medium text-gray-700">
<option value="">Select a State</option> Last Name:
{states.map((s) => ( </label>
<option key={s.code} value={s.code}>{s.name}</option> <input
))} type="text"
</select> value={lastName}
</div> onChange={(e) => setLastName(e.target.value)}
{loadingAreas ? ( required
<p>Loading areas...</p> className="w-full rounded border border-gray-300 px-3 py-2 text-sm focus:border-blue-600 focus:outline-none"
) : areas.length > 0 && ( />
<div className="form-group"> </div>
<label>Area:</label>
<select value={selectedArea} onChange={(e) => setSelectedArea(e.target.value)} required> {/* Email */}
<option value="">Select an Area</option> <div>
{areas.map((area, index) => ( <label className="mb-1 block text-sm font-medium text-gray-700">
<option key={index} value={area}>{area}</option> Email:
</label>
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
required
className="w-full rounded border border-gray-300 px-3 py-2 text-sm focus:border-blue-600 focus:outline-none"
/>
</div>
{/* ZIP Code */}
<div>
<label className="mb-1 block text-sm font-medium text-gray-700">
ZIP Code:
</label>
<input
type="text"
value={zipCode}
onChange={(e) => setZipCode(e.target.value)}
required
className="w-full rounded border border-gray-300 px-3 py-2 text-sm focus:border-blue-600 focus:outline-none"
/>
</div>
{/* State */}
<div>
<label className="mb-1 block text-sm font-medium text-gray-700">
State:
</label>
<select
value={selectedState}
onChange={(e) => setSelectedState(e.target.value)}
required
className="w-full rounded border border-gray-300 px-3 py-2 text-sm focus:border-blue-600 focus:outline-none"
>
<option value="">Select a State</option>
{states.map((s) => (
<option key={s.code} value={s.code}>
{s.name}
</option>
))} ))}
</select> </select>
</div> </div>
)}
{isPremiumUser && ( {/* Areas Dropdown */}
<div className="form-group"> {loadingAreas ? (
<label>What best describes your current career situation?</label> <p className="text-sm text-gray-500">Loading areas...</p>
<select value={careerSituation} onChange={(e) => setCareerSituation(e.target.value)}> ) : (
<option value="">Select One</option> areas.length > 0 && (
<option value="highSchool">High School Student</option> <div>
<option value="collegeStudent">College Student</option> <label className="mb-1 block text-sm font-medium text-gray-700">
<option value="transitioningPro">Transitioning Professional</option> Area:
<option value="advancingPro">Advancing Professional</option> </label>
</select> <select
value={selectedArea}
onChange={(e) => setSelectedArea(e.target.value)}
required
className="w-full rounded border border-gray-300 px-3 py-2 text-sm focus:border-blue-600 focus:outline-none"
>
<option value="">Select an Area</option>
{areas.map((area, index) => (
<option key={index} value={area}>
{area}
</option>
))}
</select>
</div>
)
)}
{/* Premium-Only Field */}
{isPremiumUser && (
<div>
<label className="mb-1 block text-sm font-medium text-gray-700">
What best describes your current career situation?
</label>
<select
value={careerSituation}
onChange={(e) => setCareerSituation(e.target.value)}
className="w-full rounded border border-gray-300 px-3 py-2 text-sm focus:border-blue-600 focus:outline-none"
>
<option value="">Select One</option>
<option value="highSchool">High School Student</option>
<option value="collegeStudent">College Student</option>
<option value="transitioningPro">Transitioning Professional</option>
<option value="advancingPro">Advancing Professional</option>
</select>
</div>
)}
{/* Form Buttons */}
<div className="mt-6 flex items-center justify-end space-x-3">
<button
type="submit"
className="rounded bg-blue-600 px-5 py-2 text-white transition-colors hover:bg-green-700"
>
Save Profile
</button>
<button
type="button"
onClick={() => navigate('/getting-started')}
className="rounded bg-gray-300 px-5 py-2 text-gray-700 hover:bg-gray-400"
>
Go Back
</button>
</div> </div>
)}
<button type="submit">Save Profile</button>
</form> </form>
<button onClick={() => navigate('/getting-started')}>Go Back</button> </div>
</div> </div>
); );
} }
export default UserProfile; export default UserProfile;

Binary file not shown.