Added PremiumOnboarding components and backend endpoints. Tested, working

This commit is contained in:
Josh 2025-04-07 15:12:09 +00:00
parent 12fba3e3f0
commit c9cdceb4b0
8 changed files with 264 additions and 48 deletions

View File

@ -11,10 +11,6 @@ import path from 'path';
import { fileURLToPath } from 'url';
import { simulateFinancialProjection } from '../src/utils/FinancialProjectionService.js';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
@ -132,6 +128,8 @@ app.post('/api/premium/planned-path', authenticatePremiumUser, async (req, res)
}
});
// Milestones premium services
// Save a new milestone
app.post('/api/premium/milestone', authenticatePremiumUser, async (req, res) => {
const rawMilestones = Array.isArray(req.body.milestones) ? req.body.milestones : [req.body];
@ -220,8 +218,6 @@ app.post('/api/premium/milestone', authenticatePremiumUser, async (req, res) =>
}
});
// Get all milestones
app.get('/api/premium/milestones', authenticatePremiumUser, async (req, res) => {
try {
@ -243,8 +239,7 @@ app.get('/api/premium/milestones', authenticatePremiumUser, async (req, res) =>
}
});
/// Update an existing milestone
// Update an existing milestone
app.put('/api/premium/milestones/:id', authenticatePremiumUser, async (req, res) => {
try {
const { id } = req.params;
@ -335,36 +330,8 @@ app.delete('/api/premium/milestones/:id', authenticatePremiumUser, async (req, r
}
});
// Archive current career to history
app.post('/api/premium/career-history', authenticatePremiumUser, async (req, res) => {
const { career_path_id, company } = req.body;
if (!career_path_id || !company) {
return res.status(400).json({ error: 'Career path ID and company are required' });
}
try {
const career = await db.get(`SELECT * FROM career_path WHERE id = ? AND user_id = ?`, [career_path_id, req.userId]);
if (!career) {
return res.status(404).json({ error: 'Career path not found' });
}
await db.run(
`INSERT INTO career_history (user_id, job_title, company, start_date)
VALUES (?, ?, ?, DATE('now'))`,
[req.userId, career.job_title, company]
);
await db.run(`DELETE FROM career_path WHERE id = ?`, [career_path_id]);
res.status(201).json({ message: 'Career moved to history successfully' });
} catch (error) {
console.error('Error moving career to history:', error);
res.status(500).json({ error: 'Failed to update career history' });
}
});
//Financial Profile premium services
//Get financial profile
app.get('/api/premium/financial-profile', authenticatePremiumUser, async (req, res) => {
try {
const row = await db.get(`SELECT * FROM financial_profile WHERE user_id = ?`, [req.userId]);
@ -377,6 +344,7 @@ app.get('/api/premium/financial-profile', authenticatePremiumUser, async (req, r
// Backend code (server3.js)
// Save or update financial profile
app.post('/api/premium/financial-profile', authenticatePremiumUser, async (req, res) => {
const {
currentSalary, additionalIncome, monthlyExpenses, monthlyDebtPayments,
@ -480,21 +448,122 @@ app.post('/api/premium/financial-profile', authenticatePremiumUser, async (req,
}
});
//PreimumOnboarding
//Career onboarding
app.post('/api/premium/onboarding/career', authenticatePremiumUser, async (req, res) => {
const { career_name, status, start_date, projected_end_date } = req.body;
// Retrieve career history
app.get('/api/premium/career-history', authenticatePremiumUser, async (req, res) => {
try {
const history = await db.all(
`SELECT * FROM career_history WHERE user_id = ? ORDER BY start_date DESC;`,
[req.userId]
const careerPathId = uuidv4();
await db.run(`
INSERT INTO career_path (id, user_id, career_name, status, start_date, projected_end_date)
VALUES (?, ?, ?, ?, ?, ?)`,
[careerPathId, req.userId, career_name, status || 'planned', start_date || new Date().toISOString(), projected_end_date || null]
);
res.json({ careerHistory: history });
res.status(201).json({ message: 'Career onboarding data saved.', careerPathId });
} catch (error) {
console.error('Error fetching career history:', error);
res.status(500).json({ error: 'Failed to fetch career history' });
console.error('Error saving career onboarding data:', error);
res.status(500).json({ error: 'Failed to save career onboarding data.' });
}
});
//Financial onboarding
app.post('/api/premium/onboarding/financial', authenticatePremiumUser, async (req, res) => {
const {
current_salary, additional_income, monthly_expenses, monthly_debt_payments,
retirement_savings, retirement_contribution, emergency_fund
} = req.body;
try {
await db.run(`
INSERT INTO financial_profile (
id, user_id, current_salary, additional_income, monthly_expenses,
monthly_debt_payments, retirement_savings, retirement_contribution, emergency_fund, updated_at
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP)`,
[
uuidv4(), req.userId, current_salary, additional_income, monthly_expenses,
monthly_debt_payments, retirement_savings, retirement_contribution, emergency_fund
]
);
res.status(201).json({ message: 'Financial onboarding data saved.' });
} catch (error) {
console.error('Error saving financial onboarding data:', error);
res.status(500).json({ error: 'Failed to save financial onboarding data.' });
}
});
//College onboarding
app.post('/api/premium/onboarding/college', authenticatePremiumUser, async (req, res) => {
const {
in_college, expected_graduation, selected_school, selected_program,
program_type, is_online, credit_hours_per_year, hours_completed
} = req.body;
try {
await db.run(`
INSERT INTO financial_profile (
id, user_id, in_college, expected_graduation, selected_school,
selected_program, program_type, is_online, credit_hours_per_year,
hours_completed, updated_at
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP)`,
[
uuidv4(), req.userId, in_college ? 1 : 0, expected_graduation, selected_school,
selected_program, program_type, is_online, credit_hours_per_year,
hours_completed
]
);
res.status(201).json({ message: 'College onboarding data saved.' });
} catch (error) {
console.error('Error saving college onboarding data:', error);
res.status(500).json({ error: 'Failed to save college onboarding data.' });
}
});
//Financial Projection Premium Services
// Save financial projection for a specific careerPathId
app.post('/api/premium/financial-projection/:careerPathId', authenticatePremiumUser, async (req, res) => {
const { careerPathId } = req.params;
const { projectionData } = req.body; // JSON containing detailed financial projections
try {
const projectionId = uuidv4();
await db.run(`
INSERT INTO financial_projections (id, user_id, career_path_id, projection_json)
VALUES (?, ?, ?, ?)`,
[projectionId, req.userId, careerPathId, JSON.stringify(projectionData)]
);
res.status(201).json({ message: 'Financial projection saved.', projectionId });
} catch (error) {
console.error('Error saving financial projection:', error);
res.status(500).json({ error: 'Failed to save financial projection.' });
}
});
// Get financial projection for a specific careerPathId
app.get('/api/premium/financial-projection/:careerPathId', authenticatePremiumUser, async (req, res) => {
const { careerPathId } = req.params;
try {
const projection = await db.get(`
SELECT projection_json FROM financial_projections
WHERE user_id = ? AND career_path_id = ?`,
[req.userId, careerPathId]
);
if (!projection) {
return res.status(404).json({ error: 'Projection not found.' });
}
res.status(200).json(JSON.parse(projection.projection_json));
} catch (error) {
console.error('Error fetching financial projection:', error);
res.status(500).json({ error: 'Failed to fetch financial projection.' });
}
});

View File

@ -11,6 +11,8 @@ import UserProfile from './components/UserProfile.js';
import FinancialProfileForm from './components/FinancialProfileForm.js';
import MilestoneTracker from "./components/MilestoneTracker.js";
import Paywall from "./components/Paywall.js";
import OnboardingContainer from './components/PremiumOnboarding/OnboardingContainer.js';
import './App.css';
function App() {
@ -51,6 +53,8 @@ function App() {
<Route path="/profile" element={<UserProfile />} />
<Route path="/milestone-tracker" element={<MilestoneTracker />} />
<Route path="/financial-profile" element={<FinancialProfileForm />} />
<Route path="/premium-onboarding" element={<OnboardingContainer />} />
</>
)}

View File

@ -0,0 +1,36 @@
// CareerOnboarding.js
import React, { useState } from 'react';
const CareerOnboarding = ({ nextStep, prevStep }) => {
const [careerData, setCareerData] = useState({
currentJob: '',
industry: '',
employmentStatus: '',
careerGoal: '',
});
const handleChange = (e) => {
setCareerData({ ...careerData, [e.target.name]: e.target.value });
};
return (
<div>
<h2>Career Details</h2>
<input name="currentJob" placeholder="Current Job Title" onChange={handleChange} />
<input name="industry" placeholder="Industry" onChange={handleChange} />
<select name="employmentStatus" onChange={handleChange}>
<option value="">Employment Status</option>
<option value="FT">Full-Time</option>
<option value="PT">Part-Time</option>
<option value="Unemployed">Unemployed</option>
<option value="Student">Student</option>
</select>
<input name="careerGoal" placeholder="Career Goal (optional)" onChange={handleChange} />
<button onClick={prevStep}>Back</button>
<button onClick={nextStep}>Next: Financial </button>
</div>
);
};
export default CareerOnboarding;

View File

@ -0,0 +1,35 @@
// CollegeOnboarding.js
import React, { useState } from 'react';
const CollegeOnboarding = ({ nextStep, prevStep }) => {
const [collegeData, setCollegeData] = useState({
studentStatus: '',
school: '',
program: '',
creditHoursPerYear: '',
});
const handleChange = (e) => {
setCollegeData({ ...collegeData, [e.target.name]: e.target.value });
};
return (
<div>
<h2>College Plans (optional)</h2>
<select name="studentStatus" onChange={handleChange}>
<option value="">Student Status</option>
<option value="Enrolled">Currently Enrolled</option>
<option value="Prospective">Prospective Student</option>
<option value="None">Not Applicable</option>
</select>
<input name="school" placeholder="School Name" onChange={handleChange} />
<input name="program" placeholder="Program Name" onChange={handleChange} />
<input name="creditHoursPerYear" placeholder="Credit Hours per Year" type="number" onChange={handleChange} />
<button onClick={prevStep}> Previous: Financial</button>
<button onClick={nextStep}>Finish Onboarding</button>
</div>
);
};
export default CollegeOnboarding;

View File

@ -0,0 +1,30 @@
// FinancialOnboarding.js
import React, { useState } from 'react';
const FinancialOnboarding = ({ nextStep, prevStep }) => {
const [financialData, setFinancialData] = useState({
salary: '',
expenses: '',
savings: '',
debts: '',
});
const handleChange = (e) => {
setFinancialData({ ...financialData, [e.target.name]: e.target.value });
};
return (
<div>
<h2>Financial Details</h2>
<input name="salary" placeholder="Annual Salary" type="number" onChange={handleChange} />
<input name="expenses" placeholder="Monthly Expenses" type="number" onChange={handleChange} />
<input name="savings" placeholder="Total Savings" type="number" onChange={handleChange} />
<input name="debts" placeholder="Outstanding Debts" type="number" onChange={handleChange} />
<button onClick={prevStep}> Previous: Career</button>
<button onClick={nextStep}>Next: College </button>
</div>
);
};
export default FinancialOnboarding;

View File

@ -0,0 +1,28 @@
// OnboardingContainer.js
import React, { useState } from 'react';
import PremiumWelcome from './PremiumWelcome.js';
import CareerOnboarding from './CareerOnboarding.js';
import FinancialOnboarding from './FinancialOnboarding.js';
import CollegeOnboarding from './CollegeOnboarding.js';
const OnboardingContainer = () => {
const [step, setStep] = useState(0);
const nextStep = () => setStep(step + 1);
const prevStep = () => setStep(step - 1);
const onboardingSteps = [
<PremiumWelcome nextStep={nextStep} />,
<CareerOnboarding nextStep={nextStep} prevStep={prevStep} />,
<FinancialOnboarding nextStep={nextStep} prevStep={prevStep} />,
<CollegeOnboarding nextStep={nextStep} prevStep={prevStep} />,
];
return (
<div className="onboarding-container">
{onboardingSteps[step]}
</div>
);
};
export default OnboardingContainer;

View File

@ -0,0 +1,14 @@
// PremiumWelcome.js
import React from 'react';
const PremiumWelcome = ({ nextStep }) => (
<div>
<h2>Welcome to AptivaAI Premium!</h2>
<p>
Let's get started by gathering some quick information to personalize your experience.
</p>
<button onClick={nextStep}>Get Started</button>
</div>
);
export default PremiumWelcome;

Binary file not shown.