diff --git a/backend/server.js b/backend/server.js index e579444..35c0643 100755 --- a/backend/server.js +++ b/backend/server.js @@ -73,21 +73,32 @@ app.use((req, res, next) => { // Route for user registration app.post('/api/register', async (req, res) => { - const { userId, username, password } = req.body; + const { + userId, + username, + password, + firstname, + lastname, + email, + zipcode, + state, + area + } = req.body; - if (!userId || !username || !password) { + // Validate all required fields + if (!userId || !username || !password || !firstname || !lastname || !email || !zipcode || !state || !area) { return res.status(400).json({ error: 'All fields are required' }); } try { - const hashedPassword = await bcrypt.hash(password, 10); // Hash the password - - // Step 1: Insert into user_auth + const hashedPassword = await bcrypt.hash(password, 10); + + // Insert into user_auth const authQuery = ` - INSERT INTO user_auth (username, hashed_password) - VALUES (?, ?) + INSERT INTO user_auth (user_id, username, hashed_password) + VALUES (?, ?, ?) `; - db.run(authQuery, [username, hashedPassword], function (err) { + db.run(authQuery, [userId, username, hashedPassword], function (err) { if (err) { console.error('Error inserting into user_auth:', err.message); if (err.message.includes('UNIQUE constraint failed')) { @@ -95,22 +106,19 @@ app.post('/api/register', async (req, res) => { } return res.status(500).json({ error: 'Failed to register user' }); } - - const user_id = this.lastID; // Retrieve the auto-generated id from user_auth - - // Step 2: Insert into user_profile + + // Insert into user_profile with actual provided values const profileQuery = ` - INSERT INTO user_profile (id, user_id, firstname, lastname, email, zipcode, state, area) - VALUES (?, ?, NULL, NULL, NULL, NULL, NULL, NULL) + INSERT INTO user_profile (user_id, firstname, lastname, email, zipcode, state, area) + VALUES (?, ?, ?, ?, ?, ?, ?) `; - db.run(profileQuery, [user_id, user_id], (err) => { + db.run(profileQuery, [userId, firstname, lastname, email, zipcode, state, area], (err) => { if (err) { console.error('Error inserting into user_profile:', err.message); return res.status(500).json({ error: 'Failed to create user profile' }); } - - // Return success response after both inserts - res.status(201).json({ message: 'User registered successfully', user_id }); + + res.status(201).json({ message: 'User registered successfully', userId }); }); }); } catch (error) { @@ -119,6 +127,7 @@ app.post('/api/register', async (req, res) => { } }); + // Route to save or update user profile app.post('/api/user-profile', (req, res) => { const token = req.headers.authorization?.split(' ')[1]; diff --git a/backend/server3.js b/backend/server3.js index b664559..2c3dc49 100644 --- a/backend/server3.js +++ b/backend/server3.js @@ -66,6 +66,38 @@ const authenticatePremiumUser = (req, res, next) => { } }; +/* ------------------------------------------------------------------ +PREMIUM UPGRADE ENDPOINT +------------------------------------------------------------------ */ +app.post('/api/activate-premium', (req, res) => { + const token = req.headers.authorization?.split(' ')[1]; + if (!token) { + return res.status(401).json({ error: 'Authorization token is required' }); + } + + let userId; + try { + const decoded = jwt.verify(token, SECRET_KEY); + userId = decoded.userId; + } catch (error) { + return res.status(401).json({ error: 'Invalid or expired token' }); + } + + const query = ` + UPDATE user_profile + SET is_premium = 1, is_pro_premium = 1 + WHERE user_id = ? + `; + db.run(query, [userId], (err) => { + if (err) { + console.error('Error updating premium status:', err.message); + return res.status(500).json({ error: 'Failed to activate premium' }); + } + res.status(200).json({ message: 'Premium activated successfully' }); + }); +}); + + /* ------------------------------------------------------------------ CAREER PROFILE ENDPOINTS ------------------------------------------------------------------ */ diff --git a/src/App.js b/src/App.js index 93907df..2d8f92d 100644 --- a/src/App.js +++ b/src/App.js @@ -7,6 +7,7 @@ import { useLocation, Link, } from 'react-router-dom'; +import { Button } from './components/ui/button.js'; // Import all components import PremiumRoute from './components/PremiumRoute.js'; @@ -103,168 +104,114 @@ function App() {

AptivaAI - Career Guidance Platform (beta)

- - {/* Navigation Menu */} + {isAuthenticated && ( )} - - {/* "Upgrade to Premium" button if not premium/pro and on a free path */} - {showPremiumCTA && isAuthenticated && !canAccessPremium && ( + + {/* Grouped Logout and Upgrade buttons */} + {isAuthenticated && ( +
+ + {showPremiumCTA && !canAccessPremium && ( + + + )} +
)} - + {/* Main Content */}
{/* Default to /signin */} } /> - + {/* Public routes */} } /> - + {/* Paywall (public) */} } /> - + {/* Authenticated routes */} {isAuthenticated && ( <> @@ -284,7 +231,7 @@ function App() { } /> } /> } /> - + {/* Premium-only routes */} } /> - - {/* 4) The new Resume Optimizer route */} + + {/* Resume Optimizer route */} )} - + {/* 404 / Fallback */} } />
- + {/* Session Handler */} ); + } export default App; diff --git a/src/components/Chatbot.js b/src/components/Chatbot.js index a2cca1e..d050e65 100644 --- a/src/components/Chatbot.js +++ b/src/components/Chatbot.js @@ -7,7 +7,7 @@ const Chatbot = ({ context }) => { { role: "assistant", content: - "Hi! I’m here to help you with career suggestions, ROI analysis, and any questions you have about your career. How can I assist you today?", + "Hi! I’m here to help you with suggestions, analyzing career options, and any questions you have about your career. How can I assist you today?", }, ]); const [input, setInput] = useState(""); diff --git a/src/components/Paywall.js b/src/components/Paywall.js index 05bf806..8d8a0cc 100644 --- a/src/components/Paywall.js +++ b/src/components/Paywall.js @@ -1,19 +1,38 @@ import React from 'react'; import { useLocation, useNavigate } from 'react-router-dom'; +import { Button } from './ui/button.js'; const Paywall = () => { const navigate = useNavigate(); const { state } = useLocation(); - // Extract the selectedCareer from location state const { selectedCareer } = state || {}; - const handleSubscribe = () => { - // Once the user subscribes, navigate to MilestoneTracker - navigate('/PremiumOnboarding', { - state: { - selectedCareer, - }, - }); + const handleSubscribe = async () => { + const token = localStorage.getItem('token'); + if (!token) { + navigate('/signin'); + return; + } + + try { + const response = await fetch('/api/activate-premium', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${token}` + } + }); + + if (response.ok) { + navigate('/PremiumOnboarding', { state: { selectedCareer } }); + } else if (response.status === 401) { + navigate('/GettingStarted', { state: { selectedCareer } }); + } else { + console.error('Failed to activate premium:', await response.text()); + } + } catch (err) { + console.error('Error activating premium:', err); + } }; return ( @@ -25,8 +44,14 @@ const Paywall = () => {
  • ✅ Detailed College Guidance & Analysis
  • - - + + + ); }; diff --git a/src/components/PremiumOnboarding/CollegeOnboarding.js b/src/components/PremiumOnboarding/CollegeOnboarding.js index 9575068..51c6602 100644 --- a/src/components/PremiumOnboarding/CollegeOnboarding.js +++ b/src/components/PremiumOnboarding/CollegeOnboarding.js @@ -434,7 +434,7 @@ function CollegeOnboarding({ nextStep, prevStep, data, setData, careerPathId })
    - + -
    - - -
    diff --git a/src/components/SignUp.js b/src/components/SignUp.js index 10a3666..a630183 100644 --- a/src/components/SignUp.js +++ b/src/components/SignUp.js @@ -1,18 +1,82 @@ -import React, { useState } from 'react'; +import React, { useState, useEffect } from 'react'; import { useNavigate } from 'react-router-dom'; +import { Button } from './ui/button.js'; function SignUp() { const navigate = useNavigate(); + const [username, setUsername] = useState(''); const [password, setPassword] = useState(''); + const [firstname, setFirstname] = useState(''); + const [lastname, setLastname] = useState(''); + const [email, setEmail] = useState(''); + const [zipcode, setZipcode] = useState(''); + const [state, setState] = useState(''); + const [area, setArea] = useState(''); + const [areas, setAreas] = useState([]); const [error, setError] = useState(''); - const [success, setSuccess] = useState(false); - const handleSignUp = async (event) => { - event.preventDefault(); + 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: 'District of Columbia', code: 'DC' }, + { 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' }, + ]; - if (!username || !password) { - setError('Please enter a username and password'); + useEffect(() => { + const fetchAreas = async () => { + if (!state) { + setAreas([]); + return; + } + try { + const res = await fetch(`/api/areas?state=${state}`); + const data = await res.json(); + setAreas(data.areas || []); + } catch (err) { + console.error('Error fetching areas:', err); + setAreas([]); + } + }; + + fetchAreas(); + }, [state]); + + const handleSignUp = async (e) => { + e.preventDefault(); + setError(''); + + const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/; + const zipRegex = /^\d{5}$/; + const passwordRegex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[!@#$%^&*]).{8,}$/; + + if (!username || !password || !firstname || !lastname || !email || !zipcode || !state || !area) { + setError('All fields are required.'); + return; + } + if (!emailRegex.test(email)) { + setError('Enter a valid email address.'); + return; + } + if (!zipRegex.test(zipcode)) { + setError('ZIP code must be exactly 5 digits.'); + return; + } + if (!passwordRegex.test(password)) { + setError('Password must include at least 8 characters, one uppercase, one lowercase, one number, and one special character.'); return; } @@ -21,71 +85,57 @@ function SignUp() { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ - userId: Math.floor(Math.random() * 10000000), // Temporary ID logic - username, - password, + userId: Math.floor(Math.random() * 1000000000), + username, password, firstname, lastname, email, zipcode, state, area, }), }); - if (response.ok) { - setSuccess(true); - console.log('User registered successfully'); - // Redirect to GettingStarted after successful sign-up - navigate('/getting-started'); - } else { - const data = await response.json(); - setError(data.error || 'Failed to register user'); + const data = await response.json(); + + if (!response.ok) { + setError(data.error || 'Registration failed. Please try again.'); + return; } + + navigate('/getting-started'); } catch (err) { - console.error('Error during registration:', err.message); - setError('An error occurred while registering. Please try again.'); + console.error(err); + setError('An unexpected error occurred. Please try again later.'); } }; return ( -
    -
    -

    Sign Up

    +
    +
    +

    Sign Up

    {error && ( -

    +

    {error} -

    +
    )} - {/* - Success is briefly shown, but you navigate away immediately - after a successful response. You may keep or remove this. - */} - {success && ( -

    - Registration successful! -

    - )} +
    + setUsername(e.target.value)} /> + setPassword(e.target.value)} /> + setFirstname(e.target.value)} /> + setLastname(e.target.value)} /> + setEmail(e.target.value)} /> + setZipcode(e.target.value)} /> - - setUsername(e.target.value)} - className="w-full rounded border border-gray-300 p-2 focus:border-blue-500 focus:outline-none" - /> + - setPassword(e.target.value)} - className="w-full rounded border border-gray-300 p-2 focus:border-blue-500 focus:outline-none" - /> + - +
    diff --git a/user_profile.db b/user_profile.db index a694451..093ed49 100644 Binary files a/user_profile.db and b/user_profile.db differ