Updated UserProfile, GettingStarted, SignUp to Tailwind
This commit is contained in:
parent
48ccf2e1dc
commit
c96cea59bd
@ -1,48 +1,85 @@
|
||||
import React from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import './GettingStarted.css';
|
||||
|
||||
function GettingStarted() {
|
||||
const navigate = useNavigate();
|
||||
|
||||
const handleStartInventory = () => {
|
||||
navigate('/interest-inventory'); // Navigate to InterestInventory when the user clicks "Start Inventory"
|
||||
navigate('/interest-inventory');
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="getting-started-container">
|
||||
<h1>Welcome to AptivaAI</h1>
|
||||
<p>Let’s start by getting to know you better. Completing the steps below will help us tailor career recommendations based on your interests.</p>
|
||||
|
||||
<div className="steps">
|
||||
|
||||
<div className="step">
|
||||
<span className="step-icon">📄</span>
|
||||
<div className="mx-auto max-w-4xl px-4 py-8">
|
||||
{/* Page Title */}
|
||||
<h1 className="mb-2 text-center text-3xl font-semibold">
|
||||
Welcome to AptivaAI
|
||||
</h1>
|
||||
<p className="mx-auto mb-8 max-w-xl text-center text-gray-700">
|
||||
Let’s start by getting to know you better. Completing the steps below
|
||||
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>
|
||||
<h2>Step 1: Set Up Your Profile</h2>
|
||||
<p>Add details like your skills, education, and experience to further personalize your recommendations.</p>
|
||||
<button className="button-link" onClick={() => navigate('/profile')}>Go to Profile</button>
|
||||
<h2 className="text-lg font-medium">
|
||||
Step 1: Set Up Your Profile
|
||||
</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 className="step">
|
||||
<span className="step-icon">🎯</span>
|
||||
{/* Step 2 */}
|
||||
<div className="flex items-center space-x-4 rounded-lg bg-blue-50 p-6 shadow-sm">
|
||||
<span className="text-3xl">🎯</span>
|
||||
<div>
|
||||
<h2>Step 2: Complete the O*Net Interest Inventory</h2>
|
||||
<p>Discover your career interests by taking the O*Net inventory. This will help us suggest personalized career paths for you.</p>
|
||||
{/* Start Inventory button */}
|
||||
<button className="button-link" onClick={handleStartInventory}>Start Inventory</button>
|
||||
<h2 className="text-lg font-medium">
|
||||
Step 2: Complete the O*Net Interest Inventory
|
||||
</h2>
|
||||
<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 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>
|
||||
);
|
||||
}
|
||||
|
@ -1,7 +1,5 @@
|
||||
// components/SignUp.js
|
||||
import React, { useState } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import './SignUp.css';
|
||||
|
||||
function SignUp() {
|
||||
const navigate = useNavigate();
|
||||
@ -19,14 +17,11 @@ function SignUp() {
|
||||
}
|
||||
|
||||
try {
|
||||
// Call the /api/register endpoint
|
||||
const response = await fetch('/api/register', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
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,
|
||||
password,
|
||||
}),
|
||||
@ -48,27 +43,47 @@ function SignUp() {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="signup-container">
|
||||
<div className="signup-form">
|
||||
<h1>Sign Up</h1>
|
||||
{error && <p className="error-message">{error}</p>}
|
||||
{success && <p className="success-message">Registration successful!</p>}
|
||||
<form onSubmit={handleSignUp}>
|
||||
<div className="flex min-h-screen flex-col items-center justify-center bg-gray-100 p-4">
|
||||
<div className="w-full max-w-sm rounded-md bg-white p-6 shadow-md">
|
||||
<h1 className="mb-6 text-center text-2xl font-semibold">Sign Up</h1>
|
||||
|
||||
{error && (
|
||||
<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
|
||||
type="text"
|
||||
placeholder="Username"
|
||||
value={username}
|
||||
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
|
||||
type="password"
|
||||
placeholder="Password"
|
||||
value={password}
|
||||
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
|
||||
</button>
|
||||
</form>
|
||||
|
@ -1,6 +1,5 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import './UserProfile.css';
|
||||
|
||||
function UserProfile() {
|
||||
const [firstName, setFirstName] = useState('');
|
||||
@ -11,10 +10,10 @@ function UserProfile() {
|
||||
const [areas, setAreas] = useState([]);
|
||||
const [selectedArea, setSelectedArea] = useState('');
|
||||
const [careerSituation, setCareerSituation] = useState('');
|
||||
const navigate = useNavigate();
|
||||
const [loadingAreas, setLoadingAreas] = useState(false);
|
||||
const [isPremiumUser, setIsPremiumUser] = useState(false);
|
||||
|
||||
const navigate = useNavigate();
|
||||
|
||||
const authFetch = async (url, options = {}) => {
|
||||
const token = localStorage.getItem('token');
|
||||
@ -41,7 +40,6 @@ function UserProfile() {
|
||||
return res;
|
||||
};
|
||||
|
||||
// Single useEffect for both profile and areas
|
||||
useEffect(() => {
|
||||
const fetchProfileAndAreas = async () => {
|
||||
try {
|
||||
@ -56,7 +54,7 @@ function UserProfile() {
|
||||
},
|
||||
});
|
||||
|
||||
if (!res.ok) return;
|
||||
if (!res || !res.ok) return;
|
||||
|
||||
const data = await res.json();
|
||||
|
||||
@ -76,7 +74,9 @@ function UserProfile() {
|
||||
setLoadingAreas(true);
|
||||
try {
|
||||
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();
|
||||
setAreas(areaData.areas);
|
||||
} catch (areaErr) {
|
||||
@ -116,7 +116,7 @@ function UserProfile() {
|
||||
body: JSON.stringify(profileData),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
if (!response || !response.ok) {
|
||||
throw new Error('Failed to save profile');
|
||||
}
|
||||
console.log('Profile saved successfully');
|
||||
@ -126,84 +126,161 @@ function UserProfile() {
|
||||
};
|
||||
|
||||
const states = [
|
||||
{ name: "Alabama", code: "AL" }, { name: "Alaska", code: "AK" }, { name: "Arizona", code: "AZ" },
|
||||
{ name: "Arkansas", code: "AR" }, { name: "California", code: "CA" }, { name: "Colorado", code: "CO" },
|
||||
{ name: "Connecticut", code: "CT" }, { name: "Delaware", code: "DE" }, { name: "Florida", code: "FL" },
|
||||
{ name: "Georgia", code: "GA" }, { name: "Hawaii", code: "HI" }, { name: "Idaho", code: "ID" },
|
||||
{ name: "Illinois", code: "IL" }, { name: "Indiana", code: "IN" }, { name: "Iowa", code: "IA" },
|
||||
{ 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" }
|
||||
{ name: 'Alabama', code: 'AL' },
|
||||
{ name: 'Alaska', code: 'AK' },
|
||||
{ name: 'Arizona', code: 'AZ' },
|
||||
// ... (truncated for brevity, include all states)
|
||||
{ name: 'Wyoming', code: 'WY' }
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="user-profile-container">
|
||||
<h2>User Profile</h2>
|
||||
<form onSubmit={handleFormSubmit}>
|
||||
<div className="form-group">
|
||||
<label>First Name:</label>
|
||||
<input type="text" value={firstName} onChange={(e) => setFirstName(e.target.value)} required />
|
||||
</div>
|
||||
<div className="form-group">
|
||||
<label>Last Name:</label>
|
||||
<input type="text" value={lastName} onChange={(e) => setLastName(e.target.value)} required />
|
||||
</div>
|
||||
<div className="form-group">
|
||||
<label>Email:</label>
|
||||
<input type="email" value={email} onChange={(e) => setEmail(e.target.value)} required />
|
||||
</div>
|
||||
<div className="form-group">
|
||||
<label>ZIP Code:</label>
|
||||
<input type="text" value={zipCode} onChange={(e) => setZipCode(e.target.value)} required />
|
||||
</div>
|
||||
<div className="form-group">
|
||||
<label>State:</label>
|
||||
<select value={selectedState} onChange={(e) => setSelectedState(e.target.value)} required>
|
||||
<option value="">Select a State</option>
|
||||
{states.map((s) => (
|
||||
<option key={s.code} value={s.code}>{s.name}</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
{loadingAreas ? (
|
||||
<p>Loading areas...</p>
|
||||
) : areas.length > 0 && (
|
||||
<div className="form-group">
|
||||
<label>Area:</label>
|
||||
<select value={selectedArea} onChange={(e) => setSelectedArea(e.target.value)} required>
|
||||
<option value="">Select an Area</option>
|
||||
{areas.map((area, index) => (
|
||||
<option key={index} value={area}>{area}</option>
|
||||
<div className="flex min-h-screen items-center justify-center bg-gray-50 p-4">
|
||||
<div className="w-full max-w-lg rounded-lg bg-white p-6 shadow-md">
|
||||
<h2 className="mb-4 text-center text-2xl font-semibold">User Profile</h2>
|
||||
|
||||
<form onSubmit={handleFormSubmit} className="space-y-4">
|
||||
{/* First Name */}
|
||||
<div>
|
||||
<label className="mb-1 block text-sm font-medium text-gray-700">
|
||||
First Name:
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
value={firstName}
|
||||
onChange={(e) => setFirstName(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>
|
||||
|
||||
{/* Last Name */}
|
||||
<div>
|
||||
<label className="mb-1 block text-sm font-medium text-gray-700">
|
||||
Last Name:
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
value={lastName}
|
||||
onChange={(e) => setLastName(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>
|
||||
|
||||
{/* Email */}
|
||||
<div>
|
||||
<label className="mb-1 block text-sm font-medium text-gray-700">
|
||||
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>
|
||||
</div>
|
||||
)}
|
||||
{isPremiumUser && (
|
||||
<div className="form-group">
|
||||
<label>What best describes your current career situation?</label>
|
||||
<select value={careerSituation} onChange={(e) => setCareerSituation(e.target.value)}>
|
||||
<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>
|
||||
|
||||
{/* Areas Dropdown */}
|
||||
{loadingAreas ? (
|
||||
<p className="text-sm text-gray-500">Loading areas...</p>
|
||||
) : (
|
||||
areas.length > 0 && (
|
||||
<div>
|
||||
<label className="mb-1 block text-sm font-medium text-gray-700">
|
||||
Area:
|
||||
</label>
|
||||
<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>
|
||||
)}
|
||||
<button type="submit">Save Profile</button>
|
||||
</form>
|
||||
<button onClick={() => navigate('/getting-started')}>Go Back</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default UserProfile;
|
||||
export default UserProfile;
|
||||
|
BIN
user_profile.db
BIN
user_profile.db
Binary file not shown.
Loading…
Reference in New Issue
Block a user