diff --git a/backend/server3.js b/backend/server3.js index a62a27d..29da2e6 100644 --- a/backend/server3.js +++ b/backend/server3.js @@ -193,8 +193,7 @@ app.get('/api/premium/career-profile/latest', authenticatePremiumUser, async (re const sql = ` SELECT *, - DATE_FORMAT(start_date, '%Y-%m-%d') AS start_date, - DATE_FORMAT(projected_end_date, '%Y-%m-%d') AS projected_end_date + DATE_FORMAT(start_date, '%Y-%m-%d') AS start_date FROM career_profiles WHERE user_id = ? ORDER BY start_date DESC @@ -214,8 +213,7 @@ app.get('/api/premium/career-profile/all', authenticatePremiumUser, async (req, const sql = ` SELECT *, - DATE_FORMAT(start_date, '%Y-%m-%d') AS start_date, - DATE_FORMAT(projected_end_date, '%Y-%m-%d') AS projected_end_date + DATE_FORMAT(start_date, '%Y-%m-%d') AS start_date FROM career_profiles WHERE user_id = ? ORDER BY start_date ASC @@ -235,8 +233,7 @@ app.get('/api/premium/career-profile/:careerProfileId', authenticatePremiumUser, const sql = ` SELECT *, - DATE_FORMAT(start_date, '%Y-%m-%d') AS start_date, - DATE_FORMAT(projected_end_date, '%Y-%m-%d') AS projected_end_date + DATE_FORMAT(start_date, '%Y-%m-%d') AS start_date FROM career_profiles WHERE id = ? AND user_id = ? @@ -262,7 +259,6 @@ app.post('/api/premium/career-profile', authenticatePremiumUser, async (req, res career_name, status, start_date, - projected_end_date, college_enrollment_status, currently_working, career_goals, @@ -295,7 +291,6 @@ app.post('/api/premium/career-profile', authenticatePremiumUser, async (req, res career_name, status, start_date, - projected_end_date, college_enrollment_status, currently_working, career_goals, @@ -309,11 +304,10 @@ app.post('/api/premium/career-profile', authenticatePremiumUser, async (req, res planned_surplus_retirement_pct, planned_additional_income ) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE status = VALUES(status), start_date = VALUES(start_date), - projected_end_date = VALUES(projected_end_date), college_enrollment_status = VALUES(college_enrollment_status), currently_working = VALUES(currently_working), career_goals = VALUES(career_goals), @@ -336,7 +330,6 @@ app.post('/api/premium/career-profile', authenticatePremiumUser, async (req, res career_name, status || 'planned', start_date || null, - projected_end_date || null, college_enrollment_status || null, currently_working || null, career_goals || null, @@ -2453,29 +2446,32 @@ app.delete('/api/premium/milestones/:milestoneId', authenticatePremiumUser, asyn ------------------------------------------------------------------ */ // GET /api/premium/financial-profile -app.get('/api/premium/financial-profile', auth, (req, res) => { - const uid = req.userId; - db.query('SELECT * FROM financial_profile WHERE user_id=?', [uid], - (err, rows) => { - if (err) return res.status(500).json({ error:'DB error' }); +app.get('/api/premium/financial-profile', authenticatePremiumUser, async (req, res) => { + try { + const [rows] = await pool.query( + 'SELECT * FROM financial_profiles WHERE user_id=? LIMIT 1', + [req.id] + ); - if (!rows.length) { - // ←———— send a benign default instead of 404 - return res.json({ - current_salary: 0, - additional_income: 0, - monthly_expenses: 0, - monthly_debt_payments: 0, - retirement_savings: 0, - emergency_fund: 0, - retirement_contribution: 0, - emergency_contribution: 0, - extra_cash_emergency_pct: 50, - extra_cash_retirement_pct: 50 - }); - } - res.json(rows[0]); - }); + if (!rows.length) { + return res.json({ + current_salary: 0, + additional_income: 0, + monthly_expenses: 0, + monthly_debt_payments: 0, + retirement_savings: 0, + emergency_fund: 0, + retirement_contribution: 0, + emergency_contribution: 0, + extra_cash_emergency_pct: 50, + extra_cash_retirement_pct: 50 + }); + } + res.json(rows[0]); + } catch (err) { + console.error('financial‑profile GET error:', err); + res.status(500).json({ error: 'DB error' }); + } }); app.post('/api/premium/financial-profile', authenticatePremiumUser, async (req, res) => { @@ -2725,6 +2721,21 @@ app.get('/api/premium/college-profile', authenticatePremiumUser, async (req, res } }); +// GET every college profile for the logged‑in user +app.get('/api/premium/college-profile/all', authenticatePremiumUser, async (req,res)=>{ + const sql = ` + SELECT cp.*, + DATE_FORMAT(cp.created_at,'%Y-%m-%d') AS created_at, + IFNULL(cpr.scenario_title, cpr.career_name) AS career_title + FROM college_profiles cp + JOIN career_profiles cpr ON cpr.id = cp.career_profile_id + WHERE cp.user_id = ? + ORDER BY cp.created_at DESC + `; + const [rows] = await pool.query(sql,[req.id]); + res.json({ collegeProfiles: rows }); +}); + /* ------------------------------------------------------------------ AI-SUGGESTED MILESTONES ------------------------------------------------------------------ */ diff --git a/src/App.js b/src/App.js index 84ddf58..6ee56d9 100644 --- a/src/App.js +++ b/src/App.js @@ -25,6 +25,10 @@ import InterestInventory from './components/InterestInventory.js'; import Dashboard from './components/Dashboard.js'; import UserProfile from './components/UserProfile.js'; import FinancialProfileForm from './components/FinancialProfileForm.js'; +import CareerProfileList from './components/CareerProfileList.js'; +import CareerProfileForm from './components/CareerProfileForm.js'; +import CollegeProfileList from './components/CollegeProfileList.js'; +import CollegeProfileForm from './components/CollegeProfileForm.js'; import CareerRoadmap from './components/CareerRoadmap.js'; import Paywall from './components/Paywall.js'; import OnboardingContainer from './components/PremiumOnboarding/OnboardingContainer.js'; @@ -239,7 +243,7 @@ const uiToolHandlers = useMemo(() => { {/* Header */}

- AptivaAI - Career Guidance Platform (beta) + AptivaAI - Career Guidance Platform

{isAuthenticated && ( @@ -360,7 +364,7 @@ const uiToolHandlers = useMemo(() => { )} onClick={() => navigate('/retirement')} > - Retirement Planning + Retirement Planning (beta) {!canAccessPremium && ( (Premium) @@ -406,20 +410,32 @@ const uiToolHandlers = useMemo(() => { {canAccessPremium ? ( /* Premium users go straight to the wizard */ - - Premium Onboarding + Career Profiles ) : ( - /* Free users are nudged to upgrade */ + + Career Profiles (Premium) + + )} + + {/* College Profiles (go straight to list) */} + {canAccessPremium ? ( - College Planning (Premium) + College Profiles + ) : ( + + College Profiles (Premium) + )} @@ -533,6 +549,11 @@ const uiToolHandlers = useMemo(() => { } /> + } /> + } /> + + } /> + } /> + setForm(prev => ({ ...prev, [e.target.name]: e.target.value })); + + const handleCareerSelected = obj => { + // obj = { title, soc_code, … } + setForm(prev => ({ + ...prev, + career_name : obj.title, + soc_code : obj.soc_code + })); + setCareerLocked(true); + }; + + const unlockCareer = () => { + // allow user to re‑pick + setCareerLocked(false); + setForm(prev => ({ ...prev, career_name: '', soc_code: '' })); + }; + + /* ---------- 3. load an existing row (edit mode) ---------- */ + useEffect(() => { + if (id === 'new') return; + (async () => { + const res = await authFetch(`/api/premium/career-profile/${id}`); + if (!res.ok) return; + const d = await res.json(); + setForm(prev => ({ + ...prev, + scenario_title : d.scenario_title ?? '', + career_name : d.career_name ?? '', + soc_code : d.soc_code ?? '', + status : d.status ?? 'current', + start_date : d.start_date ?? '', + retirement_start_date : d.retirement_start_date ?? '', + college_enrollment_status : d.college_enrollment_status ?? '', + career_goals : d.career_goals ?? '', + desired_retirement_income_monthly : + d.desired_retirement_income_monthly ?? '' + })); + })(); + }, [id]); + + /* ---------- 4. save ---------- */ + async function save() { + if (!form.soc_code) { + alert('Please pick a valid career from the list first.'); + return; + } + try { + const res = await authFetch('/api/premium/career-profile', { + method : 'POST', + headers : { 'Content-Type': 'application/json' }, + body : JSON.stringify({ + ...form, + id: id === 'new' ? undefined : id // upsert + }) + }); + if (!res.ok) throw new Error(await res.text()); + nav(-1); + } catch (err) { + console.error(err); + alert(err.message); + } + } + + /* ---------- 5. render ---------- */ + return ( +
+

+ {id === 'new' ? 'New' : 'Edit'} Career Profile +

+ + {/* Scenario title */} + + + {/* Career picker (locked vs editable) */} + + {careerLocked ? ( +
+ + +
+ ) : ( + + )} + + {/* Status */} + + + {/* Dates */} + + + + + {/* College status */} + + + {/* Career goals */} +