Added RIASEC to user_profile

This commit is contained in:
Josh 2025-06-09 14:17:53 +00:00
parent 87effa1a86
commit 112d6eec56
3 changed files with 118 additions and 18 deletions

View File

@ -337,7 +337,7 @@ app.get('/api/check-username/:username', (req, res) => {
/** /**
* POST /api/user-profile * POST /api/user-profile
* Headers: { Authorization: Bearer <token> } * Headers: { Authorization: Bearer <token> }
* Body: { firstName, lastName, email, zipCode, state, area, ... } * Body: { userName, firstName, lastName, email, zipCode, state, area, ... }
* *
* If user_profile row exists (id = token.id), update * If user_profile row exists (id = token.id), update
* else insert * else insert
@ -358,6 +358,7 @@ app.post('/api/user-profile', (req, res) => {
} }
const { const {
userName,
firstName, firstName,
lastName, lastName,
email, email,
@ -366,13 +367,14 @@ app.post('/api/user-profile', (req, res) => {
area, area,
careerSituation, careerSituation,
interest_inventory_answers, interest_inventory_answers,
riasec_scores, // new JSON with { R:15, I:22, A:..., S:..., E:..., C:... }
career_priorities, career_priorities,
career_list, career_list,
} = req.body; } = req.body;
// Check if profile row exists // Check if profile row exists
pool.query( pool.query(
`SELECT * FROM user_profile WHERE id = ?`, 'SELECT * FROM user_profile WHERE id = ?',
[profileId], [profileId],
(err, results) => { (err, results) => {
if (err) { if (err) {
@ -391,31 +393,66 @@ app.post('/api/user-profile', (req, res) => {
.json({ error: 'All fields are required for initial profile creation.' }); .json({ error: 'All fields are required for initial profile creation.' });
} }
// Final handling of interest inventory answers
const finalAnswers = const finalAnswers =
interest_inventory_answers !== undefined interest_inventory_answers !== undefined
? interest_inventory_answers ? interest_inventory_answers
: existingRow?.interest_inventory_answers || null; : existingRow?.interest_inventory_answers || null;
// final career priorities
const finalCareerPriorities = const finalCareerPriorities =
career_priorities !== undefined career_priorities !== undefined
? career_priorities ? career_priorities
: existingRow?.career_priorities || null; : existingRow?.career_priorities || null;
// final career list
const finalCareerList = const finalCareerList =
career_list !== undefined career_list !== undefined
? career_list ? career_list
: existingRow?.career_list || null; : existingRow?.career_list || null;
// final userName
const finalUserName =
userName !== undefined
? userName
: existingRow?.username || null;
// final RIASEC JSON
// If you passed something in "riasec_scores", store as JSON
// If none passed, keep existing or null
let finalRiasecScores;
if (riasec_scores !== undefined) {
if (riasec_scores) {
finalRiasecScores = JSON.stringify(riasec_scores);
} else {
// if it's empty or falsey, set to null or keep existing
finalRiasecScores = null;
}
} else {
finalRiasecScores = existingRow?.riasec_scores || null;
}
if (existingRow) { if (existingRow) {
// Update the existing user_profile // Update existing row
const updateQuery = ` const updateQuery = `
UPDATE user_profile UPDATE user_profile
SET firstname = ?, lastname = ?, email = ?, zipcode = ?, state = ?, area = ?, SET
career_situation = ?, interest_inventory_answers = ?, career_priorities = ?, username = ?,
career_list = ? firstname = ?,
lastname = ?,
email = ?,
zipcode = ?,
state = ?,
area = ?,
career_situation = ?,
interest_inventory_answers = ?,
riasec_scores = ?, -- new field
career_priorities = ?,
career_list = ?
WHERE id = ? WHERE id = ?
`; `;
const params = [ const params = [
finalUserName,
firstName || existingRow.firstname, firstName || existingRow.firstname,
lastName || existingRow.lastname, lastName || existingRow.lastname,
email || existingRow.email, email || existingRow.email,
@ -424,9 +461,10 @@ app.post('/api/user-profile', (req, res) => {
area || existingRow.area, area || existingRow.area,
careerSituation || existingRow.career_situation, careerSituation || existingRow.career_situation,
finalAnswers, finalAnswers,
finalRiasecScores, // JSON string
finalCareerPriorities, finalCareerPriorities,
finalCareerList, finalCareerList,
profileId, profileId
]; ];
pool.query(updateQuery, params, (err2) => { pool.query(updateQuery, params, (err2) => {
@ -436,20 +474,20 @@ app.post('/api/user-profile', (req, res) => {
.status(500) .status(500)
.json({ error: 'Failed to update user profile' }); .json({ error: 'Failed to update user profile' });
} }
return res return res.status(200).json({ message: 'User profile updated successfully' });
.status(200)
.json({ message: 'User profile updated successfully' });
}); });
} else { } else {
// Insert a new profile (the user_auth record exists, but the user_profile row is missing) // Insert a new profile
const insertQuery = ` const insertQuery = `
INSERT INTO user_profile INSERT INTO user_profile
(id, firstname, lastname, email, zipcode, state, area, career_situation, (id, username, firstname, lastname, email, zipcode, state, area,
interest_inventory_answers, career_priorities, career_list) career_situation, interest_inventory_answers, riasec_scores,
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) career_priorities, career_list)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
`; `;
const params = [ const params = [
profileId, // Force the row's primary key to match the existing user ID profileId,
finalUserName,
firstName, firstName,
lastName, lastName,
email, email,
@ -458,6 +496,7 @@ app.post('/api/user-profile', (req, res) => {
area, area,
careerSituation || null, careerSituation || null,
finalAnswers, finalAnswers,
finalRiasecScores, // JSON string or null
finalCareerPriorities, finalCareerPriorities,
finalCareerList, finalCareerList,
]; ];
@ -469,15 +508,17 @@ app.post('/api/user-profile', (req, res) => {
.status(500) .status(500)
.json({ error: 'Failed to create user profile' }); .json({ error: 'Failed to create user profile' });
} }
return res return res.status(201).json({
.status(201) message: 'User profile created successfully',
.json({ message: 'User profile created successfully', id: profileId }); id: profileId
});
}); });
} }
} }
); );
}); });
/* ------------------------------------------------------------------ /* ------------------------------------------------------------------
FETCH USER PROFILE (MySQL) FETCH USER PROFILE (MySQL)
------------------------------------------------------------------ */ ------------------------------------------------------------------ */

View File

@ -349,6 +349,24 @@ app.post('/api/onet/submit_answers', async (req, res) => {
// filter out lower ed // filter out lower ed
const filtered = filterHigherEducationCareers(careerSuggestions); const filtered = filterHigherEducationCareers(careerSuggestions);
const riasecCode = convertToRiasecCode(riaSecScores);
const token = req.headers.authorization?.split(' ')[1];
if (token) {
try {
await axios.post(`${process.env.MAIN_API_URL}/api/user-profile`,
{
interest_inventory_answers: answers,
riasec: riasecCode
},
{ headers: { Authorization: `Bearer ${token}` } }
);
} catch (err) {
console.error('Error storing RIASEC in user_profile =>', err.response?.data || err.message);
// fallback if needed
}
}
res.status(200).json({ res.status(200).json({
careers: filtered, careers: filtered,
riaSecScores, riaSecScores,
@ -379,6 +397,25 @@ function filterHigherEducationCareers(careers) {
.filter(Boolean); .filter(Boolean);
} }
function convertToRiasecCode(riaSecScores) {
// We assume each item has { area, score, description }
// Sort them by area in R, I, A, S, E, C order or by highest score, whichever you prefer:
// Sort by standard R -> I -> A -> S -> E -> C ordering:
const order = { Realistic: 0, Investigative: 1, Artistic: 2, Social: 3, Enterprising: 4, Conventional: 5 };
// or you can sort by descending score:
// const sorted = [...riaSecScores].sort((a, b) => b.score - a.score);
// For this example, let's do the standard R -> I -> A -> S -> E -> C
const sorted = [...riaSecScores].sort((a, b) => order[a.area] - order[b.area]);
// Now build the 6-letter code
// e.g. "RI" + "A" + ...
// If you want to show tie-breaking or real logic, you can do so
return sorted.map(item => item.area[0].toUpperCase()).join('');
// e.g. "RIASEC"
}
// ONet career details // ONet career details
app.get('/api/onet/career-details/:socCode', async (req, res) => { app.get('/api/onet/career-details/:socCode', async (req, res) => {
const { socCode } = req.params; const { socCode } = req.params;

View File

@ -3,6 +3,18 @@ import { useNavigate } from 'react-router-dom';
import { ClipLoader } from 'react-spinners'; import { ClipLoader } from 'react-spinners';
import authFetch from '../utils/authFetch.js'; import authFetch from '../utils/authFetch.js';
function mapScores(riaSecScores) {
const map = {};
// e.g. area = "Realistic" => letter "R"
riaSecScores.forEach(obj => {
const letter = obj.area[0].toUpperCase(); // 'R', 'I', 'A', 'S', 'E', 'C'
map[letter] = obj.score;
});
return map; // e.g. { R:15, I:22, A:20, S:30, E:25, C:24 }
}
const InterestInventory = () => { const InterestInventory = () => {
const [questions, setQuestions] = useState([]); const [questions, setQuestions] = useState([]);
const [responses, setResponses] = useState({}); const [responses, setResponses] = useState({});
@ -156,6 +168,16 @@ const InterestInventory = () => {
const { careers: careerSuggestions, riaSecScores } = data; const { careers: careerSuggestions, riaSecScores } = data;
if (Array.isArray(careerSuggestions) && Array.isArray(riaSecScores)) { if (Array.isArray(careerSuggestions) && Array.isArray(riaSecScores)) {
// 4) Convert those scores to a short code
const scoresMap = mapScores(riaSecScores); // { R:15, I:22, ... }
await authFetch('/api/user-profile', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
riasec_scores: scoresMap // store in DB as a JSON string
}),
});
navigate('/career-explorer', { state: { careerSuggestions, riaSecScores, fromInterestInventory: true } }); navigate('/career-explorer', { state: { careerSuggestions, riaSecScores, fromInterestInventory: true } });
} else { } else {
throw new Error('Invalid data format from the server.'); throw new Error('Invalid data format from the server.');