Added RIASEC to user_profile
This commit is contained in:
parent
87effa1a86
commit
112d6eec56
@ -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)
|
||||||
------------------------------------------------------------------ */
|
------------------------------------------------------------------ */
|
||||||
|
@ -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;
|
||||||
|
@ -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.');
|
||||||
|
Loading…
Reference in New Issue
Block a user